void getfds(NetworkSocket fds[2]) { if (netops::socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) != 0) { FAIL() << "failed to create socketpair: " << errnoStr(errno); } for (int idx = 0; idx < 2; ++idx) { if (netops::set_socket_non_blocking(fds[idx]) != 0) { FAIL() << "failed to put socket " << idx << " in non-blocking mode: " << errnoStr(errno); } } }
int NestedCommandLineApp::run(const std::vector<std::string>& args) { int status; try { doRun(args); status = 0; } catch (const ProgramExit& ex) { if (ex.what()[0]) { // if not empty fprintf(stderr, "%s\n", ex.what()); } status = ex.status(); } catch (const po::error& ex) { fprintf(stderr, "%s. Run `%s help' for help.\n", ex.what(), programName_.c_str()); status = 1; } if (status == 0) { if (ferror(stdout)) { fprintf(stderr, "error on standard output\n"); status = 1; } else if (fflush(stdout)) { fprintf(stderr, "standard output flush failed: %s\n", errnoStr(errno).c_str()); status = 1; } } return status; }
SubprocessSpawnError::SubprocessSpawnError(const char* executable, int errCode, int errnoValue) : errnoValue_(errnoValue), what_(to<std::string>(errCode == kExecFailure ? "failed to execute " : "error preparing to execute ", executable, ": ", errnoStr(errnoValue))) { }
AsyncIO::~AsyncIO() { CHECK_EQ(pending_, 0); if (ctx_) { int rc = io_queue_release(ctx_); CHECK_EQ(rc, 0) << "io_queue_release: " << errnoStr(-rc); } if (pollFd_ != -1) { CHECK_ERR(close(pollFd_)); } }
bool JemallocNodumpAllocator::extend_and_setup_arena() { #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED if (mallctl == nullptr) { // Not linked with jemalloc. return false; } size_t len = sizeof(arena_index_); if (auto ret = mallctl("arenas.extend", &arena_index_, &len, nullptr, 0)) { LOG(FATAL) << "Unable to extend arena: " << errnoStr(ret); } flags_ = MALLOCX_ARENA(arena_index_) | MALLOCX_TCACHE_NONE; // Set the custom alloc hook const auto key = folly::to<std::string>("arena.", arena_index_, ".chunk_hooks"); chunk_hooks_t hooks; len = sizeof(hooks); // Read the existing hooks if (auto ret = mallctl(key.c_str(), &hooks, &len, nullptr, 0)) { LOG(FATAL) << "Unable to get the hooks: " << errnoStr(ret); } if (original_chunk_alloc_ == nullptr) { original_chunk_alloc_ = hooks.alloc; } else { DCHECK_EQ(original_chunk_alloc_, hooks.alloc); } // Set the custom hook hooks.alloc = &JemallocNodumpAllocator::chunk_alloc; if (auto ret = mallctl(key.c_str(), nullptr, nullptr, &hooks, sizeof(hooks))) { LOG(FATAL) << "Unable to set the hooks: " << errnoStr(ret); } return true; #else // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED return false; #endif // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED }
std::ostream& operator<<(std::ostream& os, const AsyncIOOp& op) { os << "{" << op.state_ << ", "; if (op.state_ != AsyncIOOp::State::UNINITIALIZED) { os << op.iocb_; } if (op.state_ == AsyncIOOp::State::COMPLETED) { os << "result=" << op.result_; if (op.result_ < 0) { os << " (" << errnoStr(-op.result_) << ')'; } os << ", "; } return os << "}"; }
void* JemallocNodumpAllocator::chunk_alloc( void* chunk, size_t size, size_t alignment, bool* zero, bool* commit, unsigned arena_ind) { void* result = original_chunk_alloc_(chunk, size, alignment, zero, commit, arena_ind); if (result != nullptr) { if (auto ret = madvise(result, size, MADV_DONTDUMP)) { VLOG(1) << "Unable to madvise(MADV_DONTDUMP): " << errnoStr(ret); } } return result; }
/* static */ std::string AsyncSocketException::getMessage( AsyncSocketExceptionType type, const std::string& message, int errnoCopy) { if (errnoCopy != 0) { return sformat( "AsyncSocketException: {}, type = {}, errno = {} ({})", message, getExceptionTypeString(type), errnoCopy, errnoStr(errnoCopy)); } else { return sformat( "AsyncSocketException: {}, type = {}", message, getExceptionTypeString(type)); } }
Range<AsyncIO::Op**> AsyncIO::doWait(size_t minRequests, size_t maxRequests) { io_event events[maxRequests]; size_t count = 0; do { int ret; do { // GOTCHA: io_getevents() may returns less than min_nr results if // interrupted after some events have been read (if before, -EINTR // is returned). ret = io_getevents(ctx_, minRequests - count, maxRequests - count, events + count, /* timeout */ nullptr); // wait forever } while (ret == -EINTR); // Check as may not be able to recover without leaking events. CHECK_GE(ret, 0) << "AsyncIO: io_getevents failed with error " << errnoStr(-ret); count += ret; } while (count < minRequests); DCHECK_LE(count, maxRequests); completed_.clear(); if (count == 0) { return folly::Range<Op**>(); } for (size_t i = 0; i < count; ++i) { DCHECK(events[i].obj); Op* op = boost::intrusive::get_parent_from_member( events[i].obj, &AsyncIOOp::iocb_); decrementPending(); op->complete(events[i].res); completed_.push_back(op); } return folly::Range<Op**>(&completed_.front(), count); }
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); }