Make best effort to wait until all threads are stopped
| 186 | |
| 187 | // Make best effort to wait until all threads are stopped |
| 188 | static void WaitForAllThreadsToStop() |
| 189 | { |
| 190 | // Make a "best effort" in the face of threads that could do arbitrary |
| 191 | // things to make the "break all" not complete successfully. Threads |
| 192 | // can hang in system calls indefinitely, and can spawn new threads |
| 193 | // continuously that themselves do the same. Don't try to be perfect |
| 194 | // and guarantee that all threads have stopped, as that could mean |
| 195 | // waiting a long time in pathological cases or even forever in really |
| 196 | // pathological cases. Just make a best effort and if the break |
| 197 | // doesn't break everything, the user will know when they go to list |
| 198 | // all thread stacks and can try the break again. |
| 199 | |
| 200 | // Copy the thread numbers out. This is because we really don't want |
| 201 | // to hold the lock during the entire process as this could block |
| 202 | // threads from actually evaluating breakpoints. |
| 203 | std::vector<int> threadNumbers; |
| 204 | gMutex.lock(); |
| 205 | std::list<DebuggerContext *>::iterator iter = gList.begin(); |
| 206 | while (iter != gList.end()) { |
| 207 | DebuggerContext *stack = *iter++; |
| 208 | if (stack->mThreadNumber == g_debugThreadNumber) { |
| 209 | continue; |
| 210 | } |
| 211 | threadNumbers.push_back(stack->mThreadNumber); |
| 212 | } |
| 213 | gMutex.unlock(); |
| 214 | |
| 215 | // Now wait no longer than 2 seconds total for all threads to |
| 216 | // be stopped. If any thread times out, then stop immediately. |
| 217 | int size = threadNumbers.size(); |
| 218 | // Each time slice is 1/10 of a second. Yeah there's some slop here |
| 219 | // because no time is accounted for the time spent outside of sem |
| 220 | // waiting. If there were good portable time APIs easily available |
| 221 | // within hxcpp I'd use them ... |
| 222 | int timeSlicesLeft = 20; |
| 223 | HxSemaphore timeoutSem; |
| 224 | int i = 0; |
| 225 | while (i < size) { |
| 226 | gMutex.lock(); |
| 227 | DebuggerContext *stack = gMap[threadNumbers[i]]; |
| 228 | if (!stack) { |
| 229 | // The thread went away while we were working! |
| 230 | gMutex.unlock(); |
| 231 | i += 1; |
| 232 | continue; |
| 233 | } |
| 234 | if (stack->mWaiting) { |
| 235 | gMutex.unlock(); |
| 236 | i += 1; |
| 237 | continue; |
| 238 | } |
| 239 | gMutex.unlock(); |
| 240 | if (timeSlicesLeft == 0) { |
| 241 | // The 2 seconds have expired, give up |
| 242 | return; |
| 243 | } |
| 244 | // Sleep for 1/10 of a second on a semaphore that will never |
| 245 | // be Set. |
nothing calls this directly
no test coverage detected