static int test5(int argc, const char* argv[]) { int r; const char* cmd[4]; (void)argc; cmd[0] = argv[0]; cmd[1] = "run"; cmd[2] = "4"; cmd[3] = 0; fprintf(stdout, "Output on stdout before recursive test.\n"); fprintf(stderr, "Output on stderr before recursive test.\n"); fflush(stdout); fflush(stderr); r = runChild(cmd, kwsysProcess_State_Exception, kwsysProcess_Exception_Fault, 1, 1, 1, 0, 15, 0, 1, 0); fprintf(stdout, "Output on stdout after recursive test.\n"); fprintf(stderr, "Output on stderr after recursive test.\n"); fflush(stdout); fflush(stderr); return r; }
int main() { int childPid = 0; int ourPid = getpid(); printf("Ainda existe apenas um processo (%d)\n", ourPid); childPid = fork(); printf("Agora somos dois (%i)\n", getpid()); if(childPid > 0) { runMain(ourPid, childPid); } else { if(childPid < 0) { checkError(childPid); } else { runChild(); } } return 0; }
static int test8(int argc, const char* argv[]) { /* Create a disowned grandchild to test handling of processes that exit before their children. */ int r; const char* cmd[4]; (void)argc; cmd[0] = argv[0]; cmd[1] = "run"; cmd[2] = "108"; cmd[3] = 0; fprintf(stdout, "Output on stdout before grandchild test.\n"); fprintf(stderr, "Output on stderr before grandchild test.\n"); fflush(stdout); fflush(stderr); r = runChild(cmd, kwsysProcess_State_Disowned, kwsysProcess_Exception_None, 1, 1, 1, 0, 10, 0, 1, 1); fprintf(stdout, "Output on stdout after grandchild test.\n"); fprintf(stderr, "Output on stderr after grandchild test.\n"); fflush(stdout); fflush(stderr); return r; }
btNode::status btSelectorNode::run(btCharacter *self) { /*for(int i = this->currentChildIndex(); i < this->childCount(); i++) { if(this->currentChildStatus() == btNode::Succeeded) { return btNode::Succeeded; } return runChild(i); }*/ if(this->currentChildStatus() == btNode::Succeeded) { return Succeeded; } if(this->nextChildIndex() < this->childCount()) { return runChild(this->currentChildIndex()); } return Failed; }
void Subprocess::spawnInternal( std::unique_ptr<const char*[]> argv, const char* executable, Options& options, const std::vector<std::string>* env, int errFd) { // Parent work, pre-fork: create pipes std::vector<int> childFds; // Close all of the childFds as we leave this scope SCOPE_EXIT { // These are only pipes, closing them shouldn't fail for (int cfd : childFds) { CHECK_ERR(::close(cfd)); } }; int r; for (auto& p : options.fdActions_) { if (p.second == PIPE_IN || p.second == PIPE_OUT) { int fds[2]; r = ::pipe(fds); checkUnixError(r, "pipe"); PipeInfo pinfo; pinfo.direction = p.second; int cfd; if (p.second == PIPE_IN) { // Child gets reading end pinfo.parentFd = fds[1]; cfd = fds[0]; } else { pinfo.parentFd = fds[0]; cfd = fds[1]; } p.second = cfd; // ensure it gets dup2()ed pinfo.childFd = p.first; childFds.push_back(cfd); pipes_.push_back(pinfo); } } // This should already be sorted, as options.fdActions_ is DCHECK(std::is_sorted(pipes_.begin(), pipes_.end())); // Note that the const casts below are legit, per // http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html char** argVec = const_cast<char**>(argv.get()); // Set up environment std::unique_ptr<const char*[]> envHolder; char** envVec; if (env) { envHolder = cloneStrings(*env); envVec = const_cast<char**>(envHolder.get()); } else { envVec = environ; } // Block all signals around vfork; see http://ewontfix.com/7/. // // As the child may run in the same address space as the parent until // the actual execve() system call, any (custom) signal handlers that // the parent has might alter parent's memory if invoked in the child, // with undefined results. So we block all signals in the parent before // vfork(), which will cause them to be blocked in the child as well (we // rely on the fact that Linux, just like all sane implementations, only // clones the calling thread). Then, in the child, we reset all signals // to their default dispositions (while still blocked), and unblock them // (so the exec()ed process inherits the parent's signal mask) // // The parent also unblocks all signals as soon as vfork() returns. sigset_t allBlocked; r = sigfillset(&allBlocked); checkUnixError(r, "sigfillset"); sigset_t oldSignals; r = pthread_sigmask(SIG_SETMASK, &allBlocked, &oldSignals); checkPosixError(r, "pthread_sigmask"); SCOPE_EXIT { // Restore signal mask r = pthread_sigmask(SIG_SETMASK, &oldSignals, nullptr); CHECK_EQ(r, 0) << "pthread_sigmask: " << errnoStr(r); // shouldn't fail }; pid_t pid = vfork(); if (pid == 0) { int errnoValue = prepareChild(options, &oldSignals); if (errnoValue != 0) { childError(errFd, kChildFailure, errnoValue); } errnoValue = runChild(executable, argVec, envVec, options); // If we get here, exec() failed. childError(errFd, kExecFailure, errnoValue); } // In parent. Make sure vfork() succeeded. checkUnixError(pid, errno, "vfork"); // Child is alive. We have to be very careful about throwing after this // point. We are inside the constructor, so if we throw the Subprocess // object will have never existed, and the destructor will never be called. // // We should only throw if we got an error via the errFd, and we know the // child has exited and can be immediately waited for. In all other cases, // we have no way of cleaning up the child. pid_ = pid; returnCode_ = ProcessReturnCode(RV_RUNNING); }
int main(int argc, const char* argv[]) { int n = 0; #if 0 { HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); DuplicateHandle(GetCurrentProcess(), out, GetCurrentProcess(), &out, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); SetStdHandle(STD_OUTPUT_HANDLE, out); } { HANDLE out = GetStdHandle(STD_ERROR_HANDLE); DuplicateHandle(GetCurrentProcess(), out, GetCurrentProcess(), &out, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); SetStdHandle(STD_ERROR_HANDLE, out); } #endif if(argc == 2) { n = atoi(argv[1]); } else if(argc == 3 && strcmp(argv[1], "run") == 0) { n = atoi(argv[2]); } /* Check arguments. */ if(((n >= 1 && n <= 8) || n == 108) && argc == 3) { /* This is the child process for a requested test number. */ switch (n) { case 1: return test1(argc, argv); case 2: return test2(argc, argv); case 3: return test3(argc, argv); case 4: return test4(argc, argv); case 5: return test5(argc, argv); case 6: test6(argc, argv); return 0; case 7: return test7(argc, argv); case 8: return test8(argc, argv); case 108: return test8_grandchild(argc, argv); } fprintf(stderr, "Invalid test number %d.\n", n); return 1; } else if(n >= 1 && n <= 8) { /* This is the parent process for a requested test number. */ int states[8] = { kwsysProcess_State_Exited, kwsysProcess_State_Exited, kwsysProcess_State_Expired, kwsysProcess_State_Exception, kwsysProcess_State_Exited, kwsysProcess_State_Expired, kwsysProcess_State_Exited, kwsysProcess_State_Exited }; int exceptions[8] = { kwsysProcess_Exception_None, kwsysProcess_Exception_None, kwsysProcess_Exception_None, kwsysProcess_Exception_Fault, kwsysProcess_Exception_None, kwsysProcess_Exception_None, kwsysProcess_Exception_None, kwsysProcess_Exception_None }; int values[8] = {0, 123, 1, 1, 0, 0, 0, 0}; int outputs[8] = {1, 1, 1, 1, 1, 0, 1, 1}; int delays[8] = {0, 0, 0, 0, 0, 1, 0, 0}; double timeouts[8] = {10, 10, 10, 30, 30, 10, -1, 10}; int polls[8] = {0, 0, 0, 0, 0, 0, 1, 0}; int repeat[8] = {2, 1, 1, 1, 1, 1, 1, 1}; int r; const char* cmd[4]; #ifdef _WIN32 char* argv0 = 0; if(n == 0 && (argv0 = strdup(argv[0]))) { /* Try converting to forward slashes to see if it works. */ char* c; for(c=argv0; *c; ++c) { if(*c == '\\') { *c = '/'; } } cmd[0] = argv0; } else { cmd[0] = argv[0]; } #else cmd[0] = argv[0]; #endif cmd[1] = "run"; cmd[2] = argv[1]; cmd[3] = 0; fprintf(stdout, "Output on stdout before test %d.\n", n); fprintf(stderr, "Output on stderr before test %d.\n", n); fflush(stdout); fflush(stderr); r = runChild(cmd, states[n-1], exceptions[n-1], values[n-1], 0, outputs[n-1], delays[n-1], timeouts[n-1], polls[n-1], repeat[n-1], 0); fprintf(stdout, "Output on stdout after test %d.\n", n); fprintf(stderr, "Output on stderr after test %d.\n", n); fflush(stdout); fflush(stderr); #if defined(_WIN32) if(argv0) { free(argv0); } #endif return r; } else if(argc > 2 && strcmp(argv[1], "0") == 0) { /* This is the special debugging test to run a given command line. */ const char** cmd = argv+2; int state = kwsysProcess_State_Exited; int exception = kwsysProcess_Exception_None; int value = 0; double timeout = 0; int r = runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1, 0); return r; } else { /* Improper usage. */ fprintf(stdout, "Usage: %s <test number>\n", argv[0]); return 1; } }
void Subprocess::spawn( std::unique_ptr<const char*[]> argv, const char* executable, const Options& optionsIn, const std::vector<std::string>* env) { if (optionsIn.usePath_ && env) { throw std::invalid_argument( "usePath() not allowed when overriding environment"); } // Make a copy, we'll mutate options Options options(optionsIn); // Parent work, pre-fork: create pipes std::vector<int> childFds; for (auto& p : options.fdActions_) { if (p.second == PIPE_IN || p.second == PIPE_OUT) { int fds[2]; int r = ::pipe(fds); checkUnixError(r, "pipe"); PipeInfo pinfo; pinfo.direction = p.second; int cfd; if (p.second == PIPE_IN) { // Child gets reading end pinfo.parentFd = fds[1]; cfd = fds[0]; } else { pinfo.parentFd = fds[0]; cfd = fds[1]; } p.second = cfd; // ensure it gets dup2()ed pinfo.childFd = p.first; childFds.push_back(cfd); pipes_.push_back(pinfo); } } // This should already be sorted, as options.fdActions_ is DCHECK(std::is_sorted(pipes_.begin(), pipes_.end())); // Note that the const casts below are legit, per // http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html char** argVec = const_cast<char**>(argv.get()); // Set up environment std::unique_ptr<const char*[]> envHolder; char** envVec; if (env) { envHolder = cloneStrings(*env); envVec = const_cast<char**>(envHolder.get()); } else { envVec = environ; } // Block all signals around vfork; see http://ewontfix.com/7/. // // As the child may run in the same address space as the parent until // the actual execve() system call, any (custom) signal handlers that // the parent has might alter parent's memory if invoked in the child, // with undefined results. So we block all signals in the parent before // vfork(), which will cause them to be blocked in the child as well (we // rely on the fact that Linux, just like all sane implementations, only // clones the calling thread). Then, in the child, we reset all signals // to their default dispositions (while still blocked), and unblock them // (so the exec()ed process inherits the parent's signal mask) // // The parent also unblocks all signals as soon as vfork() returns. sigset_t allBlocked; int r = ::sigfillset(&allBlocked); checkUnixError(r, "sigfillset"); sigset_t oldSignals; r = pthread_sigmask(SIG_SETMASK, &allBlocked, &oldSignals); checkPosixError(r, "pthread_sigmask"); pid_t pid = vfork(); if (pid == 0) { // While all signals are blocked, we must reset their // dispositions to default. for (int sig = 1; sig < NSIG; ++sig) { ::signal(sig, SIG_DFL); } // Unblock signals; restore signal mask. int r = pthread_sigmask(SIG_SETMASK, &oldSignals, nullptr); if (r != 0) abort(); runChild(executable, argVec, envVec, options); // This should never return, but there's nothing else we can do here. abort(); } // In parent. We want to restore the signal mask even if vfork fails, // so we'll save errno here, restore the signal mask, and only then // throw. int savedErrno = errno; // Restore signal mask; do this even if vfork fails! // We only check for errors from pthread_sigmask after we recorded state // that the child is alive, so we know to reap it. r = pthread_sigmask(SIG_SETMASK, &oldSignals, nullptr); checkUnixError(pid, savedErrno, "vfork"); // Child is alive pid_ = pid; returnCode_ = ProcessReturnCode(RV_RUNNING); // Parent work, post-fork: close child's ends of pipes for (int f : childFds) { closeChecked(f); } checkPosixError(r, "pthread_sigmask"); }