00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00039 #include "xdasd_thread.h"
00040
00041 #include <xdas_base.h>
00042
00043 #include <stddef.h>
00044
00065 thread_t thread_create(void *(*thread_proc)(void *), void * arg)
00066 {
00067 #ifdef _WIN32
00068 return (thread_t)CreateThread(0, 0,
00069 (LPTHREAD_START_ROUTINE)thread_proc, arg, 0, 0);
00070 #else
00071 pthread_t th;
00072 return (thread_t)(pthread_create(&th, 0, thread_proc, arg)? 0: th);
00073 #endif
00074 }
00075
00087 void * thread_wait(thread_t th)
00088 {
00089 void * result = 0;
00090 #ifdef _WIN32
00091 DWORD dwres;
00092 WaitForSingleObject((HANDLE)th, INFINITE);
00093 if (GetExitCodeThread((HANDLE)th, &dwres))
00094 result = (void *)(intptr_t)dwres;
00095 CloseHandle((HANDLE)th);
00096 #else
00097 pthread_join((pthread_t)th, &result);
00098 #endif
00099 return result;
00100 }
00101
00102 #ifdef _WIN32
00103
00104
00105
00106 #define MAX_SEM_COUNT ((LONG)(0x7FFFFFFFL))
00107
00118 static int cv_unblock(cv_t * cvp, int unblock_all)
00119 {
00120 int nSignalsToIssue;
00121
00122
00123
00124 EnterCriticalSection(&cvp->csUnblockLock);
00125
00126 if (cvp->waitersToUnblock != 0)
00127 {
00128 if (cvp->waitersBlocked == 0)
00129 {
00130 LeaveCriticalSection(&cvp->csUnblockLock);
00131 return 0;
00132 }
00133 if (unblock_all)
00134 {
00135 cvp->waitersToUnblock += (nSignalsToIssue = cvp->waitersBlocked);
00136 cvp->waitersBlocked = 0;
00137 }
00138 else
00139 {
00140 nSignalsToIssue = 1;
00141 cvp->waitersToUnblock++;
00142 cvp->waitersBlocked--;
00143 }
00144 }
00145 else if (cvp->waitersBlocked > cvp->waitersGone)
00146 {
00147
00148 if (!ReleaseSemaphore(cvp->semBlockLock, 1, 0))
00149 {
00150 int err = (int)GetLastError();
00151 LeaveCriticalSection(&cvp->csUnblockLock);
00152 return err;
00153 }
00154 if (cvp->waitersGone != 0)
00155 {
00156 cvp->waitersBlocked -= cvp->waitersGone;
00157 cvp->waitersGone = 0;
00158 }
00159 if (unblock_all)
00160 {
00161 nSignalsToIssue = cvp->waitersToUnblock = cvp->waitersBlocked;
00162 cvp->waitersBlocked = 0;
00163 }
00164 else
00165 {
00166 nSignalsToIssue = cvp->waitersToUnblock = 1;
00167 cvp->waitersBlocked--;
00168 }
00169 }
00170 else
00171 {
00172 LeaveCriticalSection(&cvp->csUnblockLock);
00173 return 0;
00174 }
00175
00176 LeaveCriticalSection(&cvp->csUnblockLock);
00177
00178 return ReleaseSemaphore(cvp->semBlockQueue,
00179 nSignalsToIssue, 0)? 0: (int)GetLastError();
00180 }
00181
00190 int cv_create(cv_t * cvp)
00191 {
00192
00193
00194 memset(cvp, 0, sizeof(*cvp));
00195 if ((cvp->semBlockLock = CreateSemaphore(0, 1, MAX_SEM_COUNT, 0)) == 0
00196 || (cvp->semBlockQueue = CreateSemaphore(0, 0, MAX_SEM_COUNT, 0)) == 0)
00197 {
00198 if (cvp->semBlockLock)
00199 CloseHandle(cvp->semBlockLock);
00200 return 0;
00201 }
00202 InitializeCriticalSection(&cvp->csUnblockLock);
00203 return 0;
00204 }
00205
00212 void cv_destroy(cv_t * cvp)
00213 {
00214
00215
00216
00217
00218
00219
00220 if (WaitForSingleObject(cvp->semBlockLock, INFINITE) != WAIT_OBJECT_0)
00221 return;
00222
00223
00224
00225
00226
00227 if (TryEnterCriticalSection(&cvp->csUnblockLock) == FALSE)
00228 {
00229 ReleaseSemaphore(cvp->semBlockLock, 1, 0);
00230 return;
00231 }
00232
00233
00234 if (cvp->waitersBlocked > cvp->waitersGone)
00235 {
00236 ReleaseSemaphore(cvp->semBlockLock, 1, 0);
00237 LeaveCriticalSection(&cvp->csUnblockLock);
00238 return;
00239 }
00240
00241
00242 CloseHandle(cvp->semBlockLock);
00243 CloseHandle(cvp->semBlockQueue);
00244 LeaveCriticalSection(&cvp->csUnblockLock);
00245 DeleteCriticalSection(&cvp->csUnblockLock);
00246 }
00247
00257 int cv_wait(cv_t * cvp, mutex_t * mp)
00258 {
00259 DWORD rv;
00260 int err = 0;
00261 int nSignalsWasLeft;
00262
00263
00264
00265 if (WaitForSingleObject(cvp->semBlockLock, INFINITE) != WAIT_OBJECT_0)
00266 return -1;
00267
00268 ++cvp->waitersBlocked;
00269 if (!ReleaseSemaphore(cvp->semBlockLock, 1, 0))
00270 return -1;
00271
00272
00273 LeaveCriticalSection(mp);
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 if ((rv = WaitForSingleObject(cvp->semBlockQueue, INFINITE)) != WAIT_OBJECT_0)
00291 err = rv == WAIT_TIMEOUT? -1: -2;
00292
00293
00294
00295
00296
00297
00298 EnterCriticalSection(&cvp->csUnblockLock);
00299
00300 if ((nSignalsWasLeft = cvp->waitersToUnblock) != 0)
00301 --cvp->waitersToUnblock;
00302 else if (++cvp->waitersGone == (unsigned)(-1) / 2)
00303 {
00304
00305 if (WaitForSingleObject(cvp->semBlockLock, INFINITE) != WAIT_OBJECT_0)
00306 return (int)GetLastError();
00307
00308 cvp->waitersBlocked -= cvp->waitersGone;
00309 if (!ReleaseSemaphore(cvp->semBlockLock, 1, 0))
00310 return (int)GetLastError();
00311
00312 cvp->waitersGone = 0;
00313 }
00314 LeaveCriticalSection(&cvp->csUnblockLock);
00315 if (nSignalsWasLeft == 1)
00316 if (!ReleaseSemaphore(cvp->semBlockLock, 1, 0))
00317 return (int)GetLastError();
00318
00319
00320
00321 EnterCriticalSection(mp);
00322 return err;
00323 }
00324
00333 int cv_signal(cv_t * cvp)
00334 {
00335
00336 return cv_unblock(cvp, 0);
00337 }
00338
00347 int cv_broadcast(cv_t * cvp)
00348 {
00349
00350 return cv_unblock(cvp, 1);
00351 }
00352
00353 #else
00354
00362 static void p_operation_cleanup(void * arg)
00363 { pthread_mutex_unlock(&((sem_t *)arg)->lock); }
00364
00374 int sem_create(sem_t * sp, int count)
00375 {
00376 if (pthread_mutex_init(&sp->lock, 0) != 0)
00377 return -1;
00378 if (pthread_cond_init(&sp->cond, 0) != 0)
00379 {
00380 pthread_mutex_destroy(&sp->lock);
00381 return -1;
00382 }
00383 sp->count = count;
00384 return 0;
00385 }
00386
00393 void sem_destroy(sem_t * sp)
00394 {
00395 (void)pthread_mutex_destroy(&sp->lock);
00396 (void)pthread_cond_destroy(&sp->cond);
00397 }
00398
00405 void sem_wait(sem_t * sp)
00406 {
00407 pthread_mutex_lock(&sp->lock);
00408 pthread_cleanup_push(p_operation_cleanup, sp);
00409
00410 while (sp->count <= 0)
00411 pthread_cond_wait(&sp->cond, &sp->lock);
00412 sp->count--;
00413
00414 pthread_cleanup_pop(1);
00415 }
00416
00424 void sem_signal(sem_t * sp, int count)
00425 {
00426 pthread_mutex_lock(&sp->lock);
00427
00428 sp->count += count;
00429 if (sp->count <= 0)
00430 pthread_cond_signal(&sp->cond);
00431
00432 pthread_mutex_unlock(&sp->lock);
00433 }
00434
00435 #endif
00436