• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2005 The Android Open Source Project
3 //
4 
5 #define LOG_TAG "SignalHandler"
6 
7 #include "SignalHandler.h"
8 
9 #include <utils/Atomic.h>
10 #include <utils/Debug.h>
11 #include <utils/Log.h>
12 
13 #include <errno.h>
14 #include <sys/wait.h>
15 #include <unistd.h>
16 
17 namespace android {
18 
19 class SignalHandler::ProcessThread : public Thread
20 {
21 public:
ProcessThread(SignalHandler & sh)22     ProcessThread(SignalHandler& sh)
23         : Thread(false)
24         , mOwner(sh)
25     {
26     }
27 
threadLoop()28     virtual bool threadLoop()
29     {
30         char buffer[32];
31         read(mOwner.mAvailMsg[0], buffer, sizeof(buffer));
32 
33         LOGV("Signal command processing thread woke up!");
34 
35         if (mOwner.mLostCommands) {
36             LOGE("Lost %d signals!", mOwner.mLostCommands);
37             mOwner.mLostCommands = 0;
38         }
39 
40         int cur;
41         while ((cur=mOwner.mCommandBottom) != mOwner.mCommandTop) {
42             if (mOwner.mCommands[cur].filled == 0) {
43                 LOGV("Command at %d is not yet filled", cur);
44                 break;
45             }
46 
47             LOGV("Processing command at %d, top is %d",
48                  cur, mOwner.mCommandTop);
49             processCommand(mOwner.mCommands[cur]);
50             mOwner.mCommands[cur].filled = 0;
51 
52             int next = mOwner.mCommandBottom+1;
53             if (next >= COMMAND_QUEUE_SIZE) {
54                 next = 0;
55             }
56 
57             mOwner.mCommandBottom = next;
58         }
59 
60         return true;
61     }
62 
processCommand(const CommandEntry & entry)63     void processCommand(const CommandEntry& entry)
64     {
65         switch (entry.signum) {
66         case SIGCHLD: {
67             mOwner.mLock.lock();
68             ssize_t i = mOwner.mChildHandlers.indexOfKey(entry.info.si_pid);
69             ChildHandler ch;
70             if (i >= 0) {
71                 ch = mOwner.mChildHandlers.valueAt(i);
72                 mOwner.mChildHandlers.removeItemsAt(i);
73             }
74             mOwner.mLock.unlock();
75 
76             LOGD("SIGCHLD: pid=%d, handle index=%d", entry.info.si_pid, i);
77 
78             if (i >= 0) {
79                 int res = waitpid(entry.info.si_pid, NULL, WNOHANG);
80                 LOGW_IF(res == 0,
81                         "Received SIGCHLD, but pid %d is not yet stopped",
82                         entry.info.si_pid);
83                 if (ch.handler) {
84                     ch.handler(entry.info.si_pid, ch.userData);
85                 }
86             } else {
87                 LOGW("Unhandled SIGCHLD for pid %d", entry.info.si_pid);
88             }
89         } break;
90         }
91     }
92 
93     SignalHandler& mOwner;
94 };
95 
96 
97 Mutex SignalHandler::mInstanceLock;
98 SignalHandler* SignalHandler::mInstance = NULL;
99 
setChildHandler(pid_t childPid,int tag,child_callback_t handler,void * userData)100 status_t SignalHandler::setChildHandler(pid_t childPid,
101                                         int tag,
102                                         child_callback_t handler,
103                                         void* userData)
104 {
105     SignalHandler* const self = getInstance();
106 
107     self->mLock.lock();
108 
109     // First make sure this child hasn't already exited.
110     pid_t res = waitpid(childPid, NULL, WNOHANG);
111     if (res != 0) {
112         if (res < 0) {
113             LOGW("setChildHandler waitpid of %d failed: %d (%s)",
114                  childPid, res, strerror(errno));
115         } else {
116             LOGW("setChildHandler waitpid of %d said %d already dead",
117                  childPid, res);
118         }
119 
120         // Some kind of error...  just handle the exit now.
121         self->mLock.unlock();
122 
123         if (handler) {
124             handler(childPid, userData);
125         }
126 
127         // Return an error code -- 0 means it already exited.
128         return (status_t)res;
129     }
130 
131     ChildHandler entry;
132     entry.childPid = childPid;
133     entry.tag = tag;
134     entry.handler = handler;
135     entry.userData = userData;
136 
137     // Note: this replaces an existing entry for this pid, if there already
138     // is one.  This is the required behavior.
139     LOGD("setChildHandler adding pid %d, tag %d, handler %p, data %p",
140          childPid, tag, handler, userData);
141     self->mChildHandlers.add(childPid, entry);
142 
143     self->mLock.unlock();
144 
145     return NO_ERROR;
146 }
147 
killAllChildren(int tag)148 void SignalHandler::killAllChildren(int tag)
149 {
150     SignalHandler* const self = getInstance();
151 
152     AutoMutex _l (self->mLock);
153     const size_t N = self->mChildHandlers.size();
154     for (size_t i=0; i<N; i++) {
155         const ChildHandler& ch(self->mChildHandlers.valueAt(i));
156         if (tag == 0 || ch.tag == tag) {
157             const pid_t pid = ch.childPid;
158             LOGI("Killing child %d (tag %d)\n", pid, ch.tag);
159             kill(pid, SIGKILL);
160         }
161     }
162 }
163 
SignalHandler()164 SignalHandler::SignalHandler()
165     : mCommandTop(0)
166     , mCommandBottom(0)
167     , mLostCommands(0)
168 {
169     memset(mCommands, 0, sizeof(mCommands));
170 
171     int res = pipe(mAvailMsg);
172     LOGE_IF(res != 0, "Unable to create signal handler pipe: %s", strerror(errno));
173 
174     mProcessThread = new ProcessThread(*this);
175     mProcessThread->run("SignalHandler", PRIORITY_HIGHEST);
176 
177     struct sigaction sa;
178     memset(&sa, 0, sizeof(sa));
179     sa.sa_sigaction = sigAction;
180     sa.sa_flags = SA_NOCLDSTOP|SA_SIGINFO;
181     sigaction(SIGCHLD, &sa, NULL);
182 }
183 
~SignalHandler()184 SignalHandler::~SignalHandler()
185 {
186 }
187 
getInstance()188 SignalHandler* SignalHandler::getInstance()
189 {
190     AutoMutex _l(mInstanceLock);
191     if (mInstance == NULL) {
192         mInstance = new SignalHandler();
193     }
194     return mInstance;
195 }
196 
sigAction(int signum,siginfo_t * info,void *)197 void SignalHandler::sigAction(int signum, siginfo_t* info, void*)
198 {
199     static const char wakeupMsg[1] = { 0xff };
200 
201     // If our signal handler is being called, then we know we have
202     // already initialized the SignalHandler class and thus mInstance
203     // is valid.
204     SignalHandler* const self = mInstance;
205 
206     // XXX This is not safe!
207     #if 0
208     LOGV("Signal %d: signo=%d, errno=%d, code=%d, pid=%d\n",
209            signum,
210            info->si_signo, info->si_errno, info->si_code,
211            info->si_pid);
212     #endif
213 
214     int32_t oldTop, newTop;
215 
216     // Find the next command slot...
217     do {
218         oldTop = self->mCommandTop;
219 
220         newTop = oldTop + 1;
221         if (newTop >= COMMAND_QUEUE_SIZE) {
222             newTop = 0;
223         }
224 
225         if (newTop == self->mCommandBottom) {
226             // The buffer is filled up!  Ouch!
227             // XXX This is not safe!
228             #if 0
229             LOGE("Command buffer overflow!  newTop=%d\n", newTop);
230             #endif
231             android_atomic_add(1, &self->mLostCommands);
232             write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
233             return;
234         }
235     } while(android_atomic_cmpxchg(oldTop, newTop, &(self->mCommandTop)));
236 
237     // Fill in the command data...
238     self->mCommands[oldTop].signum = signum;
239     self->mCommands[oldTop].info = *info;
240 
241     // And now make this command available.
242     self->mCommands[oldTop].filled = 1;
243 
244     // Wake up the processing thread.
245     write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
246 }
247 
248 }; // namespace android
249 
250