/* ===================================================================== * Wait for the turn of the thread denoted by 'tid' to do its checking * ===================================================================== */ void WaitForThisThreadToBeActive(THREADID tid) { // Waits for the turn of this thread while (VecThreadIds[ActiveThreadIndex] != tid) { PIN_MutexUnlock(&MtxActiveThread); YIELD(); PIN_MutexLock(&MtxActiveThread); } // At this point it's the turn of the current thread to do the checking // the previous thread release the mutex MtxActiveThread. // We still need to wait (for at most 10 seconds) for the previous thread // to stop at the debugger time_t startWaitingTime = time(NULL); if (ActiveThreadIndex > 0) { THREADID prevTid = VecThreadIds[ActiveThreadIndex - 1]; while (!PIN_IsThreadStoppedInDebugger(prevTid)) { ASSERT((time(NULL) - startWaitingTime) < 10, "Timeout waiting for thread " + hexstr(prevTid) + " to stop in debugger"); YIELD(); } } }
static void DoTestMutexTryStress(THREAD_INFO *info, UINT32 *done) { // Try to acquire / release PIN_MUTEX as fast as possible, using "try". if (PIN_MutexTryLock(&Mutex)) PIN_MutexUnlock(&Mutex); CheckIfDone(info, done); }
static void DoTestMutexStress(THREAD_INFO *info, UINT32 *done) { // This test just tries to acquire and release PIN_MUTEX as fast as possible // to see if we can provoke a deadlock due to missing a wakeup. PIN_MutexLock(&Mutex); PIN_MutexUnlock(&Mutex); CheckIfDone(info, done); }
static void DoTestSemaphore(THREAD_INFO *info, UINT32 *done) { // This test assumes exactly two threads. The two threads take turns pinging // each other's semaphore. We make sure that a thread does not wake up from // the semaphore unless it is set. We also check for deadlocks due to missing // wakeups. if (info->_workerId == 0) { PIN_SemaphoreWait(&Sem1); if (!PIN_SemaphoreIsSet(&Sem1)) { std::cout << "SemaphoreWait returned, but semaphore is not set" << std::endl; PIN_ExitProcess(1); } PIN_MutexLock(&Mutex); PIN_SemaphoreClear(&Sem1); PIN_SemaphoreSet(&Sem2); PIN_MutexUnlock(&Mutex); } else { PIN_SemaphoreWait(&Sem2); if (!PIN_SemaphoreIsSet(&Sem2)) { std::cout << "SemaphoreWait returned, but semaphore is not set" << std::endl; PIN_ExitProcess(1); } PIN_MutexLock(&Mutex); PIN_SemaphoreClear(&Sem2); PIN_SemaphoreSet(&Sem1); PIN_MutexUnlock(&Mutex); } if (CheckIfDone(info, done)) { PIN_SemaphoreSet(&Sem1); PIN_SemaphoreSet(&Sem2); } }
/* * GetReadId * Returns the unique read id */ long unsigned int GetReadId() { long unsigned int ret; PIN_MutexLock(&readid_lock); ret = readid; readid++; PIN_MutexUnlock(&readid_lock); return ret; }
/* ===================================================================== * Called on DoBreakpoint() for each thread. * Waits for all the threads to reach this point, filling the vector of * the created thread IDs, and then release all the threads. * ===================================================================== */ static void WaitForAllThreadsToStart(THREADID tid) { PIN_MutexLock(&MtxVecThreadIds); VecThreadIds.push_back(tid); if (VecThreadIds.size() >= KnobThreads.Value()) { PrintAllThreadIDs(); AllThreadsWereStarted = true; PIN_SemaphoreSet(&SemAllThreadStarted); } PIN_MutexUnlock(&MtxVecThreadIds); PIN_SemaphoreWait(&SemAllThreadStarted); }
/* ===================================================================== * Called on each thread when it calls GlobalFunction() * ===================================================================== */ static void DoBreakpoint(THREADID tid, CONTEXT *context) { // If all thread were started then this is the second time we're entering // this function for the thread 'tid'. // We enter this function twice for the same thread because we hit the same // instrumentation we the debugger was returned from the break-point that // we mock to the same address. In this case we need to return and don't // repeat the test (unless we'll end up with an infinite test). if (AllThreadsWereStarted) return; WaitForAllThreadsToStart(tid); // All threads are synchronized to this point PIN_MutexLock(&MtxActiveThread); WaitForThisThreadToBeActive(tid); Out << "Performing check on thread ID " << tid << std::endl; for (unsigned i = 0; i < KnobThreads.Value(); i++) { THREADID otherTid = VecThreadIds[i]; if (i < ActiveThreadIndex) { // All threads that were already active should be stopped in the debugger ASSERT(PIN_IsThreadStoppedInDebugger(otherTid), "Thread " + decstr(otherTid) + " should be stopped"); } else { // All threads that weren't already active should be running ASSERT(!PIN_IsThreadStoppedInDebugger(otherTid), "Thread " + decstr(otherTid) + " shouldn't be stopped"); } } ActiveThreadIndex++; PIN_MutexUnlock(&MtxActiveThread); // Stop this thread in the debugger // Note that because we add the instrumentation at IPOINT_AFTER, the program counter // at 'context' will not lead us to run this instrumentation function again PIN_ApplicationBreakpoint(context, tid, FALSE, "Stopping in Worker Thread " + decstr(tid) + "\n"); }
static void DoTestMutexIntegrity(THREADID tid, THREAD_INFO *info, UINT32 *done) { // This test checks to see if two threads can be in the PIN_MUTEX mutex // simultaneously. PIN_MutexLock(&Mutex); THREADID owner = HasLock; HasLock = tid; if (owner != INVALID_THREADID) { std::cout << "Two theads in mutex simultaneously: " << std::dec << tid << " and " << owner << std::endl; PIN_ExitProcess(1); } ATOMIC::OPS::Delay(DELAY_COUNT); HasLock = INVALID_THREADID; PIN_MutexUnlock(&Mutex); CheckIfDone(info, done); }