-
-// The signleton ChildManager.
-ChildManager ChildManager::childManager;
-
-ChildManager::ChildManager()
-{
-}
-
-ChildManager::~ChildManager()
-{
-}
-
-bool
-ChildManager::forkChild(mach_port_t &outChildPort, int &outWaitStatus)
-{
- StLock<Mutex> lock(mLock, false);
- pid_t pid;
-
- /* Retry fork 10 times on failure after that just give up. */
- for (int tries = 0; tries < 10; ++tries)
- {
- lock.lock(); // aquire the lock
- pid = fork();
- if (pid != pid_t(-1))
- break;
-
- /* Something went wrong. */
- lock.unlock(); // Release the lock so we aren't holding it during the usleep below.
-
- int err = errno;
- if (err == EINTR)
- continue;
-
- if (err == EAGAIN || err == ENOMEM)
- usleep(100 * tries);
- else
- UnixError::throwMe(err);
- }
-
- if (pid == 0)
- {
- // Child - return true.
- return true;
- }
- else
- {
- Child child(pid);
- child.insertInMap(); // Insert child into the map.
- lock.unlock(); // Unlock as soon as we are done accessing mChildMap.
-
- child.waitForRegister();
-
- // Remove child from the map.
- child.eraseFromMap();
-
- // Transfer ownership of child's childPort to our caller.
- outChildPort = child.childPort();
-
- if (!outChildPort)
- outWaitStatus = child.waitStatus();
-
- // Parent - return false
- return false;
- }
-}
-
-void
-ChildManager::handleSignal(int signal_number)
-{
- if (signal_number == SIGCHLD)
- handleSigChild();
-}
-
-void
-ChildManager::registerChild(pid_t pid, mach_port_t &childPort)
-{
- StLock<Mutex> _(mLock);
- Child *child = findChild(pid);
- if (child)
- child->childPort(childPort);
-}
-
-// Assumes mLock is not locked.
-void
-ChildManager::eraseChild(pid_t pid)
-{
- StLock<Mutex> _(mLock);
- mChildMap.erase(pid);
-}
-
-// Assumes mLock is already locked.
-void
-ChildManager::insertChild(pid_t pid, Child *child)
-{
- mChildMap[pid] = child;
+// In case you wonder about the tango below, it's making sure we
+// get to "It's dead, Jim" with the minimum number of checkChildren()
+// calls while still working correctly if this is the only thread alive.
+//
+//@@@ We *could* define a "soft shutdown" MIG message to send to all
+//@@@ ServerChildren in this situation.
+//
+ServerChild::~ServerChild()
+{
+ mServicePort.destroy();
+
+ if (state() == alive) {
+ this->kill(SIGTERM); // shoot it once
+ checkChildren(); // check for quick death
+ if (state() == alive) {
+ usleep(300000); // give it some grace
+ if (state() == alive) { // could have been reaped by another thread
+ checkChildren(); // check again
+ if (state() == alive) { // it... just... won't... die...
+ this->kill(SIGKILL); // take THAT!
+ checkChildren();
+ if (state() == alive) // stuck zombie
+ abandon(); // leave the body behind
+ }
+ }
+ }
+ }