1 #ifndef TUT_FORK_H_GUARD
2 #define TUT_FORK_H_GUARD
3 #include <tut/tut_config.hpp>
5 #if defined(TUT_USE_POSIX)
11 #include <sys/types.h>
19 #include "tut_result.hpp"
20 #include "tut_assert.hpp"
21 #include "tut_runner.hpp"
26 template<typename, int>
32 class test_group_posix
35 template<typename, int>
36 friend class test_group;
39 void send_result_(const T *obj, const test_result &tr)
41 if(obj->get_pipe_() == -1)
46 if(tr.result != test_result::ok)
48 std::ostringstream ss;
49 ss << int(tr.result) << "\n"
53 << tr.exception_typeid << "\n";
54 std::copy( tr.message.begin(), tr.message.end(), std::ostreambuf_iterator<char>(ss.rdbuf()) );
56 int size = ss.str().length();
57 int w = write(obj->get_pipe_(), ss.str().c_str(), size);
58 ensure_errno("write() failed", w == size);
62 virtual ~test_group_posix()
72 test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
73 ensure("trying to call 'tut_fork' in ctor of test object", self != NULL);
78 pid_t waitpid(pid_t pid, int *status, int flags = 0)
80 test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
81 ensure("trying to call 'tut_waitpid' in ctor of test object", self != NULL);
83 return self->waitpid_(pid, status, flags);
86 void ensure_child_exit(pid_t pid, int exit_status = 0)
88 test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
89 ensure("trying to call 'ensure_child_exit' in ctor of test object", self != NULL);
92 self->waitpid_(pid, &status);
94 self->ensure_child_exit_(status, exit_status);
98 void ensure_child_signal(pid_t pid, int signal = SIGTERM)
100 test_object<T> *self = dynamic_cast< tut::test_object<T>* >(this);
101 ensure("trying to call 'ensure_child_signal' in ctor of test object", self != NULL);
104 self->waitpid_(pid, &status);
106 self->ensure_child_signal_(status, signal);
109 std::set<pid_t> get_pids() const
113 const test_object<T> *self = dynamic_cast< const tut::test_object<T>* >(this);
114 ensure("trying to call 'get_pids' in ctor of test object", self != NULL);
116 return self->get_pids_();
125 class test_object_posix
128 typedef std::map<pid_t, int> pid_map;
131 * Default constructor
140 virtual ~test_object_posix()
145 // in child, force exit
151 std::ostringstream ss;
153 // in parent, reap children
154 for(std::map<pid_t, int>::iterator i = pids_.begin(); i != pids_.end(); ++i)
157 kill_child_(i->first);
158 } catch(const rethrown &ex) {
159 ss << std::endl << "child " << ex.tr.pid << " has thrown an exception: " << ex.what();
160 } catch(const failure &ex) {
161 ss << std::endl << ex.what();
165 if(!ss.str().empty())
167 fail(ss.str().c_str());
174 friend class tut_posix;
176 friend class test_group_posix;
178 int get_pipe_() const
188 ensure_errno("pipe() failed", ::pipe(fds) == 0);
190 pid_t pid = ::fork();
192 ensure_errno("fork() failed", pid >= 0);
196 // in parent, register pid
197 ensure("duplicated child", pids_.insert( std::make_pair(pid, fds[0]) ).second);
199 // close writing side
204 // in child, shutdown reporter
205 tut::runner.get().clear_callbacks();
207 // close reading side
215 void kill_child_(pid_t pid)
219 if(waitpid_(pid, &status, WNOHANG) == pid)
221 ensure_child_exit_(status, 0);
225 if(::kill(pid, SIGTERM) != 0)
234 // cannot kill, we are in trouble
235 std::ostringstream ss;
237 ss << "child " << pid << " could not be killed with SIGTERM, " << strerror_r(errno, e, sizeof(e)) << std::endl;
242 if(waitpid_(pid, &status, WNOHANG) == pid)
244 // child killed, check signal
245 ensure_child_signal_(status, SIGTERM);
247 ensure_equals("child process exists after SIGTERM", ::kill(pid, 0), -1);
251 // child seems to be still exiting, give it some time
254 if(waitpid_(pid, &status, WNOHANG) != pid)
256 // child is still running, kill it
257 if(::kill(pid, SIGKILL) != 0)
266 std::ostringstream ss;
268 ss << "child " << pid << " could not be killed with SIGKILL, " << strerror_r(errno, e, sizeof(e)) << std::endl;
273 ensure_equals("wait after SIGKILL", waitpid_(pid, &status), pid);
274 ensure_child_signal_(status, SIGKILL);
276 ensure_equals("child process exists after SIGKILL", ::kill(pid, 0), -1);
278 std::ostringstream ss;
279 ss << "child " << pid << " had to be killed with SIGKILL";
284 test_result receive_result_(std::istream &ss, pid_t pid)
290 tr.result = test_result::result_type(type);
291 ss.ignore(1024, '\n');
293 std::getline(ss, tr.group);
295 ss.ignore(1024, '\n');
296 std::getline(ss, tr.name);
297 std::getline(ss, tr.exception_typeid);
298 std::copy( std::istreambuf_iterator<char>(ss.rdbuf()),
299 std::istreambuf_iterator<char>(),
300 std::back_inserter(tr.message) );
309 fdclose(int fd): fd_(fd) { }
318 pid_t waitpid_(pid_t pid, int *status, int flags = 0)
321 ensure("trying to wait for unknown pid", pids_.count(pid) > 0);
323 pid_t p = ::waitpid(pid, status, flags);
324 if( (flags & WNOHANG) && (p != pid) )
329 // read child result from pipe
337 int pipe = pids_[pid];
340 FD_SET(pipe, &fdset);
342 int result = select(pipe+1, &fdset, NULL, NULL, &tv);
343 ensure_errno("sanity check on select() failed", result >= 0);
347 ensure("sanity check on FD_ISSET() failed", FD_ISSET(pipe, &fdset) );
349 std::stringstream ss;
351 //TODO: max failure length
353 int r = read(pipe, buffer, sizeof(buffer));
354 ensure_errno("sanity check on read() failed", r >= 0);
359 throw rethrown( receive_result_(ss, pid) );
366 void ensure_child_exit_(int status, int exit_status)
368 if(WIFSIGNALED(status))
370 std::ostringstream ss;
371 ss << "child killed by signal " << WTERMSIG(status)
372 << ": expected exit with code " << exit_status;
374 throw failure(ss.str().c_str());
377 if(WIFEXITED(status))
379 if(WEXITSTATUS(status) != exit_status)
381 std::ostringstream ss;
382 ss << "child exited, expected '"
385 << WEXITSTATUS(status)
388 throw failure(ss.str().c_str());
392 if(WIFSTOPPED(status))
394 std::ostringstream ss;
395 ss << "child stopped by signal " << WTERMSIG(status)
396 << ": expected exit with code " << exit_status;
397 throw failure(ss.str().c_str());
401 void ensure_child_signal_(int status, int signal)
403 if(WIFSIGNALED(status))
405 if(WTERMSIG(status) != signal)
407 std::ostringstream ss;
408 ss << "child killed by signal, expected '"
413 throw failure(ss.str().c_str());
417 if(WIFEXITED(status))
419 std::ostringstream ss;
420 ss << "child exited with code " << WEXITSTATUS(status)
421 << ": expected signal " << signal;
423 throw failure(ss.str().c_str());
426 if(WIFSTOPPED(status))
428 std::ostringstream ss;
429 ss << "child stopped by signal " << WTERMSIG(status)
430 << ": expected kill by signal " << signal;
432 throw failure(ss.str().c_str());
436 std::set<pid_t> get_pids_() const
441 for(pid_map::const_iterator i = pids_.begin(); i != pids_.end(); ++i)
443 pids.insert( i->first );
460 struct test_object_posix
462 virtual ~test_object_posix()
467 struct test_group_posix
470 void send_result_(const T*, const test_result &)
474 virtual ~test_group_posix()