SignalHandler.h revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1//
2// Copyright 2005 The Android Open Source Project
3//
4#ifndef ANDROID_SIGNAL_HANDLER_H
5#define ANDROID_SIGNAL_HANDLER_H
6
7#include <utils/KeyedVector.h>
8#include <utils/threads.h>
9
10#include <signal.h>
11
12namespace android {
13
14// ----------------------------------------------------------------------
15
16enum {
17    DEFAULT_PROCESS_TAG = 1
18};
19
20class SignalHandler
21{
22public:
23    typedef void (*child_callback_t)(pid_t child, void* userData);
24
25    /**
26     * Set a handler for when a child process exits.  By calling
27     * this, a waitpid() will be done when the child exits to remove
28     * it from the zombie state.  You can also optionally specify a
29     * handler to be called when the child exits.
30     *
31     * If there is already a handler for this child process, it is
32     * replaced by this new handler.  In this case the old handler's
33     * function is not called.
34     *
35     * @param childPid Process ID of child to watch.
36     * @param childTag User-defined tag for this child.  Must be
37     *                 greater than zero.
38     * @param handler If non-NULL, this will be called when the
39     *                child exits.  It may be called in either a
40     *                separate signal handling thread, or
41     *                immediately if the child has already exited.
42     * @param userData Propageted as-is to handler.
43     *
44     * @return status_t NO_ERROR if all is well.
45     */
46    static status_t             setChildHandler(pid_t childPid,
47                                                int childTag = DEFAULT_PROCESS_TAG,
48                                                child_callback_t handler = NULL,
49                                                void* userData = NULL);
50
51    /**
52     * Kill all of the child processes for which we have a waiting
53     * handler, whose tag is the given value.  If tag is 0, all
54     * children are killed.
55     *
56     * @param tag
57     */
58    static void                 killAllChildren(int tag = 0);
59
60private:
61                                SignalHandler();
62                                ~SignalHandler();
63
64    static SignalHandler*       getInstance();
65
66    static void                 sigAction(int, siginfo_t*, void*);
67
68    // --------------------------------------------------
69    // Shared state...  all of this is protected by mLock.
70    // --------------------------------------------------
71
72    mutable Mutex                       mLock;
73
74    struct ChildHandler
75    {
76        pid_t childPid;
77        int tag;
78        child_callback_t handler;
79        void* userData;
80    };
81    KeyedVector<pid_t, ChildHandler>    mChildHandlers;
82
83    // --------------------------------------------------
84    // Commmand queue...  data is inserted by the signal
85    // handler using atomic ops, and retrieved by the
86    // signal processing thread.  Because these are touched
87    // by the signal handler, no lock is used.
88    // --------------------------------------------------
89
90    enum {
91        COMMAND_QUEUE_SIZE = 64
92    };
93    struct CommandEntry
94    {
95        int filled;
96        int signum;
97        siginfo_t info;
98    };
99
100    // The top of the queue.  This is incremented atomically by the
101    // signal handler before placing a command in the queue.
102    volatile int32_t                    mCommandTop;
103
104    // The bottom of the queue.  Only modified by the processing
105    // thread; the signal handler reads it only to determine if the
106    // queue is full.
107    int32_t                             mCommandBottom;
108
109    // Incremented each time we receive a signal and don't have room
110    // for it on the command queue.
111    volatile int32_t                    mLostCommands;
112
113    // The command processing thread.
114    class ProcessThread;
115    sp<Thread>                          mProcessThread;
116
117    // Pipe used to tell command processing thread when new commands.
118    // are available.  The thread blocks on the read end, the signal
119    // handler writes when it enqueues new commands.
120    int                                 mAvailMsg[2];
121
122    // The commands.
123    CommandEntry                        mCommands[COMMAND_QUEUE_SIZE];
124
125    // --------------------------------------------------
126    // Singleton.
127    // --------------------------------------------------
128
129    static Mutex                        mInstanceLock;
130    static SignalHandler*               mInstance;
131};
132
133// ----------------------------------------------------------------------
134
135}; // namespace android
136
137#endif // ANDROID_SIGNAL_HANDLER_H
138