You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
4.5 KiB
166 lines
4.5 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
#include <map>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include "threadUtils.h"
|
|
|
|
using std::map;
|
|
|
|
|
|
/**************************************************
|
|
* Global variables *
|
|
**************************************************/
|
|
static volatile int numOfThreads = 0;
|
|
static map<TidType, HANDLE> handles;
|
|
|
|
|
|
/**************************************************
|
|
* Global locks *
|
|
**************************************************/
|
|
static HANDLE printLock; // This mutex lock is used for synchronizing prints.
|
|
static HANDLE numThreadsLock; // This mutex lock is used for synchronizing access to numOfThreads.
|
|
|
|
|
|
/**************************************************
|
|
* Static functions declaration *
|
|
**************************************************/
|
|
static void GetLock(HANDLE * thelock);
|
|
static void ReleaseLock(HANDLE * thelock);
|
|
static void ErrorExitUnlocked(Results res);
|
|
|
|
|
|
|
|
|
|
static HANDLE cancellationPoint;
|
|
|
|
|
|
/**************************************************
|
|
* External functions implementation *
|
|
**************************************************/
|
|
unsigned int GetTid() {
|
|
return (unsigned int)GetCurrentThreadId();
|
|
}
|
|
|
|
void InitLocks() {
|
|
printLock = CreateMutex(NULL, FALSE, NULL);
|
|
numThreadsLock = CreateMutex(NULL, FALSE, NULL); // Create mutexes without initial ownership.
|
|
cancellationPoint = CreateEvent(NULL, TRUE, FALSE, NULL); // manual reset event
|
|
}
|
|
|
|
bool CreateNewThread(TidType* tid, void* func, void* info) {
|
|
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, info, 0, tid);
|
|
if (hThread == NULL) return false;
|
|
handles[*tid] = hThread;
|
|
return true;
|
|
}
|
|
|
|
void CancelThread(TidType tid) {
|
|
if (TerminateThread(handles[tid], 0) == 0) {
|
|
ErrorExit(RES_CANCEL_FAILED);
|
|
}
|
|
}
|
|
|
|
void WaitForThread(TidType tid) {
|
|
if (WaitForSingleObject(handles[tid], INFINITE) == WAIT_FAILED) {
|
|
ErrorExit(RES_JOIN_FAILED);
|
|
}
|
|
}
|
|
|
|
void TimeoutThreadFunc(void* info){
|
|
DoSleep(TIMEOUT);
|
|
|
|
// Should never get here, only if timeout occurred
|
|
Print("Got timeout, exiting test with an error");
|
|
ErrorExit(RES_EXIT_TIMEOUT);
|
|
}
|
|
|
|
void SetTimeout(){
|
|
TidType tid;
|
|
if (!CreateNewThread(&tid, (void *)TimeoutThreadFunc, NULL)) {
|
|
Print("Could not open a timeout thread");
|
|
ErrorExit(RES_CREATE_FAILED);
|
|
}
|
|
}
|
|
|
|
|
|
void ThreadExit() {
|
|
ExitThread(0);
|
|
}
|
|
|
|
void IncThreads() {
|
|
GetLock(&numThreadsLock);
|
|
++numOfThreads;
|
|
ReleaseLock(&numThreadsLock);
|
|
}
|
|
|
|
void DecThreads() {
|
|
GetLock(&numThreadsLock);
|
|
--numOfThreads;
|
|
ReleaseLock(&numThreadsLock);
|
|
}
|
|
|
|
int NumOfThreads() {
|
|
return numOfThreads;
|
|
}
|
|
|
|
void Print(const string& str) {
|
|
GetLock(&printLock);
|
|
fprintf(stderr, "APP: <%d> %s\n", GetTid(), str.c_str());
|
|
fflush(stderr);
|
|
ReleaseLock(&printLock);
|
|
}
|
|
|
|
void ErrorExit(Results res) {
|
|
GetLock(&printLock);
|
|
fprintf(stderr, "APP ERROR <%d>: %s\n", GetTid(), errorStrings[res].c_str());
|
|
fflush(stderr);
|
|
ReleaseLock(&printLock);
|
|
exit(res);
|
|
}
|
|
|
|
void ErrorExitUnlocked(Results res) {
|
|
fflush(stderr);
|
|
fprintf(stderr, "APP ERROR <%d>: %s\n", GetTid(), errorStrings[res].c_str());
|
|
fflush(stderr);
|
|
exit(res);
|
|
}
|
|
|
|
void DoSleep(unsigned int seconds) {
|
|
Sleep(seconds*1000);
|
|
}
|
|
|
|
void DoYield() {
|
|
Yield();
|
|
}
|
|
|
|
void EnterSafeCancellationPoint() {
|
|
WaitForSingleObject(cancellationPoint, INFINITE);
|
|
}
|
|
|
|
|
|
/**************************************************
|
|
* Static functions implementation *
|
|
**************************************************/
|
|
void GetLock(HANDLE * thelock) {
|
|
DWORD status = WaitForSingleObject(*thelock, INFINITE);
|
|
if (status == WAIT_OBJECT_0) return; // Success.
|
|
// Do not proceed if status is either WAIT_ABANDONED (thread that owned the mutex was terminated,
|
|
// current thread takes ownership, but we don't want to recover), or WAIT_FAILED (any other failure).
|
|
ErrorExitUnlocked(RES_LOCK_FAILED);
|
|
}
|
|
|
|
void ReleaseLock(HANDLE * thelock) {
|
|
if (ReleaseMutex(*thelock)) return; // Success.
|
|
ErrorExitUnlocked(RES_UNLOCK_FAILED);
|
|
}
|