Esempio n. 1
0
Object c_AwaitAllWaitHandle::createAAWH(T start, T stop,
                                        F1 iterNext, F2 getCell) {
  auto ctx_idx = std::numeric_limits<context_idx_t>::max();
  uint32_t cnt = 0;

  for (auto iter = start; iter != stop; iter = iterNext(iter, stop)) {
    prepareChild(getCell(iter), ctx_idx, cnt);
  }

  if (!cnt) {
    return Object{returnEmpty()};
  }

  auto result = Alloc(cnt);
  auto next = &result->m_children[cnt];

  uint32_t idx = cnt - 1;
  for (auto iter = start; iter != stop; iter = iterNext(iter, stop)) {
    addChild(getCell(iter), next, idx);
  }

  assert(next == &result->m_children[0]);
  result->initialize(ctx_idx);
  return Object{std::move(result)};
}
Object c_AwaitAllWaitHandle::FromMixedArray(const MixedArray* dependencies) {
  auto const start = dependencies->data();
  auto const stop = start + dependencies->iterLimit();
  auto ctx_idx = std::numeric_limits<context_idx_t>::max();
  int32_t cnt = 0;

  for (auto iter = start; iter < stop; ++iter) {
    if (MixedArray::isTombstone(iter->data.m_type)) continue;
    prepareChild(tvToCell(&iter->data), ctx_idx, cnt);
  }

  if (!cnt) return returnEmpty();

  auto result = Alloc(cnt);
  auto next = &result->m_children[cnt];

  for (auto iter = start; iter < stop; ++iter) {
    if (MixedArray::isTombstone(iter->data.m_type)) continue;
    addChild(tvToCell(&iter->data), next);
  }

  assert(next == &result->m_children[0]);
  result->initialize(ctx_idx);
  return Object{std::move(result)};
}
void c_AsyncGeneratorWaitHandle::await(c_WaitableWaitHandle* child) {
  // Prepare child for establishing dependency. May throw.
  prepareChild(child);

  // Set up the dependency.
  m_child = child;
  setState(STATE_BLOCKED);
  blockOn(m_child);
}
void c_AsyncGeneratorWaitHandle::await(c_WaitableWaitHandle* child) {
  // Prepare child for establishing dependency. May throw.
  prepareChild(child);

  // Set up the dependency.
  setState(STATE_BLOCKED);
  m_child = child;
  m_child->getParentChain()
    .addParent(m_blockable, AsioBlockable::Kind::AsyncGeneratorWaitHandle);
}
void c_AsyncFunctionWaitHandle::await(Offset resumeOffset,
                                      c_WaitableWaitHandle* child) {
  // Prepare child for establishing dependency. May throw.
  prepareChild(child);

  // Suspend the async function.
  resumable()->setResumeAddr(nullptr, resumeOffset);

  // Set up the dependency.
  setState(STATE_BLOCKED);
  m_children[0].setChild(child);
}
Object c_AwaitAllWaitHandle::FromVector(const BaseVector* dependencies) {
  auto const start = dependencies->data();
  auto const stop = start + dependencies->size();
  auto ctx_idx = std::numeric_limits<context_idx_t>::max();
  int32_t cnt = 0;

  for (auto iter = start; iter < stop; ++iter) {
    prepareChild(tvAssertCell(iter), ctx_idx, cnt);
  }

  if (!cnt) return returnEmpty();

  auto result = Alloc(cnt);
  auto next = &result->m_children[cnt];

  for (auto iter = start; iter < stop; ++iter) {
    addChild(tvAssertCell(iter), next);
  }

  assert(next == &result->m_children[0]);
  result->initialize(ctx_idx);
  return Object{std::move(result)};
}
Object c_AwaitAllWaitHandle::FromMap(const BaseMap* dependencies) {
  auto const start = dependencies->firstElm();
  auto const stop = dependencies->elmLimit();
  auto ctx_idx = std::numeric_limits<context_idx_t>::max();
  int32_t cnt = 0;

  for (auto iter = start; iter != stop; iter = BaseMap::nextElm(iter, stop)) {
    prepareChild(tvAssertCell(&iter->data), ctx_idx, cnt);
  }

  if (!cnt) return returnEmpty();

  auto result = Alloc(cnt);
  auto next = &result->m_children[cnt];

  for (auto iter = start; iter != stop; iter = BaseMap::nextElm(iter, stop)) {
    addChild(tvAssertCell(&iter->data), next);
  }

  assert(next == &result->m_children[0]);
  result->initialize(ctx_idx);
  return Object{std::move(result)};
}
Object c_AwaitAllWaitHandle::FromPackedArray(const ArrayData* dependencies) {
  auto const start = reinterpret_cast<const TypedValue*>(dependencies + 1);
  auto const stop = start + dependencies->getSize();
  auto ctx_idx = std::numeric_limits<context_idx_t>::max();
  int32_t cnt = 0;

  for (auto iter = start; iter < stop; ++iter) {
    prepareChild(tvToCell(iter), ctx_idx, cnt);
  }

  if (!cnt) return returnEmpty();

  auto result = Alloc(cnt);
  auto next = &result->m_children[cnt];

  for (auto iter = start; iter < stop; ++iter) {
    addChild(tvToCell(iter), next);
  }

  assert(next == &result->m_children[0]);
  result->initialize(ctx_idx);
  return Object{std::move(result)};
}
Object c_AwaitAllWaitHandle::Create(Iter iter) {
  auto ctx_idx = std::numeric_limits<context_idx_t>::max();
  uint32_t cnt = 0;

  auto toCell = convert
    ? [](TypedValue tv) { return tvToCell(tv); }
    : [](TypedValue tv) { return tvAssertCell(tv); };

  iter([&](TypedValue v) { prepareChild(toCell(v), ctx_idx, cnt); });

  if (!cnt) {
    return Object{returnEmpty()};
  }

  auto result = Alloc(cnt);
  auto next = &result->m_children[cnt];
  uint32_t idx = cnt - 1;

  iter([&](TypedValue v) { addChild(toCell(v), next, idx); });

  assert(next == &result->m_children[0]);
  result->initialize(ctx_idx);
  return Object{std::move(result)};
}
Esempio n. 10
0
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);
}