-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquarkwinthread.c
269 lines (217 loc) · 8.08 KB
/
quarkwinthread.c
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
/**
*
* @file quarkwinthread.c
*
* This file handles the mapping from pthreads calls to windows threads
* QUARK is a software package provided by Univ. of Tennessee,
* Univ. of California Berkeley and Univ. of Colorado Denver
*
* @version 2.8.0
* @author Piotr Luszczek
* @date 2010-11-15
*
* Note : this file is a copy of a PLASMA file for use of QUARK in a
* standalone library updated by Asim YarKhan
**/
#include "quarkwinthread.h"
#include <limits.h>
/** this is needed to get a declaration for _beginthreadex() */
#include <process.h>
#include <stdio.h>
#include <quark.h>
CRITICAL_SECTION quarkwinthread_static_initializer_check_lock;
static int quarkwinthread_initialized = 0;
QUARK_DLLPORT unsigned int QUARK_CDECL pthread_self_id(void) {
return GetCurrentThreadId();
}
QUARK_DLLPORT pthread_t QUARK_CDECL pthread_self(void) {
pthread_t pt;
pt.hThread = GetCurrentThread();
pt.uThId = GetCurrentThreadId();
return pt;
}
QUARK_DLLPORT int QUARK_CDECL pthread_equal(pthread_t thread1, pthread_t thread2) {
if (thread1.uThId == thread2.uThId) // && thread1.hThread == thread2.hThread)
return 1;
return 0;
}
QUARK_DLLPORT int QUARK_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 ( quarkwinthread_initialized == 0 ) {
quarkwinthread_initialized = 1;
InitializeCriticalSection( &quarkwinthread_static_initializer_check_lock );
}
EnterCriticalSection( &quarkwinthread_static_initializer_check_lock );
if ( *mutex == PTHREAD_MUTEX_INITIALIZER )
retval = pthread_mutex_init( mutex, NULL );
LeaveCriticalSection( &quarkwinthread_static_initializer_check_lock );
return retval;
}
QUARK_DLLPORT int QUARK_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;
}
}
QUARK_DLLPORT int QUARK_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;
}
}
QUARK_DLLPORT int QUARK_CDECL pthread_mutex_unlock(pthread_mutex_t *mutex) {
if (! ReleaseMutex( *mutex ))
return -1;
return 0;
}
QUARK_DLLPORT int QUARK_CDECL pthread_mutex_destroy(pthread_mutex_t *mutex) {
CloseHandle( *mutex );
return 0;
}
QUARK_DLLPORT int QUARK_CDECL pthread_attr_init(pthread_attr_t *attr) {
*attr = 1;
return 0;
}
QUARK_DLLPORT int QUARK_CDECL pthread_attr_destroy(pthread_attr_t *attr) {
*attr = 0;
return 0;
}
QUARK_DLLPORT int QUARK_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 *(*QUARK_realThStart)(void *);
/*
This function is only called to have a proxy that is compatible with WINAPI.
*/
unsigned WINAPI QUARK_winThStart(void *arg) {
QUARK_realThStart( arg );
return 0;
}
QUARK_DLLPORT int QUARK_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) */
QUARK_realThStart = start;
thread->hThread = (HANDLE)_beginthreadex(
NULL, /* default security */
0, /* stack size: use the size of calling thread */
QUARK_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;
}
QUARK_DLLPORT int QUARK_CDECL pthread_join(pthread_t thread, void **value_ptr) {
WaitForSingleObject( thread.hThread, INFINITE );
CloseHandle( thread.hThread );
return 0;
}
QUARK_DLLPORT int QUARK_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;
}
QUARK_DLLPORT int QUARK_CDECL pthread_cond_destroy(pthread_cond_t *cond) {
DeleteCriticalSection( &cond->cs );
CloseHandle( cond->hSem );
CloseHandle( cond->hEvt );
return 0;
}
QUARK_DLLPORT int QUARK_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;
}
QUARK_DLLPORT int QUARK_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;
QUARK_DLLPORT int QUARK_CDECL pthread_setconcurrency (int level) {
pthread_conclevel = level;
return 0;
}