]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/unixchild.cpp
2 * Copyright (c) 2000-2001,2003-2004,2011,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 // unixchild - low-level UNIX process child management.
28 // Note that the map-of-children (mChildren) only holds children presumed to
29 // be alive. Neither unborn nor dead children are included. This is important
30 // for how children are reaped and death notifications dispatched, and should
31 // not be changed without prior deep contemplation.
34 // All Child objects in this subsystem are mutated under control of a single
35 // lock (mChildren). This means that children will not step on each other.
36 // However, death callbacks (Child::dying) are made outside the lock's scope
37 // to avoid deadlock scenarios with outside locking hierarchies. When Child::dying
38 // is called, the child has already transitioned to "dead" state and is no longer
39 // in the (live) children map.
41 #include "unixchild.h"
42 #include <security_utilities/debugging.h>
47 namespace UnixPlusPlus
{
51 // All our globals are in a ModuleNexus, for that special lazy-init goodness
53 ModuleNexus
<Child::Children
> Child::mChildren
;
57 // Make and break Children
60 : mState(unborn
), mPid(0), mStatus(0)
67 assert(mState
!= alive
); // not allowed by protocol
72 // Take a Child object that is not alive (i.e. is either unborn or dead),
73 // and reset it to unborn, so you can fork() it again.
74 // This call forgets everything about the previous process.
80 assert(false); // bad boy; can't do that
84 secinfo("unixchild", "%p reset (from state %d)", this, mState
);
94 // Global inquiries and setup
96 void Child::sharedChildren(bool s
)
98 StLock
<Mutex
> _(mChildren());
99 mChildren().shared
= s
;
102 bool Child::sharedChildren()
104 StLock
<Mutex
> _(mChildren());
105 return mChildren().shared
;
110 // Check status for one Child
112 Child::State
Child::check()
117 StLock
<Mutex
> _(mChildren());
121 reaped
= checkStatus(WNOHANG
);
134 // Wait for a particular child to be dead.
135 // This call cannot wait for multiple children; you'll have
136 // to program that yourself using whatever event loop you're using.
142 StLock
<Mutex
> _(mChildren());
145 reaped
= checkStatus(0); // wait for it
148 assert(false); // don't do that
160 // Requires caller to hold mChildren() lock.
162 void Child::tryKill(int signal
)
164 assert(mState
== alive
); // ... or don't bother us
165 secinfo("unixchild", "%p (pid %d) sending signal(%d)", this, pid(), signal
);
166 if (::kill(pid(), signal
))
168 case ESRCH
: // someone else reaped ths child; or things are just wacky
169 secinfo("unixchild", "%p (pid %d) has disappeared!", this, pid());
171 mChildren().erase(pid());
174 UnixError::throwMe();
180 // Send a signal to the Child.
181 // This will succeed (and do nothing) if the Child is not alive.
183 void Child::kill(int signal
)
185 StLock
<Mutex
> _(mChildren());
189 secinfo("unixchild", "%p (pid %d) not alive; cannot send signal %d",
190 this, pid(), signal
);
195 // Kill with prejudice.
196 // This will make a serious attempt to *synchronously* kill the process before
197 // returning. If that doesn't work for some reason, abandon the child.
198 // This is one thing you can do in the destructor of your subclass to legally
199 // dispose of your Child's process.
203 // note that we mustn't hold the lock across these calls
204 switch (this->state()) {
206 if (this->state() == alive
) {
207 this->kill(SIGTERM
); // shoot it once
208 checkChildren(); // check for quick death
209 if (this->state() == alive
) {
210 usleep(200000); // give it some time to die
211 if (this->state() == alive
) { // could have been reaped by another thread
212 checkChildren(); // check again
213 if (this->state() == alive
) { // it... just... won't... die...
214 this->kill(SIGKILL
); // take THAT!
216 if (this->state() == alive
) // stuck zombie
217 this->abandon(); // leave the body behind
224 secinfo("unixchild", "%p (pid %d) already dead; ignoring kill request", this, pid());
227 secinfo("unixchild", "%p state %d; ignoring kill request", this, this->state());
234 // Take a living child and cut it loose. This sets its state to abandoned
235 // and removes it from the child registry.
236 // This is one thing you can do in the destructor of your subclass to legally
237 // dispose of your child's process.
239 void Child::abandon()
241 StLock
<Mutex
> _(mChildren());
242 if (mState
== alive
) {
243 secinfo("unixchild", "%p (pid %d) abandoned", this, pid());
245 mChildren().erase(pid());
247 secinfo("unixchild", "%p (pid %d) is not alive; abandon() ignored",
254 // Forensic examination of the Child's cadaver.
255 // Not interlocked because you have to check for state() == dead first,
256 // and these values are const ever after.
258 int Child::waitStatus() const
260 assert(mState
== dead
);
264 bool Child::bySignal() const
266 assert(mState
== dead
);
267 return WIFSIGNALED(mStatus
);
270 int Child::exitCode() const
272 assert(mState
== dead
);
273 assert(WIFEXITED(mStatus
));
274 return WEXITSTATUS(mStatus
);
277 int Child::exitSignal() const
279 assert(mState
== dead
);
280 assert(WIFSIGNALED(mStatus
));
281 return WTERMSIG(mStatus
);
284 bool Child::coreDumped() const
286 assert(mState
== dead
);
287 assert(WIFSIGNALED(mStatus
));
288 return WCOREDUMP(mStatus
);
293 // Find a child in the child map, by pid
294 // This will only find live children, and return NULL for all others.
296 Child
*Child::findGeneric(pid_t pid
)
298 StLock
<Mutex
> _(mChildren());
299 Children::iterator it
= mChildren().find(pid
);
300 if (it
== mChildren().end())
308 // Do the actual fork job.
309 // At this layer, the client side does nothing but run childAction(). Any plumbing
310 // or cleanup is up to that function (which runs in the child) and the caller (after
311 // fork() returns). If childAction() returns at all, we will call exit(1) to get
316 static const unsigned maxDelay
= 30; // seconds increment, i.e. 5 retries
318 assert(mState
== unborn
);
319 for (unsigned delay
= 1; ;) {
320 switch (pid_t pid
= ::fork()) {
321 case -1: // fork failed
324 secinfo("unixchild", "%p fork EINTR; retrying", this);
325 continue; // no problem
327 if (delay
< maxDelay
) {
328 secinfo("unixchild", "%p fork EAGAIN; delaying %d seconds",
336 UnixError::throwMe();
338 assert(false); // unreached
341 //@@@ bother to clean child map?
350 StLock
<Mutex
> _(mChildren());
353 mChildren().insert(make_pair(pid
, this));
355 secinfo("unixchild", "%p (parent) running parent action", this);
356 this->parentAction();
365 // Check the status of this child by explicitly probing it.
366 // Caller must hold master lock.
368 bool Child::checkStatus(int options
)
370 assert(state() == alive
);
371 secinfo("unixchild", "checking %p (pid %d)", this, this->pid());
374 switch (IFDEBUG(pid_t pid
=) ::wait4(this->pid(), &status
, options
, NULL
)) {
380 secinfo("unixchild", "%p (pid=%d) unknown to kernel", this, this->pid());
382 mChildren().erase(this->pid());
385 UnixError::throwMe();
388 return false; // child not ready (do nothing)
390 assert(pid
== this->pid());
398 // Perform an idempotent check for dead children, as per the UNIX wait() system calls.
399 // This can be called at any time, and will reap all children that have died since
400 // last time. The obvious time to call this is after a SIGCHLD has been received;
401 // however signal dispatch is so - uh, interesting - in UNIX that we don't even try
402 // to deal with it at this level. Suffice to say that calling checkChildren directly
403 // from within a signal handler is NOT generally safe due to locking constraints.
405 // If the shared() flag is on, we explicitly poll each child known to be recently
406 // alive. That is less efficient than reaping any and all, but leaves any children
407 // alone that someone else may have created without our knowledge. The default is
408 // not shared(), which will reap (and discard) any unrelated children without letting
409 // the caller know about it.
411 void Child::checkChildren()
415 StLock
<Mutex
> _(mChildren());
416 if (mChildren().shared
) {
417 for (Children::iterator it
= mChildren().begin(); it
!= mChildren().end(); it
++)
418 if (it
->second
->checkStatus(WNOHANG
))
419 casualties
.add(it
->second
);
420 } else if (!mChildren().empty()) {
422 while (pid_t pid
= ::wait4(0, &status
, WNOHANG
, NULL
)) {
423 secinfo("unixchild", "universal child check (%ld children known alive)", mChildren().size());
428 secinfo("unixchild", "EINTR on wait4; retrying");
429 continue; // benign, but retry the wait()
431 // Should not normally happen (there *is* a child around),
432 // but gets returned anyway if the child is stopped in the debugger.
433 // Treat like a zero return (no children ready to be buried).
434 secinfo("unixchild", "ECHILD with filled nursery (ignored)");
437 UnixError::throwMe();
440 if (Child
*child
= mChildren()[pid
]) {
442 casualties
.add(child
);
444 secinfo("unixchild", "reaping feral child pid=%d", pid
);
445 if (mChildren().empty())
446 goto no_more
; // none left
452 secinfo("unixchild", "spurious checkChildren (the nursery is empty)");
454 } // release master lock
460 // Perform the canonical last rites for a formerly alive child.
461 // Requires master lock held throughout.
463 void Child::bury(int status
)
465 assert(mState
== alive
);
468 mChildren().erase(mPid
);
471 secinfo("unixchild", "%p (pid %d) died by signal %d%s",
472 this, mPid
, exitSignal(),
473 coreDumped() ? " and dumped core" : "");
475 secinfo("unixchild", "%p (pid %d) died by exit(%d)",
476 this, mPid
, exitCode());
484 void Child::parentAction()
494 void Child::Bier::notify()
496 for (const_iterator it
= begin(); it
!= end(); ++it
)
501 } // end namespace IPPlusPlus
502 } // end namespace Security