1 /* 2 * Copyright 2000 Sun Microsystems, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any questions. 22 * 23 */ 24 25 #include <iostream> 26 #include "Reaper.hpp" 27 28 using namespace std; 29 30 Reaper::Reaper(ReaperCB* cb) { 31 InitializeCriticalSection(&crit); 32 event = CreateEvent(NULL, TRUE, FALSE, NULL); 33 this->cb = cb; 34 35 active = false; 36 shouldShutDown = false; 37 } 38 39 bool 40 Reaper::start() { 41 bool result = false; 42 43 EnterCriticalSection(&crit); 44 45 if (!active) { 46 DWORD id; 47 HANDLE reaper = CreateThread(NULL, 0, &Reaper::reaperThreadEntry, 48 this, 0, &id); 49 if (reaper != NULL) { 50 result = true; 51 } 52 } 53 54 LeaveCriticalSection(&crit); 55 56 return result; 57 } 58 59 bool 60 Reaper::stop() { 61 bool result = false; 62 63 EnterCriticalSection(&crit); 64 65 if (active) { 66 shouldShutDown = true; 67 SetEvent(event); 68 while (active) { 69 Sleep(1); 70 } 71 shouldShutDown = false; 72 result = true; 73 } 74 75 LeaveCriticalSection(&crit); 76 77 return result; 78 } 79 80 void 81 Reaper::registerProcess(HANDLE processHandle, void* userData) { 82 ProcessInfo info; 83 84 info.handle = processHandle; 85 info.userData = userData; 86 87 EnterCriticalSection(&crit); 88 89 procInfo.push_back(info); 90 SetEvent(event); 91 92 LeaveCriticalSection(&crit); 93 } 94 95 void 96 Reaper::reaperThread() { 97 while (!shouldShutDown) { 98 // Take atomic snapshot of the current process list and user data 99 EnterCriticalSection(&crit); 100 101 int num = procInfo.size(); 102 HANDLE* handleList = new HANDLE[1 + num]; 103 void** dataList = new void*[num]; 104 for (int i = 0; i < num; i++) { 105 handleList[i] = procInfo[i].handle; 106 dataList[i] = procInfo[i].userData; 107 } 108 109 LeaveCriticalSection(&crit); 110 111 // Topmost handle becomes the event object, so other threads can 112 // signal this one to notice differences in the above list (or 113 // shut down) 114 handleList[num] = event; 115 116 // Wait for these objects 117 DWORD idx = WaitForMultipleObjects(1 + num, handleList, 118 FALSE, INFINITE); 119 if ((idx >= WAIT_OBJECT_0) && (idx <= WAIT_OBJECT_0 + num)) { 120 idx -= WAIT_OBJECT_0; 121 if (idx < num) { 122 // A process exited (i.e., it wasn't that we were woken up 123 // just because the event went off) 124 (*cb)(dataList[idx]); 125 // Remove this process from the list (NOTE: requires that 126 // ordering does not change, i.e., that all additions are to 127 // the back of the process list) 128 EnterCriticalSection(&crit); 129 130 std::vector<ProcessInfo>::iterator iter = procInfo.begin(); 131 iter += idx; 132 procInfo.erase(iter); 133 134 LeaveCriticalSection(&crit); 135 } else { 136 // Notification from other thread 137 ResetEvent(event); 138 } 139 } else { 140 // Unexpected return value. For now, warn. 141 cerr << "Reaper::reaperThread(): unexpected return value " 142 << idx << " from WaitForMultipleObjects" << endl; 143 } 144 145 // Clean up these lists 146 delete[] handleList; 147 delete[] dataList; 148 } 149 150 // Time to shut down 151 active = false; 152 } 153 154 DWORD WINAPI 155 Reaper::reaperThreadEntry(LPVOID data) { 156 Reaper* reaper = (Reaper*) data; 157 reaper->reaperThread(); 158 return 0; 159 }