| // |
| // 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 |