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
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 #include <config.h>
00048
00049 #include <errno.h>
00050 #include <signal.h>
00051 #include <stdio.h>
00052 #include <stdarg.h>
00053 #include <sys/types.h>
00054 #include <time.h>
00055 #include <winsock2.h>
00056 #undef NS_ALL
00057 #include <windows.h>
00058 #include <process.h>
00059
00060
00061
00062 #include "unistd.h"
00063 #include "misc.h"
00064 #include "empthread.h"
00065 #include "prototypes.h"
00066 #include "server.h"
00067
00068 #define loc_MIN_THREAD_STACK 16384
00069
00070
00071
00072
00073 struct loc_Thread {
00074
00075
00076 char szName[17];
00077
00078
00079 BOOL bMainThread;
00080
00081
00082 void *pvUserData;
00083
00084
00085 BOOL bKilled;
00086
00087
00088 void (*pfnEntry) (void *);
00089
00090
00091 unsigned long ulThreadID;
00092
00093
00094 HANDLE hThreadEvent;
00095 };
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 struct loc_RWLock {
00138 char name[17];
00139 HANDLE can_read;
00140 HANDLE can_write;
00141 int nread;
00142 int nwrite;
00143 };
00144
00145
00146
00147
00148 static HANDLE hThreadMutex;
00149
00150
00151
00152 static HANDLE hThreadStartEvent;
00153
00154
00155
00156 static HANDLE hShutdownEvent;
00157
00158
00159
00160 static DWORD dwTLSIndex;
00161
00162
00163 static empth_t *pCurThread;
00164
00165
00166 static unsigned long ulTickAtStart;
00167
00168
00169
00170 static void **ppvUserData;
00171
00172
00173 static int global_flags;
00174
00175
00176
00177
00178
00179
00180
00181 static void
00182 loc_debug(const char *pszFmt, ...)
00183 {
00184 va_list vaList;
00185 unsigned long ulCurTick;
00186 unsigned long ulRunTick;
00187 unsigned long ulMs, ulSec, ulMin, ulHr;
00188 empth_t *pThread = TlsGetValue(dwTLSIndex);
00189 char buf[1024];
00190
00191 if ((global_flags & EMPTH_PRINT) != 0) {
00192
00193
00194 ulCurTick = GetTickCount();
00195
00196 ulRunTick = ulCurTick - ulTickAtStart;
00197 ulMs = ulRunTick % 1000L;
00198 ulSec = (ulRunTick / 1000L) % 60L;
00199 ulMin = (ulRunTick / (60L * 1000L)) % 60L;
00200 ulHr = (ulRunTick / (60L * 60L * 1000L));
00201
00202 va_start(vaList, pszFmt);
00203 vsprintf(buf, pszFmt, vaList);
00204 va_end(vaList);
00205
00206 if (pThread) {
00207 printf("%ld:%02ld:%02ld.%03ld %17s: %s\n",
00208 ulHr, ulMin, ulSec, ulMs, pThread->szName, buf);
00209 } else {
00210 printf("%ld:%02ld:%02ld.%03ld %17s: %s\n",
00211 ulHr, ulMin, ulSec, ulMs, "UNKNOWN", buf);
00212 }
00213
00214 }
00215 }
00216
00217
00218
00219
00220 static void
00221 loc_FreeThreadInfo(empth_t *pThread)
00222 {
00223 if (pThread) {
00224 if (pThread->hThreadEvent)
00225 CloseHandle(pThread->hThreadEvent);
00226 memset(pThread, 0, sizeof(*pThread));
00227 free(pThread);
00228 }
00229 }
00230
00231
00232
00233
00234
00235
00236
00237
00238 static void
00239 loc_RunThisThread(HANDLE hWaitObject)
00240 {
00241 HANDLE hWaitObjects[2];
00242
00243 empth_t *pThread = TlsGetValue(dwTLSIndex);
00244
00245 if (pThread->bKilled) {
00246 if (!pThread->bMainThread) {
00247 TlsSetValue(dwTLSIndex, NULL);
00248 loc_FreeThreadInfo(pThread);
00249 _endthread();
00250 }
00251 }
00252
00253 hWaitObjects[0] = hThreadMutex;
00254 hWaitObjects[1] = hWaitObject;
00255
00256 WaitForMultipleObjects(hWaitObject ? 2 : 1, hWaitObjects,
00257 TRUE, INFINITE);
00258
00259 if (!pCurThread) {
00260
00261 *ppvUserData = pThread->pvUserData;
00262
00263 pCurThread = pThread;
00264 } else {
00265
00266 logerror("RunThisThread, someone already running.");
00267 }
00268 }
00269
00270
00271
00272
00273
00274
00275 static void
00276 loc_BlockThisThread(void)
00277 {
00278 empth_t *pThread = TlsGetValue(dwTLSIndex);
00279
00280 if (pCurThread == pThread) {
00281
00282
00283 pCurThread = NULL;
00284 *ppvUserData = NULL;
00285
00286
00287 ReleaseMutex(hThreadMutex);
00288 } else {
00289
00290 logerror("BlockThisThread, not running.");
00291 }
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301 static BOOL WINAPI
00302 loc_Exit_Handler(DWORD fdwCtrlType)
00303 {
00304 switch (fdwCtrlType) {
00305 case CTRL_C_EVENT:
00306 case CTRL_CLOSE_EVENT:
00307 case CTRL_BREAK_EVENT:
00308 case CTRL_LOGOFF_EVENT:
00309 case CTRL_SHUTDOWN_EVENT:
00310 empth_request_shutdown();
00311 return TRUE;
00312 default:
00313 return FALSE;
00314 }
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 static void
00327 empth_threadMain(void *pvData)
00328 {
00329 empth_t *pThread = pvData;
00330
00331
00332 if (!pvData)
00333 return;
00334
00335
00336 TlsSetValue(dwTLSIndex, pvData);
00337
00338
00339 pThread->ulThreadID = GetCurrentThreadId();
00340
00341
00342 SetEvent(hThreadStartEvent);
00343
00344
00345 loc_RunThisThread(NULL);
00346
00347
00348 if (pThread->pfnEntry)
00349 pThread->pfnEntry(pThread->pvUserData);
00350
00351
00352 empth_exit();
00353 }
00354
00355
00356
00357
00358
00359
00360
00361
00362 int
00363 empth_init(void **ctx_ptr, int flags)
00364 {
00365 empth_t *pThread = NULL;
00366
00367 ulTickAtStart = GetTickCount();
00368 ppvUserData = ctx_ptr;
00369 global_flags = flags;
00370 dwTLSIndex = TlsAlloc();
00371
00372
00373
00374 hThreadMutex = CreateMutex(NULL, FALSE, NULL);
00375 if (!hThreadMutex) {
00376 logerror("Failed to create mutex %lu", GetLastError());
00377 return 0;
00378 }
00379
00380
00381
00382 hThreadStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
00383 if (!hThreadStartEvent) {
00384 logerror("Failed to create start event %lu", GetLastError());
00385 return 0;
00386 }
00387
00388
00389
00390 hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
00391 if (!hShutdownEvent) {
00392 logerror("Failed to create shutdown event %lu", GetLastError());
00393 return 0;
00394 }
00395 SetConsoleCtrlHandler(loc_Exit_Handler, TRUE);
00396
00397
00398 pThread = malloc(sizeof(*pThread));
00399 if (!pThread) {
00400 logerror("not enough memory to create main thread.");
00401 return 0;
00402 }
00403 memset(pThread, 0, sizeof(*pThread));
00404
00405 strncpy(pThread->szName, "Main", sizeof(pThread->szName) - 1);
00406 pThread->ulThreadID = GetCurrentThreadId();
00407 pThread->bMainThread = TRUE;
00408
00409 TlsSetValue(dwTLSIndex, pThread);
00410
00411
00412 loc_RunThisThread(NULL);
00413
00414 logerror("NT pthreads initialized");
00415 return 0;
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433 empth_t *
00434 empth_create(void (*entry)(void *), int size, int flags,
00435 char *name, void *ud)
00436 {
00437 empth_t *pThread = NULL;
00438
00439 loc_debug("creating new thread %s", name);
00440
00441 pThread = malloc(sizeof(*pThread));
00442 if (!pThread) {
00443 logerror("not enough memory to create thread %s", name);
00444 return NULL;
00445 }
00446 memset(pThread, 0, sizeof(*pThread));
00447
00448 strncpy(pThread->szName, name, sizeof(pThread->szName) - 1);
00449 pThread->pvUserData = ud;
00450 pThread->pfnEntry = entry;
00451 pThread->bMainThread = FALSE;
00452
00453
00454 pThread->hThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
00455
00456 if (size < loc_MIN_THREAD_STACK)
00457 size = loc_MIN_THREAD_STACK;
00458
00459 pThread->ulThreadID = _beginthread(empth_threadMain, size, pThread);
00460 if (pThread->ulThreadID == 1L) {
00461 logerror("can not create thread: %s: %s", name, strerror(errno));
00462 goto bad;
00463 }
00464
00465 loc_debug("new thread id is %ld", pThread->ulThreadID);
00466 empth_yield();
00467 return pThread;
00468
00469 bad:
00470 if (pThread) {
00471 loc_FreeThreadInfo(pThread);
00472 }
00473 return NULL;
00474 }
00475
00476
00477
00478
00479
00480 empth_t *
00481 empth_self(void)
00482 {
00483 empth_t *pThread = TlsGetValue(dwTLSIndex);
00484
00485 return pThread;
00486 }
00487
00488
00489
00490
00491 void
00492 empth_exit(void)
00493 {
00494 empth_t *pThread = TlsGetValue(dwTLSIndex);
00495
00496 loc_debug("empth_exit");
00497 loc_BlockThisThread();
00498
00499 TlsSetValue(dwTLSIndex, NULL);
00500 loc_FreeThreadInfo(pThread);
00501 _endthread();
00502 }
00503
00504
00505
00506
00507
00508
00509 void
00510 empth_yield(void)
00511 {
00512 loc_BlockThisThread();
00513 loc_RunThisThread(NULL);
00514 }
00515
00516
00517
00518
00519
00520
00521 void
00522 empth_terminate(empth_t *pThread)
00523 {
00524 loc_debug("killing thread %s", pThread->szName);
00525 pThread->bKilled = TRUE;
00526
00527 SetEvent(pThread->hThreadEvent);
00528 }
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538 void
00539 empth_select(int fd, int flags)
00540 {
00541 int handle;
00542 WSAEVENT hEventObject[2];
00543 empth_t *pThread = TlsGetValue(dwTLSIndex);
00544
00545 loc_debug("%s select on %d",
00546 flags == EMPTH_FD_READ ? "read" : "write", fd);
00547 loc_BlockThisThread();
00548
00549 hEventObject[0] = WSACreateEvent();
00550 hEventObject[1] = pThread->hThreadEvent;
00551
00552 handle = posix_fd2socket(fd);
00553 CANT_HAPPEN(handle < 0);
00554
00555 if (flags == EMPTH_FD_READ)
00556 WSAEventSelect(handle, hEventObject[0], FD_READ | FD_ACCEPT | FD_CLOSE);
00557 else if (flags == EMPTH_FD_WRITE)
00558 WSAEventSelect(handle, hEventObject[0], FD_WRITE | FD_CLOSE);
00559 else {
00560 logerror("bad flag %d passed to empth_select", flags);
00561 empth_exit();
00562 }
00563
00564 WSAWaitForMultipleEvents(2, hEventObject, FALSE, WSA_INFINITE, FALSE);
00565
00566 WSAEventSelect(handle, hEventObject[0], 0);
00567
00568 WSACloseEvent(hEventObject[0]);
00569
00570 loc_RunThisThread(NULL);
00571 }
00572
00573
00574
00575
00576
00577
00578 void
00579 empth_wakeup(empth_t *pThread)
00580 {
00581 loc_debug("waking up thread %s", pThread->szName);
00582
00583
00584 SetEvent(pThread->hThreadEvent);
00585 }
00586
00587
00588
00589
00590
00591
00592 int
00593 empth_sleep(time_t until)
00594 {
00595 long lSec;
00596 empth_t *pThread = TlsGetValue(dwTLSIndex);
00597 int iReturn = 0;
00598
00599 while (!iReturn && ((lSec = until - time(0)) > 0)) {
00600 loc_BlockThisThread();
00601 loc_debug("going to sleep %ld sec", lSec);
00602
00603 if (WaitForSingleObject(pThread->hThreadEvent, lSec * 1000L) !=
00604 WAIT_TIMEOUT)
00605 iReturn = -1;
00606
00607 loc_debug("sleep done. Waiting to run.");
00608 loc_RunThisThread(NULL);
00609 }
00610 return iReturn;
00611 }
00612
00613
00614
00615
00616
00617
00618
00619 void
00620 empth_request_shutdown(void)
00621 {
00622 SetEvent(hShutdownEvent);
00623 }
00624
00625 int
00626 empth_wait_for_signal(void)
00627 {
00628 loc_BlockThisThread();
00629 loc_RunThisThread(hShutdownEvent);
00630 return SIGTERM;
00631 }
00632
00633 empth_rwlock_t *
00634 empth_rwlock_create(char *name)
00635 {
00636 empth_rwlock_t *rwlock;
00637
00638 rwlock = malloc(sizeof(*rwlock));
00639 if (!rwlock)
00640 return NULL;
00641
00642 memset(rwlock, 0, sizeof(*rwlock));
00643 strncpy(rwlock->name, name, sizeof(rwlock->name) - 1);
00644
00645 if ((rwlock->can_read = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL) {
00646 logerror("rwlock_create: failed to create reader event %s at %s:%d",
00647 name, __FILE__, __LINE__);
00648 free(rwlock);
00649 return NULL;
00650 }
00651
00652 if ((rwlock->can_write = CreateEvent(NULL, FALSE, TRUE, NULL)) == NULL) {
00653 logerror("rwlock_create: failed to create writer event %s at %s:%d",
00654 name, __FILE__, __LINE__);
00655 CloseHandle(rwlock->can_read);
00656 free(rwlock);
00657 return NULL;
00658 }
00659 return rwlock;
00660 }
00661
00662 void
00663 empth_rwlock_destroy(empth_rwlock_t *rwlock)
00664 {
00665 if (CANT_HAPPEN(rwlock->nread || rwlock->nwrite))
00666 return;
00667 CloseHandle(rwlock->can_read);
00668 CloseHandle(rwlock->can_write);
00669 free(rwlock);
00670 }
00671
00672 void
00673 empth_rwlock_wrlock(empth_rwlock_t *rwlock)
00674 {
00675
00676 ResetEvent(rwlock->can_read);
00677 rwlock->nwrite++;
00678 loc_BlockThisThread();
00679 loc_RunThisThread(rwlock->can_write);
00680 CANT_HAPPEN(rwlock->nread != 0);
00681 }
00682
00683 void
00684 empth_rwlock_rdlock(empth_rwlock_t *rwlock)
00685 {
00686 loc_BlockThisThread();
00687 loc_RunThisThread(rwlock->can_read);
00688 ResetEvent(rwlock->can_write);
00689 rwlock->nread++;
00690 }
00691
00692 void
00693 empth_rwlock_unlock(empth_rwlock_t *rwlock)
00694 {
00695 if (CANT_HAPPEN(!rwlock->nread && !rwlock->nwrite))
00696 return;
00697 if (rwlock->nread) {
00698 rwlock->nread--;
00699 if (rwlock->nread == 0)
00700 SetEvent(rwlock->can_write);
00701 } else {
00702 rwlock->nwrite--;
00703 SetEvent(rwlock->can_write);
00704 }
00705 if (rwlock->nwrite == 0)
00706 SetEvent(rwlock->can_read);
00707 }