auto import from //depot/cupcake/@135843
diff --git a/cmds/runtime/SignalHandler.cpp b/cmds/runtime/SignalHandler.cpp
new file mode 100644
index 0000000..cccaabf
--- /dev/null
+++ b/cmds/runtime/SignalHandler.cpp
@@ -0,0 +1,249 @@
+//
+// Copyright 2005 The Android Open Source Project
+//
+
+#define LOG_TAG "SignalHandler"
+
+#include "SignalHandler.h"
+
+#include <utils/Atomic.h>
+#include <utils/Debug.h>
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+namespace android {
+
+class SignalHandler::ProcessThread : public Thread
+{
+public:
+    ProcessThread(SignalHandler& sh)
+        : Thread(false)
+        , mOwner(sh)
+    {
+    }
+
+    virtual bool threadLoop()
+    {
+        char buffer[32];
+        read(mOwner.mAvailMsg[0], buffer, sizeof(buffer));
+
+        LOGV("Signal command processing thread woke up!");
+
+        if (mOwner.mLostCommands) {
+            LOGE("Lost %d signals!", mOwner.mLostCommands);
+            mOwner.mLostCommands = 0;
+        }
+
+        int cur;
+        while ((cur=mOwner.mCommandBottom) != mOwner.mCommandTop) {
+            if (mOwner.mCommands[cur].filled == 0) {
+                LOGV("Command at %d is not yet filled", cur);
+                break;
+            }
+
+            LOGV("Processing command at %d, top is %d",
+                 cur, mOwner.mCommandTop);
+            processCommand(mOwner.mCommands[cur]);
+            mOwner.mCommands[cur].filled = 0;
+
+            int next = mOwner.mCommandBottom+1;
+            if (next >= COMMAND_QUEUE_SIZE) {
+                next = 0;
+            }
+
+            mOwner.mCommandBottom = next;
+        }
+
+        return true;
+    }
+
+    void processCommand(const CommandEntry& entry)
+    {
+        switch (entry.signum) {
+        case SIGCHLD: {
+            mOwner.mLock.lock();
+            ssize_t i = mOwner.mChildHandlers.indexOfKey(entry.info.si_pid);
+            ChildHandler ch;
+            if (i >= 0) {
+                ch = mOwner.mChildHandlers.valueAt(i);
+                mOwner.mChildHandlers.removeItemsAt(i);
+            }
+            mOwner.mLock.unlock();
+
+            LOGD("SIGCHLD: pid=%d, handle index=%d", entry.info.si_pid, i);
+
+            if (i >= 0) {
+                int res = waitpid(entry.info.si_pid, NULL, WNOHANG);
+                LOGW_IF(res == 0,
+                        "Received SIGCHLD, but pid %d is not yet stopped",
+                        entry.info.si_pid);
+                if (ch.handler) {
+                    ch.handler(entry.info.si_pid, ch.userData);
+                }
+            } else {
+                LOGW("Unhandled SIGCHLD for pid %d", entry.info.si_pid);
+            }
+        } break;
+        }
+    }
+
+    SignalHandler& mOwner;
+};
+
+
+Mutex SignalHandler::mInstanceLock;
+SignalHandler* SignalHandler::mInstance = NULL;
+
+status_t SignalHandler::setChildHandler(pid_t childPid,
+                                        int tag,
+                                        child_callback_t handler,
+                                        void* userData)
+{
+    SignalHandler* const self = getInstance();
+
+    self->mLock.lock();
+
+    // First make sure this child hasn't already exited.
+    pid_t res = waitpid(childPid, NULL, WNOHANG);
+    if (res != 0) {
+        if (res < 0) {
+            LOGW("setChildHandler waitpid of %d failed: %d (%s)",
+                 childPid, res, strerror(errno));
+        } else {
+            LOGW("setChildHandler waitpid of %d said %d already dead",
+                 childPid, res);
+        }
+
+        // Some kind of error...  just handle the exit now.
+        self->mLock.unlock();
+
+        if (handler) {
+            handler(childPid, userData);
+        }
+
+        // Return an error code -- 0 means it already exited.
+        return (status_t)res;
+    }
+
+    ChildHandler entry;
+    entry.childPid = childPid;
+    entry.tag = tag;
+    entry.handler = handler;
+    entry.userData = userData;
+
+    // Note: this replaces an existing entry for this pid, if there already
+    // is one.  This is the required behavior.
+    LOGD("setChildHandler adding pid %d, tag %d, handler %p, data %p",
+         childPid, tag, handler, userData);
+    self->mChildHandlers.add(childPid, entry);
+
+    self->mLock.unlock();
+
+    return NO_ERROR;
+}
+
+void SignalHandler::killAllChildren(int tag)
+{
+    SignalHandler* const self = getInstance();
+
+    AutoMutex _l (self->mLock);
+    const size_t N = self->mChildHandlers.size();
+    for (size_t i=0; i<N; i++) {
+        const ChildHandler& ch(self->mChildHandlers.valueAt(i));
+        if (tag == 0 || ch.tag == tag) {
+            const pid_t pid = ch.childPid;
+            LOGI("Killing child %d (tag %d)\n", pid, ch.tag);
+            kill(pid, SIGKILL);
+        }
+    }
+}
+
+SignalHandler::SignalHandler()
+    : mCommandTop(0)
+    , mCommandBottom(0)
+    , mLostCommands(0)
+{
+    memset(mCommands, 0, sizeof(mCommands));
+
+    int res = pipe(mAvailMsg);
+    LOGE_IF(res != 0, "Unable to create signal handler pipe: %s", strerror(errno));
+
+    mProcessThread = new ProcessThread(*this);
+    mProcessThread->run("SignalHandler", PRIORITY_HIGHEST);
+
+    struct sigaction sa;
+    memset(&sa, 0, sizeof(sa));
+    sa.sa_sigaction = sigAction;
+    sa.sa_flags = SA_NOCLDSTOP|SA_SIGINFO;
+    sigaction(SIGCHLD, &sa, NULL);
+}
+
+SignalHandler::~SignalHandler()
+{
+}
+
+SignalHandler* SignalHandler::getInstance()
+{
+    AutoMutex _l(mInstanceLock);
+    if (mInstance == NULL) {
+        mInstance = new SignalHandler();
+    }
+    return mInstance;
+}
+
+void SignalHandler::sigAction(int signum, siginfo_t* info, void*)
+{
+    static const char wakeupMsg[1] = { 0xff };
+
+    // If our signal handler is being called, then we know we have
+    // already initialized the SignalHandler class and thus mInstance
+    // is valid.
+    SignalHandler* const self = mInstance;
+
+    // XXX This is not safe!
+    #if 0
+    LOGV("Signal %d: signo=%d, errno=%d, code=%d, pid=%d\n",
+           signum,
+           info->si_signo, info->si_errno, info->si_code,
+           info->si_pid);
+    #endif
+
+    int32_t oldTop, newTop;
+
+    // Find the next command slot...
+    do {
+        oldTop = self->mCommandTop;
+
+        newTop = oldTop + 1;
+        if (newTop >= COMMAND_QUEUE_SIZE) {
+            newTop = 0;
+        }
+
+        if (newTop == self->mCommandBottom) {
+            // The buffer is filled up!  Ouch!
+            // XXX This is not safe!
+            #if 0
+            LOGE("Command buffer overflow!  newTop=%d\n", newTop);
+            #endif
+            android_atomic_add(1, &self->mLostCommands);
+            write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
+            return;
+        }
+    } while(android_atomic_cmpxchg(oldTop, newTop, &(self->mCommandTop)));
+
+    // Fill in the command data...
+    self->mCommands[oldTop].signum = signum;
+    self->mCommands[oldTop].info = *info;
+
+    // And now make this command available.
+    self->mCommands[oldTop].filled = 1;
+
+    // Wake up the processing thread.
+    write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
+}
+
+}; // namespace android
+