1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
16 Implementation of functions related to threads.
24 #include "pal/corunix.hpp"
25 #include "pal/thread.hpp"
26 #include "pal/mutex.hpp"
27 #include "pal/seh.hpp"
29 #include "pal/dbgmsg.h"
37 #include <debugmacrosext.h>
40 // AIX requires explicit definition of the union semun (see semctl man page)
44 struct semid_ds * buf;
45 unsigned short * array;
49 using namespace CorUnix;
51 /* ------------------- Definitions ------------------------------*/
52 SET_DEFAULT_DEBUG_CHANNEL(THREAD);
54 /* This code is written to the blocking pipe of a thread that was created
55 in suspended state in order to resume it. */
56 CONST BYTE WAKEUPCODE=0x2A;
58 // #define USE_GLOBAL_LOCK_FOR_SUSPENSION // Uncomment this define to use the global suspension lock.
59 /* The global suspension lock can be used in place of each thread having its own
60 suspension mutex or spinlock. The downside is that it restricts us to only
61 performing one suspension or resumption in the PAL at a time. */
62 #ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
63 static LONG g_ssSuspensionLock = 0;
68 InternalSuspendNewThreadFromData
70 On platforms where we use pipes for starting threads suspended, this
71 function sets the blocking pipe for the thread and blocks until the
72 wakeup code is written to the pipe by ResumeThread.
76 CThreadSuspensionInfo::InternalSuspendNewThreadFromData(
80 PAL_ERROR palError = NO_ERROR;
82 AcquireSuspensionLock(pThread);
83 pThread->suspensionInfo.SetSelfSusp(TRUE);
84 ReleaseSuspensionLock(pThread);
87 if (pipe(pipe_descs) == -1)
89 ERROR("pipe() failed! error is %d (%s)\n", errno, strerror(errno));
90 return ERROR_NOT_ENOUGH_MEMORY;
93 // [0] is the read end of the pipe, and [1] is the write end.
94 pThread->suspensionInfo.SetBlockingPipe(pipe_descs[1]);
95 pThread->SetStartStatus(TRUE);
100 // Block until ResumeThread writes something to the pipe
101 while ((read_ret = read(pipe_descs[0], &resume_code, sizeof(resume_code))) != sizeof(resume_code))
103 if (read_ret != -1 || EINTR != errno)
105 // read might return 0 (with EAGAIN) if the other end of the pipe gets closed
106 palError = ERROR_INTERNAL_ERROR;
111 if (palError == NO_ERROR && resume_code != WAKEUPCODE)
113 // If we did read successfully but the byte didn't match WAKEUPCODE, we treat it as a failure.
114 palError = ERROR_INTERNAL_ERROR;
117 if (palError == NO_ERROR)
119 AcquireSuspensionLock(pThread);
120 pThread->suspensionInfo.SetSelfSusp(FALSE);
121 ReleaseSuspensionLock(pThread);
124 // Close the pipes regardless of whether we were successful.
125 close(pipe_descs[0]);
126 close(pipe_descs[1]);
145 CPalThread *pthrResumer;
146 DWORD dwSuspendCount = (DWORD)-1;
148 PERF_ENTRY(ResumeThread);
149 ENTRY("ResumeThread(hThread=%p)\n", hThread);
151 pthrResumer = InternalGetCurrentThread();
152 palError = InternalResumeThread(
158 if (NO_ERROR != palError)
160 pthrResumer->SetLastError(palError);
161 dwSuspendCount = (DWORD) -1;
165 _ASSERT_MSG(dwSuspendCount != static_cast<DWORD>(-1), "InternalResumeThread returned success but dwSuspendCount did not change.\n");
168 LOGEXIT("ResumeThread returns DWORD %u\n", dwSuspendCount);
169 PERF_EXIT(ResumeThread);
170 return dwSuspendCount;
177 InternalResumeThread converts the handle of the target thread to a
178 CPalThread, and passes both the resumer and target thread references
179 to InternalResumeThreadFromData. A reference to the suspend count from
180 the resumption attempt is passed back to the caller of this function.
183 CorUnix::InternalResumeThread(
184 CPalThread *pthrResumer,
185 HANDLE hTargetThread,
186 DWORD *pdwSuspendCount
189 PAL_ERROR palError = NO_ERROR;
190 CPalThread *pthrTarget = NULL;
191 IPalObject *pobjThread = NULL;
193 palError = InternalGetThreadDataFromHandle(
196 0, // THREAD_SUSPEND_RESUME
201 if (NO_ERROR == palError)
203 palError = pthrResumer->suspensionInfo.InternalResumeThreadFromData(
210 if (NULL != pobjThread)
212 pobjThread->ReleaseReference(pthrResumer);
220 InternalResumeThreadFromData
222 InternalResumeThreadFromData resumes the target thread. First, the suspension
223 mutexes of the threads are acquired. Next, there's a check to ensure that the
224 target thread was actually suspended. Finally, the resume attempt is made
225 and the suspension mutexes are released. The suspend count of the
226 target thread is passed back to the caller of this function.
228 Note that ReleaseSuspensionLock(s) is called before hitting ASSERTs in error
229 paths. Currently, this seems unnecessary since asserting within
230 InternalResumeThreadFromData will not cause cleanup to occur. However,
231 this may change since it would be preferable to perform cleanup. Thus, calls
232 to release suspension locks remain in the error paths.
235 CThreadSuspensionInfo::InternalResumeThreadFromData(
236 CPalThread *pthrResumer,
237 CPalThread *pthrTarget,
238 DWORD *pdwSuspendCount
241 PAL_ERROR palError = NO_ERROR;
243 int nWrittenBytes = -1;
245 if (SignalHandlerThread == pthrTarget->GetThreadType())
247 ASSERT("Attempting to resume the signal handling thread, which can never be suspended.\n");
248 palError = ERROR_INVALID_HANDLE;
249 goto InternalResumeThreadFromDataExit;
252 // Acquire suspension mutex
253 AcquireSuspensionLocks(pthrResumer, pthrTarget);
255 // Check target thread's state to ensure it hasn't died.
256 // Setting a thread's state to TS_DONE is protected by the
257 // target's suspension mutex.
258 if (pthrTarget->synchronizationInfo.GetThreadState() == TS_DONE)
260 palError = ERROR_INVALID_HANDLE;
261 ReleaseSuspensionLocks(pthrResumer, pthrTarget);
262 goto InternalResumeThreadFromDataExit;
265 // If this is a dummy thread, then it represents a process that was created with CREATE_SUSPENDED
266 // and it should have a blocking pipe set. If GetBlockingPipe returns -1 for a dummy thread, then
267 // something is wrong - either CREATE_SUSPENDED wasn't used or the process was already resumed.
268 if (pthrTarget->IsDummy() && -1 == pthrTarget->suspensionInfo.GetBlockingPipe())
270 palError = ERROR_INVALID_HANDLE;
271 ERROR("Tried to wake up dummy thread without a blocking pipe.\n");
272 ReleaseSuspensionLocks(pthrResumer, pthrTarget);
273 goto InternalResumeThreadFromDataExit;
276 // If there is a blocking pipe on this thread, resume it by writing the wake up code to that pipe.
277 if (-1 != pthrTarget->suspensionInfo.GetBlockingPipe())
279 // If write() is interrupted by a signal before writing data,
280 // it returns -1 and sets errno to EINTR. In this case, we
281 // attempt the write() again.
283 nWrittenBytes = write(pthrTarget->suspensionInfo.GetBlockingPipe(), &WAKEUPCODE, sizeof(WAKEUPCODE));
285 // The size of WAKEUPCODE is 1 byte. If write returns 0, we'll treat it as an error.
286 if (sizeof(WAKEUPCODE) != nWrittenBytes)
288 // If we are here during process creation, this is most likely caused by the target
289 // process dying before reaching this point and thus breaking the pipe.
290 if (nWrittenBytes == -1 && EPIPE == errno)
292 palError = ERROR_INVALID_HANDLE;
293 ReleaseSuspensionLocks(pthrResumer, pthrTarget);
294 ERROR("Write failed with EPIPE\n");
295 goto InternalResumeThreadFromDataExit;
297 else if (nWrittenBytes == 0 || (nWrittenBytes == -1 && EINTR == errno))
299 TRACE("write() failed with EINTR; re-attempting write\n");
304 // Some other error occurred; need to release suspension mutexes before leaving ResumeThread.
305 palError = ERROR_INTERNAL_ERROR;
306 ReleaseSuspensionLocks(pthrResumer, pthrTarget);
307 ASSERT("Write() failed; error is %d (%s)\n", errno, strerror(errno));
308 goto InternalResumeThreadFromDataExit;
312 // Reset blocking pipe to -1 since we're done using it.
313 pthrTarget->suspensionInfo.SetBlockingPipe(-1);
315 ReleaseSuspensionLocks(pthrResumer, pthrTarget);
316 goto InternalResumeThreadFromDataExit;
320 *pdwSuspendCount = 0;
321 palError = ERROR_BAD_COMMAND;
324 InternalResumeThreadFromDataExit:
326 if (NO_ERROR == palError)
328 *pdwSuspendCount = 1;
336 TryAcquireSuspensionLock
338 TryAcquireSuspensionLock is a utility function that tries to acquire a thread's
339 suspension mutex or spinlock. If it succeeds, the function returns TRUE.
340 Otherwise, it returns FALSE. This function is used in AcquireSuspensionLocks.
341 Note that the global lock cannot be acquired in this function since it makes
342 no sense to do so. A thread holding the global lock is the only thread that
343 can perform suspend or resume operations so it doesn't need to acquire
347 CThreadSuspensionInfo::TryAcquireSuspensionLock(
348 CPalThread* pthrTarget
352 #if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
354 iPthreadRet = SPINLOCKTryAcquire(pthrTarget->suspensionInfo.GetSuspensionSpinlock());
356 #else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
358 iPthreadRet = pthread_mutex_trylock(pthrTarget->suspensionInfo.GetSuspensionMutex());
359 _ASSERT_MSG(iPthreadRet == 0 || iPthreadRet == EBUSY, "pthread_mutex_trylock returned %d\n", iPthreadRet);
361 #endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
363 // If iPthreadRet is 0, lock acquisition was successful. Otherwise, it failed.
364 return (iPthreadRet == 0);
369 AcquireSuspensionLock
371 AcquireSuspensionLock acquires a thread's suspension mutex or spinlock.
372 If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, it will acquire the global lock.
373 A thread in this function blocks until it acquires
374 its lock, unlike in TryAcquireSuspensionLock.
377 CThreadSuspensionInfo::AcquireSuspensionLock(
378 CPalThread* pthrCurrent
381 #ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
383 SPINLOCKAcquire(&g_ssSuspensionLock, 0);
385 #else // USE_GLOBAL_LOCK_FOR_SUSPENSION
387 #if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
389 SPINLOCKAcquire(&pthrCurrent->suspensionInfo.m_nSpinlock, 0);
391 #else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
393 INDEBUG(int iPthreadError = )
394 pthread_mutex_lock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex);
395 _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_lock returned %d\n", iPthreadError);
397 #endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
399 #endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
404 ReleaseSuspensionLock
406 ReleaseSuspensionLock is a function that releases a thread's suspension mutex
407 or spinlock. If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined,
408 it will release the global lock.
411 CThreadSuspensionInfo::ReleaseSuspensionLock(
412 CPalThread* pthrCurrent
415 #ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
417 SPINLOCKRelease(&g_ssSuspensionLock);
419 #else // USE_GLOBAL_LOCK_FOR_SUSPENSION
421 #if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
423 SPINLOCKRelease(&pthrCurrent->suspensionInfo.m_nSpinlock);
425 #else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
427 INDEBUG(int iPthreadError = )
428 pthread_mutex_unlock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex);
429 _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_unlock returned %d\n", iPthreadError);
431 #endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
433 #endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
438 AcquireSuspensionLocks
440 AcquireSuspensionLocks is used to acquire the suspension locks
441 of a suspender (or resumer) and target thread. The thread will
442 perform a blocking call to acquire its own suspension lock
443 and will then try to acquire the target thread's lock without blocking.
444 If it fails to acquire the target's lock, it releases its own lock
445 and the thread will try to acquire both locks again. The key
446 is that both locks must be acquired together.
448 Originally, only blocking calls were used to acquire the suspender
449 and the target lock. However, this was problematic since a thread
450 could acquire its own lock and then block on acquiring the target
451 lock. In the meantime, the target could have already acquired its
452 own lock and be attempting to suspend the suspender thread. This
453 clearly causes deadlock. A second approach used locking hierarchies,
454 where locks were acquired use thread id ordering. This was better but
455 suffered from the scenario where thread A acquires thread B's
456 suspension mutex first. In the meantime, thread C acquires thread A's
457 suspension mutex and its own. Thus, thread A is suspended while
458 holding thread B's mutex. This is problematic if thread C now wants
459 to suspend thread B. The issue here is that a thread can be
460 suspended while holding someone else's mutex but not holding its own.
461 In the end, the correct approach is to always acquire your suspension
462 mutex first. This prevents you from being suspended while holding the
463 target's mutex. Then, attempt to acquire the target's mutex. If the mutex
464 cannot be acquired, release your own and try again. This all or nothing
465 approach is the safest and avoids nasty race conditions.
467 If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, the calling thread
468 will acquire the global lock when possible.
471 CThreadSuspensionInfo::AcquireSuspensionLocks(
472 CPalThread *pthrSuspender,
473 CPalThread *pthrTarget
476 BOOL fReacquire = FALSE;
478 #ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
479 AcquireSuspensionLock(pthrSuspender);
480 #else // USE_GLOBAL_LOCK_FOR_SUSPENSION
484 AcquireSuspensionLock(pthrSuspender);
485 if (!TryAcquireSuspensionLock(pthrTarget))
487 // pthread_mutex_trylock returned EBUSY so release the first lock and try again.
488 ReleaseSuspensionLock(pthrSuspender);
492 } while (fReacquire);
493 #endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
495 // Whenever the native implementation for the wait subsystem's thread
496 // blocking requires a lock as protection (as pthread conditions do with
497 // the associated mutex), we need to grab that lock to prevent the target
498 // thread from being suspended while holding the lock.
499 // Failing to do so can lead to a multiple threads deadlocking such as the
500 // one described in VSW 363793.
501 // In general, in similar scenarios, we need to grab the protecting lock
502 // every time suspension safety/unsafety is unbalanced on the two sides
503 // using the same condition (or any other native blocking support which
504 // needs an associated native lock), i.e. when either the signaling
505 // thread(s) is(are) signaling from an unsafe area and the waiting
506 // thread(s) is(are) waiting from a safe one, or vice versa (the scenario
507 // described in VSW 363793 is a good example of the first type of
508 // unbalanced suspension safety/unsafety).
509 // Instead, whenever signaling and waiting sides are both marked safe or
510 // unsafe, the deadlock cannot take place since either the suspending
511 // thread will suspend them anyway (regardless of the native lock), or it
512 // won't suspend any of them, since they are both marked unsafe.
513 // Such a balanced scenario applies, for instance, to critical sections
514 // where depending on whether the target CS is internal or not, both the
515 // signaling and the waiting side will access the mutex/condition from
516 // respectively an unsafe or safe region.
518 pthrTarget->AcquireNativeWaitLock();
523 ReleaseSuspensionLocks
525 ReleaseSuspensionLocks releases both thread's suspension mutexes.
526 Note that the locks are released in the opposite order they're acquired.
527 This prevents a suspending or resuming thread from being suspended
528 while holding the target's lock.
529 If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, it simply releases the global lock.
532 CThreadSuspensionInfo::ReleaseSuspensionLocks(
533 CPalThread *pthrSuspender,
534 CPalThread *pthrTarget
537 // See comment in AcquireSuspensionLocks
538 pthrTarget->ReleaseNativeWaitLock();
540 #ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
541 ReleaseSuspensionLock(pthrSuspender);
542 #else // USE_GLOBAL_LOCK_FOR_SUSPENSION
543 ReleaseSuspensionLock(pthrTarget);
544 ReleaseSuspensionLock(pthrSuspender);
545 #endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
550 PostOnSuspendSemaphore
552 PostOnSuspendSemaphore is a utility function for a thread
553 to post on its POSIX or SysV suspension semaphore.
556 CThreadSuspensionInfo::PostOnSuspendSemaphore()
558 #if USE_POSIX_SEMAPHORES
559 if (sem_post(&m_semSusp) == -1)
561 ASSERT("sem_post returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
563 #elif USE_SYSV_SEMAPHORES
564 if (semop(m_nSemsuspid, &m_sbSempost, 1) == -1)
566 ASSERT("semop - post returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
568 #elif USE_PTHREAD_CONDVARS
571 // The suspending thread may not have entered the wait yet, in which case the cond var
572 // signal below will be a no-op. To prevent the race condition we set m_fSuspended to
573 // TRUE first (which the suspender will take as an indication that no wait is required).
574 // But the setting of the flag and the signal must appear atomic to the suspender (as
575 // reading the flag and potentially waiting must appear to us) to avoid the race
576 // condition where the suspender reads the flag as FALSE, we set it and signal and the
577 // suspender then waits.
579 // Acquire the suspend mutex. Once we enter the critical section the suspender has
580 // either gotten there before us (and is waiting for our signal) or is yet to even
581 // check the flag (so we can set it here to stop them attempting a wait).
582 status = pthread_mutex_lock(&m_mutexSusp);
585 ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status));
590 status = pthread_cond_signal(&m_condSusp);
593 ASSERT("pthread_cond_signal returned %d (%s)\n", status, strerror(status));
596 status = pthread_mutex_unlock(&m_mutexSusp);
599 ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status));
601 #endif // USE_POSIX_SEMAPHORES
606 WaitOnSuspendSemaphore
608 WaitOnSuspendSemaphore is a utility function for a thread
609 to wait on its POSIX or SysV suspension semaphore.
612 CThreadSuspensionInfo::WaitOnSuspendSemaphore()
614 #if USE_POSIX_SEMAPHORES
615 while (sem_wait(&m_semSusp) == -1)
617 ASSERT("sem_wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
619 #elif USE_SYSV_SEMAPHORES
620 while (semop(m_nSemsuspid, &m_sbSemwait, 1) == -1)
622 ASSERT("semop wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
624 #elif USE_PTHREAD_CONDVARS
627 // By the time we wait the target thread may have already signalled its suspension (in
628 // which case m_fSuspended will be TRUE and we shouldn't wait on the cond var). But we
629 // must check the flag and potentially wait atomically to avoid the race where we read
630 // the flag and the target thread sets it and signals before we have a chance to wait.
632 status = pthread_mutex_lock(&m_mutexSusp);
635 ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status));
638 // If the target has already acknowledged the suspend we shouldn't wait.
639 while (!m_fSuspended)
641 // We got here before the target could signal. Wait on them (which atomically releases
642 // the mutex during the wait).
643 status = pthread_cond_wait(&m_condSusp, &m_mutexSusp);
646 ASSERT("pthread_cond_wait returned %d (%s)\n", status, strerror(status));
650 status = pthread_mutex_unlock(&m_mutexSusp);
653 ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status));
655 #endif // USE_POSIX_SEMAPHORES
660 PostOnResumeSemaphore
662 PostOnResumeSemaphore is a utility function for a thread
663 to post on its POSIX or SysV resume semaphore.
666 CThreadSuspensionInfo::PostOnResumeSemaphore()
668 #if USE_POSIX_SEMAPHORES
669 if (sem_post(&m_semResume) == -1)
671 ASSERT("sem_post returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
673 #elif USE_SYSV_SEMAPHORES
674 if (semop(m_nSemrespid, &m_sbSempost, 1) == -1)
676 ASSERT("semop - post returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
678 #elif USE_PTHREAD_CONDVARS
681 // The resuming thread may not have entered the wait yet, in which case the cond var
682 // signal below will be a no-op. To prevent the race condition we set m_fResumed to
683 // TRUE first (which the resumer will take as an indication that no wait is required).
684 // But the setting of the flag and the signal must appear atomic to the resumer (as
685 // reading the flag and potentially waiting must appear to us) to avoid the race
686 // condition where the resumer reads the flag as FALSE, we set it and signal and the
687 // resumer then waits.
689 // Acquire the resume mutex. Once we enter the critical section the resumer has
690 // either gotten there before us (and is waiting for our signal) or is yet to even
691 // check the flag (so we can set it here to stop them attempting a wait).
692 status = pthread_mutex_lock(&m_mutexResume);
695 ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status));
700 status = pthread_cond_signal(&m_condResume);
703 ASSERT("pthread_cond_signal returned %d (%s)\n", status, strerror(status));
706 status = pthread_mutex_unlock(&m_mutexResume);
709 ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status));
711 #endif // USE_POSIX_SEMAPHORES
716 WaitOnResumeSemaphore
718 WaitOnResumeSemaphore is a utility function for a thread
719 to wait on its POSIX or SysV resume semaphore.
722 CThreadSuspensionInfo::WaitOnResumeSemaphore()
724 #if USE_POSIX_SEMAPHORES
725 while (sem_wait(&m_semResume) == -1)
727 ASSERT("sem_wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
729 #elif USE_SYSV_SEMAPHORES
730 while (semop(m_nSemrespid, &m_sbSemwait, 1) == -1)
732 ASSERT("semop wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
734 #elif USE_PTHREAD_CONDVARS
737 // By the time we wait the target thread may have already signalled its resumption (in
738 // which case m_fResumed will be TRUE and we shouldn't wait on the cond var). But we
739 // must check the flag and potentially wait atomically to avoid the race where we read
740 // the flag and the target thread sets it and signals before we have a chance to wait.
742 status = pthread_mutex_lock(&m_mutexResume);
745 ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status));
748 // If the target has already acknowledged the resume we shouldn't wait.
751 // We got here before the target could signal. Wait on them (which atomically releases
752 // the mutex during the wait).
753 status = pthread_cond_wait(&m_condResume, &m_mutexResume);
756 ASSERT("pthread_cond_wait returned %d (%s)\n", status, strerror(status));
760 status = pthread_mutex_unlock(&m_mutexResume);
763 ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status));
765 #endif // USE_POSIX_SEMAPHORES
770 InitializeSuspensionLock
772 InitializeSuspensionLock initializes a thread's suspension spinlock
773 or suspension mutex. It is called from the CThreadSuspensionInfo
777 CThreadSuspensionInfo::InitializeSuspensionLock()
779 #if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
780 SPINLOCKInit(&m_nSpinlock);
782 int iError = pthread_mutex_init(&m_ptmSuspmutex, NULL);
785 ASSERT("pthread_mutex_init(&suspmutex) returned %d\n", iError);
788 m_fSuspmutexInitialized = TRUE;
789 #endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
796 InitializePreCreate initializes the semaphores and signal masks used
797 for thread suspension. At the end, it sets the calling thread's
798 signal mask to the default signal mask.
801 CThreadSuspensionInfo::InitializePreCreate()
803 PAL_ERROR palError = ERROR_INTERNAL_ERROR;
805 #if SEM_INIT_MODIFIES_ERRNO
807 #endif // SEM_INIT_MODIFIES_ERRNO
809 #if USE_POSIX_SEMAPHORES
811 #if SEM_INIT_MODIFIES_ERRNO
812 nStoredErrno = errno;
813 #endif // SEM_INIT_MODIFIES_ERRNO
815 // initialize suspension semaphore
816 iError = sem_init(&m_semSusp, 0, 0);
818 #if SEM_INIT_MODIFIES_ERRNO
821 // Restore errno if sem_init succeeded.
822 errno = nStoredErrno;
824 #endif // SEM_INIT_MODIFIES_ERRNO
828 ASSERT("sem_init(&suspsem) returned %d\n", iError);
829 goto InitializePreCreateExit;
832 #if SEM_INIT_MODIFIES_ERRNO
833 nStoredErrno = errno;
834 #endif // SEM_INIT_MODIFIES_ERRNO
836 // initialize resume semaphore
837 iError = sem_init(&m_semResume, 0, 0);
839 #if SEM_INIT_MODIFIES_ERRNO
842 // Restore errno if sem_init succeeded.
843 errno = nStoredErrno;
845 #endif // SEM_INIT_MODIFIES_ERRNO
849 ASSERT("sem_init(&suspsem) returned %d\n", iError);
850 sem_destroy(&m_semSusp);
851 goto InitializePreCreateExit;
854 m_fSemaphoresInitialized = TRUE;
856 #elif USE_SYSV_SEMAPHORES
857 // preparing to initialize the SysV semaphores.
858 union semun semunData;
859 m_nSemsuspid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
860 if (m_nSemsuspid == -1)
862 ASSERT("semget for suspension sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
863 goto InitializePreCreateExit;
866 m_nSemrespid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
867 if (m_nSemrespid == -1)
869 ASSERT("semget for resumption sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
870 goto InitializePreCreateExit;
873 if (m_nSemsuspid == m_nSemrespid)
875 ASSERT("Suspension and Resumption Semaphores have the same id\n");
876 goto InitializePreCreateExit;
880 iError = semctl(m_nSemsuspid, 0, SETVAL, semunData);
883 ASSERT("semctl for suspension sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
884 goto InitializePreCreateExit;
888 iError = semctl(m_nSemrespid, 0, SETVAL, semunData);
891 ASSERT("semctl for resumption sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
892 goto InitializePreCreateExit;
895 // initialize suspend semaphore
896 m_sbSemwait.sem_num = 0;
897 m_sbSemwait.sem_op = -1;
898 m_sbSemwait.sem_flg = 0;
900 // initialize resume semaphore
901 m_sbSempost.sem_num = 0;
902 m_sbSempost.sem_op = 1;
903 m_sbSempost.sem_flg = 0;
904 #elif USE_PTHREAD_CONDVARS
905 iError = pthread_cond_init(&m_condSusp, NULL);
908 ASSERT("pthread_cond_init for suspension returned %d (%s)\n", iError, strerror(iError));
909 goto InitializePreCreateExit;
912 iError = pthread_mutex_init(&m_mutexSusp, NULL);
915 ASSERT("pthread_mutex_init for suspension returned %d (%s)\n", iError, strerror(iError));
916 goto InitializePreCreateExit;
919 iError = pthread_cond_init(&m_condResume, NULL);
922 ASSERT("pthread_cond_init for resume returned %d (%s)\n", iError, strerror(iError));
923 goto InitializePreCreateExit;
926 iError = pthread_mutex_init(&m_mutexResume, NULL);
929 ASSERT("pthread_mutex_init for resume returned %d (%s)\n", iError, strerror(iError));
930 goto InitializePreCreateExit;
933 m_fSemaphoresInitialized = TRUE;
934 #endif // USE_POSIX_SEMAPHORES
936 // Initialization was successful.
939 InitializePreCreateExit:
941 if (NO_ERROR == palError && 0 != iError)
948 palError = ERROR_OUTOFMEMORY;
953 ASSERT("A pthrSuspender init call returned %d (%s)\n", iError, strerror(iError));
954 palError = ERROR_INTERNAL_ERROR;
962 CThreadSuspensionInfo::~CThreadSuspensionInfo()
964 #if !DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
965 if (m_fSuspmutexInitialized)
967 INDEBUG(int iError = )
968 pthread_mutex_destroy(&m_ptmSuspmutex);
969 _ASSERT_MSG(0 == iError, "pthread_mutex_destroy returned %d (%s)\n", iError, strerror(iError));
973 #if USE_POSIX_SEMAPHORES
974 if (m_fSemaphoresInitialized)
978 iError = sem_destroy(&m_semSusp);
979 _ASSERT_MSG(0 == iError, "sem_destroy failed and set errno to %d (%s)\n", errno, strerror(errno));
981 iError = sem_destroy(&m_semResume);
982 _ASSERT_MSG(0 == iError, "sem_destroy failed and set errno to %d (%s)\n", errno, strerror(errno));
984 #elif USE_SYSV_SEMAPHORES
985 DestroySemaphoreIds();
986 #elif USE_PTHREAD_CONDVARS
987 if (m_fSemaphoresInitialized)
991 iError = pthread_cond_destroy(&m_condSusp);
992 _ASSERT_MSG(0 == iError, "pthread_cond_destroy failed with %d (%s)\n", iError, strerror(iError));
994 iError = pthread_mutex_destroy(&m_mutexSusp);
995 _ASSERT_MSG(0 == iError, "pthread_mutex_destroy failed with %d (%s)\n", iError, strerror(iError));
997 iError = pthread_cond_destroy(&m_condResume);
998 _ASSERT_MSG(0 == iError, "pthread_cond_destroy failed with %d (%s)\n", iError, strerror(iError));
1000 iError = pthread_mutex_destroy(&m_mutexResume);
1001 _ASSERT_MSG(0 == iError, "pthread_mutex_destroy failed with %d (%s)\n", iError, strerror(iError));
1003 #endif // USE_POSIX_SEMAPHORES
1006 #if USE_SYSV_SEMAPHORES
1011 DestroySemaphoreIds is called from the CThreadSuspensionInfo destructor and
1012 from PROCCleanupThreadSemIds. If a thread exits before shutdown or is suspended
1013 during shutdown, its destructor will be invoked and the semaphore ids destroyed.
1014 In assert or exceptions situations that are suspension unsafe,
1015 PROCCleanupThreadSemIds is called, which uses DestroySemaphoreIds.
1018 CThreadSuspensionInfo::DestroySemaphoreIds()
1020 union semun semunData;
1021 if (m_nSemsuspid != 0)
1024 if (0 != semctl(m_nSemsuspid, 0, IPC_RMID, semunData))
1026 ERROR("semctl(Semsuspid) failed and set errno to %d (%s)\n", errno, strerror(errno));
1033 if (this->m_nSemrespid)
1036 if (0 != semctl(m_nSemrespid, 0, IPC_RMID, semunData))
1038 ERROR("semctl(Semrespid) failed and set errno to %d (%s)\n", errno, strerror(errno));
1046 #endif // USE_SYSV_SEMAPHORES