// // Copyright 2005 The Android Open Source Project // #ifndef ANDROID_SIGNAL_HANDLER_H #define ANDROID_SIGNAL_HANDLER_H #include <utils/KeyedVector.h> #include <utils/threads.h> #include <signal.h> namespace android { // ---------------------------------------------------------------------- enum { DEFAULT_PROCESS_TAG = 1 }; class SignalHandler { public: typedef void (*child_callback_t)(pid_t child, void* userData); /** * Set a handler for when a child process exits. By calling * this, a waitpid() will be done when the child exits to remove * it from the zombie state. You can also optionally specify a * handler to be called when the child exits. * * If there is already a handler for this child process, it is * replaced by this new handler. In this case the old handler's * function is not called. * * @param childPid Process ID of child to watch. * @param childTag User-defined tag for this child. Must be * greater than zero. * @param handler If non-NULL, this will be called when the * child exits. It may be called in either a * separate signal handling thread, or * immediately if the child has already exited. * @param userData Propageted as-is to handler. * * @return status_t NO_ERROR if all is well. */ static status_t setChildHandler(pid_t childPid, int childTag = DEFAULT_PROCESS_TAG, child_callback_t handler = NULL, void* userData = NULL); /** * Kill all of the child processes for which we have a waiting * handler, whose tag is the given value. If tag is 0, all * children are killed. * * @param tag */ static void killAllChildren(int tag = 0); private: SignalHandler(); ~SignalHandler(); static SignalHandler* getInstance(); static void sigAction(int, siginfo_t*, void*); // -------------------------------------------------- // Shared state... all of this is protected by mLock. // -------------------------------------------------- mutable Mutex mLock; struct ChildHandler { pid_t childPid; int tag; child_callback_t handler; void* userData; }; KeyedVector<pid_t, ChildHandler> mChildHandlers; // -------------------------------------------------- // Commmand queue... data is inserted by the signal // handler using atomic ops, and retrieved by the // signal processing thread. Because these are touched // by the signal handler, no lock is used. // -------------------------------------------------- enum { COMMAND_QUEUE_SIZE = 64 }; struct CommandEntry { int filled; int signum; siginfo_t info; }; // The top of the queue. This is incremented atomically by the // signal handler before placing a command in the queue. volatile int32_t mCommandTop; // The bottom of the queue. Only modified by the processing // thread; the signal handler reads it only to determine if the // queue is full. int32_t mCommandBottom; // Incremented each time we receive a signal and don't have room // for it on the command queue. volatile int32_t mLostCommands; // The command processing thread. class ProcessThread; sp<Thread> mProcessThread; // Pipe used to tell command processing thread when new commands. // are available. The thread blocks on the read end, the signal // handler writes when it enqueues new commands. int mAvailMsg[2]; // The commands. CommandEntry mCommands[COMMAND_QUEUE_SIZE]; // -------------------------------------------------- // Singleton. // -------------------------------------------------- static Mutex mInstanceLock; static SignalHandler* mInstance; }; // ---------------------------------------------------------------------- }; // namespace android #endif // ANDROID_SIGNAL_HANDLER_H