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: 22 ProcessThread(SignalHandler& sh) 23 : Thread(false) 24 , mOwner(sh) 25 { 26 } 27 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 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 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 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 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 184 SignalHandler::~SignalHandler() 185 { 186 } 187 188 SignalHandler* SignalHandler::getInstance() 189 { 190 AutoMutex _l(mInstanceLock); 191 if (mInstance == NULL) { 192 mInstance = new SignalHandler(); 193 } 194 return mInstance; 195 } 196 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