summaryrefslogtreecommitdiffstats
path: root/cmds/runtime/SignalHandler.h
blob: 7f4ef8e4e8147c7c0ef75343b99ebb7e669f374d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//
// 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