1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
|
/**
*
* magma_winthread.cpp
*
* This file handles the mapping from pthreads calls to windows threads.
* MAGMA is a software package provided by Univ. of Tennessee,
* Univ. of California Berkeley and Univ. of Colorado Denver
*
* @version 2.3.1
* @author Piotr Luszczek
* @date January 2025
*
* This file is originally from PLASMA project, where plasma has been
* replaced by MAGMA.
*
**/
#if defined( _WIN32 ) || defined( _WIN64 )
#include "magma_winthread.h"
#include <limits.h>
/** this is needed to get a declaration for _beginthreadex() */
#include <process.h>
#include <stdio.h>
CRITICAL_SECTION magma_winthread_static_initializer_check_lock;
static int magma_winthread_initialized = 0;
extern "C"
MAGMA_DLLPORT unsigned int MAGMA_CDECL pthread_self_id(void)
{
return GetCurrentThreadId();
}
extern "C"
MAGMA_DLLPORT pthread_t MAGMA_CDECL pthread_self(void)
{
pthread_t pt;
pt.hThread = GetCurrentThread();
pt.uThId = GetCurrentThreadId();
return pt;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_equal(pthread_t thread1, pthread_t thread2)
{
if (thread1.uThId == thread2.uThId) // && thread1.hThread == thread2.hThread)
return 1;
return 0;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t * attr)
{
*mutex =
CreateMutex( NULL, /** no security atributes */
FALSE, /** not owned (initialy) by the creating thread */
NULL /** no name provided: cannot be shared between processes */
);
return 0;
}
static int pthread_mutex_check_for_static_initialization( pthread_mutex_t *mutex ) {
int retval = 0;
/* This should be called once to initialize some structures */
if ( magma_winthread_initialized == 0 ) {
magma_winthread_initialized = 1;
InitializeCriticalSection( &magma_winthread_static_initializer_check_lock );
}
EnterCriticalSection( &magma_winthread_static_initializer_check_lock );
if ( *mutex == PTHREAD_MUTEX_INITIALIZER )
retval = pthread_mutex_init( mutex, NULL );
LeaveCriticalSection( &magma_winthread_static_initializer_check_lock );
return retval;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_mutex_lock(pthread_mutex_t *mutex)
{
DWORD rv;
if ( *mutex == PTHREAD_MUTEX_INITIALIZER ) pthread_mutex_check_for_static_initialization( mutex );
rv = WaitForSingleObject( *mutex, INFINITE );
switch (rv) {
case WAIT_OBJECT_0: /** the wait was succesful */
return 0;
case WAIT_FAILED: /** the wait failed */
return -1;
case WAIT_ABANDONED: /** thread killed during the wait */
return -1;
case WAIT_TIMEOUT: /** impossible because of INFINITE */
return -1;
default:
return -1;
}
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_mutex_trylock(pthread_mutex_t *mutex)
{
DWORD rv;
if ( *mutex == PTHREAD_MUTEX_INITIALIZER ) pthread_mutex_check_for_static_initialization( mutex );
rv = WaitForSingleObject( *mutex, 0 );
switch (rv) {
case WAIT_OBJECT_0: /** the wait was succesful */
return 0;
case WAIT_FAILED: /** the wait failed */
return -1;
case WAIT_ABANDONED: /** thread killed during the wait */
return -1;
case WAIT_TIMEOUT: /** impossible because of INFINITE */
return -1;
default:
return -1;
}
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_mutex_unlock(pthread_mutex_t *mutex)
{
if (! ReleaseMutex( *mutex ))
return -1;
return 0;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_mutex_destroy(pthread_mutex_t *mutex)
{
CloseHandle( *mutex );
return 0;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_attr_init(pthread_attr_t *attr)
{
*attr = 1;
return 0;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_attr_destroy(pthread_attr_t *attr)
{
*attr = 0;
return 0;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_attr_setscope(pthread_attr_t *attr, int scope)
{
if (*attr != 1)
return -1;
if (scope != PTHREAD_SCOPE_SYSTEM)
return -1;
return 0;
}
void *(*MAGMA_realThStart)(void *);
/*
This function is only called to have a proxy that is compatible with WINAPI.
*/
unsigned WINAPI MAGMA_winThStart(void *arg) {
MAGMA_realThStart( arg );
return 0;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start) (void *), void *arg)
{
/* this assumes that the threads call the same function, always; it also assumes there
is no race condition while assigning a pointer and using it from within threads
(this assumption is fulfilled by creating the new thread in suspended state) */
MAGMA_realThStart = start;
thread->hThread = (HANDLE)_beginthreadex(
NULL, /* default security */
0, /* stack size: use the size of calling thread */
MAGMA_winThStart,
arg,
CREATE_SUSPENDED,
/*0,*/ /* the thread will run immedietally (rather than get suspended) */
&thread->uThId );
/* We need to make sure that _beginthreadex() returns to the parent thread first
so we can safely fill up the members of the pthread_t structure without possible
race conditions. If the new thread is created in supsended state we eliminate
the race condition but now we have to resume the new thread. */
ResumeThread( thread->hThread );
return 0;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_join(pthread_t thread, void **value_ptr)
{
WaitForSingleObject( thread.hThread, INFINITE );
CloseHandle( thread.hThread );
return 0;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
{
InitializeCriticalSection( &cond->cs );
cond->hSem = CreateSemaphore( NULL, /* no security attributes */
0, /* initial count */
LONG_MAX, /* maximum count*/
NULL ); /* unnamed semaphore */
cond->hEvt = CreateEvent( NULL, /* no security attributes */
FALSE, /* reset to not-singaled automatically */
FALSE, /* set initial status to not-signaled */
NULL ); /* unnamed event */
cond->waitCount = 0;
return 0;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_cond_destroy(pthread_cond_t *cond)
{
DeleteCriticalSection( &cond->cs );
CloseHandle( cond->hSem );
CloseHandle( cond->hEvt );
return 0;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
int last;
if ( *mutex == PTHREAD_MUTEX_INITIALIZER ) pthread_mutex_check_for_static_initialization( mutex );
/* Avoid race condition on waiting thread counter. */
EnterCriticalSection(&cond->cs);
cond->waitCount++;
LeaveCriticalSection(&cond->cs);
/* Releases _atomically_ the mutex and wait on the semaphore until
pthread_cond_signal() or pthread_cond_broadcast() are called (by another thread). */
SignalObjectAndWait(*mutex, cond->hSem, INFINITE, FALSE);
/* Avoid race condition on waiting thread counter. */
EnterCriticalSection(&cond->cs);
cond->waitCount--; /* this thread doesn't wait any more */
/* if this is the last thread to have waited */
last = cond->waitCount == 0;
LeaveCriticalSection(&cond->cs);
/* If this thread is the last waiter thread during this particular broadcast
then let all the other threads proceed. */
if (last)
/* This call ensures that two things happen atomically: signaling the hEvt event and
waiting until "mutex" can be acquired. */
SignalObjectAndWait(cond->hEvt, *mutex, INFINITE, FALSE);
else
WaitForSingleObject(*mutex, INFINITE); /* Upon return, this thread has to own "mutex". */
return 0;
}
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_cond_broadcast(pthread_cond_t *cond)
{
int more_waiters = 0;
/* This is needed to ensure exclusive access to "waitCount" */
EnterCriticalSection (&cond->cs);
if (cond->waitCount > 0) {
/* always are broadcasting - no need for pthread_cond_singal() case */
more_waiters = 1;
}
if (more_waiters) {
/* this will wake up all the waiters atomically at once. */
ReleaseSemaphore(cond->hSem, cond->waitCount, 0);
LeaveCriticalSection(&cond->cs);
/* Wait for all the awakened threads to acquire the counting semaphore. */
WaitForSingleObject(cond->hEvt, INFINITE);
} else
LeaveCriticalSection(&cond->cs);
return 0;
}
int pthread_conclevel;
extern "C"
MAGMA_DLLPORT int MAGMA_CDECL pthread_setconcurrency (int level)
{
pthread_conclevel = level;
return 0;
}
#endif /* defined( _WIN32 ) || defined( _WIN64 ) */
|