00001 #include <assert.h>
00002 #include "stdafx.h"
00003 #include "cphidget.h"
00004 #include "cphidgetmanager.h"
00005 #include "cusb.h"
00006 #include "cphidgetlist.h"
00007
00008 #if defined(_MACOSX) && !defined(_IPHONE)
00009 #include "macusb.h"
00010 #endif
00011
00012 CThread_func_return_t CentralThreadFunction(CThread_func_arg_t arg);
00013
00014 static CThread CentralThread;
00015 static int checkForDevicesEventInitialized = PFALSE;
00016 static EVENT checkForDevicesEvent;
00017
00018
00019 int pause_usb_traffic = PFALSE;
00020 int usb_write_paused = PFALSE;
00021 int usb_read_paused = PFALSE;
00022
00023 #ifdef _MACOSX
00024 void macPeriodicTimerFunction(CFRunLoopTimerRef timer, void *Handle);
00025 void macFindActiveDevicesSource(void *nothing);
00026 CFRunLoopTimerRef timer = NULL;
00027 CFRunLoopSourceRef findActiveDevicesSource = NULL;
00028 #endif
00029
00030 #ifdef _WINDOWS
00031
00032 #if defined(_WINDOWS) && !defined(WINCE)
00033 extern void initializeThreadSecurityAttributes();
00034 #else
00035 #define initializeThreadSecurityAttributes()
00036 #endif
00037 extern PSECURITY_ATTRIBUTES pSA;
00038
00039 #endif
00040
00041 int
00042 StartCentralThread()
00043 {
00044
00045 #ifdef _WINDOWS
00046 if (CentralThread.m_ThreadHandle) {
00047 int threadStatus = 0;
00048 int result = 0;
00049 result = GetExitCodeThread(CentralThread.m_ThreadHandle,
00050 (LPDWORD)&threadStatus);
00051 if (result) {
00052 if (threadStatus != STILL_ACTIVE) {
00053 CloseHandle(CentralThread.m_ThreadHandle);
00054 CentralThread.m_ThreadHandle = 0;
00055 }
00056 }
00057 }
00058 #endif
00059
00060 if(checkForDevicesEventInitialized == PFALSE)
00061 {
00062 checkForDevicesEventInitialized = PTRUE;
00063 CThread_create_event(&checkForDevicesEvent);
00064 }
00065
00066 #ifdef _MACOSX
00067 if(findActiveDevicesSource == NULL)
00068 {
00069 CFRunLoopSourceContext sourceContext = {0};
00070 sourceContext.perform = macFindActiveDevicesSource;
00071 findActiveDevicesSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &sourceContext);
00072 }
00073 if(timer == NULL)
00074 timer = CFRunLoopTimerCreate(kCFAllocatorDefault, 0, 0.250, 0, 0, macPeriodicTimerFunction, NULL);
00075 #endif
00076
00077
00078 if (!CentralThread.m_ThreadHandle || CentralThread.thread_status == FALSE)
00079 {
00080 #ifdef _MACOSX
00081 CentralThread.macInitDone = PFALSE;
00082 #endif
00083 CThread_reset_event(&checkForDevicesEvent);
00084
00085 if (CThread_create(&CentralThread, CentralThreadFunction, 0))
00086 return EPHIDGET_UNEXPECTED;
00087 CentralThread.thread_status = TRUE;
00088 }
00089
00090 else {
00091 #ifdef _MACOSX
00092
00093 while(!CentralThread.macInitDone)
00094 SLEEP(10);
00095
00096 CFRunLoopSourceSignal(findActiveDevicesSource);
00097 CFRunLoopWakeUp(CentralThread.runLoop);
00098 #else
00099
00100 CThread_set_event(&checkForDevicesEvent);
00101 #endif
00102 }
00103 return EPHIDGET_OK;
00104 }
00105
00106 int
00107 JoinCentralThread()
00108 {
00109 if(CentralThread.m_ThreadHandle && !CThread_is_my_thread(CentralThread))
00110 {
00111 #ifdef _MACOSX
00112 while(!CentralThread.macInitDone)
00113 SLEEP(10);
00114 CPhidgetManager_teardownNotifications();
00115
00116 CFRunLoopRemoveTimer(CentralThread.runLoop, timer, kCFRunLoopDefaultMode);
00117 CFRunLoopRemoveSource(CentralThread.runLoop, findActiveDevicesSource, kCFRunLoopDefaultMode);
00118
00119 CFRunLoopStop(CentralThread.runLoop);
00120
00121 CentralThread.macInitDone = PFALSE;
00122 #endif
00123 CThread_join(&CentralThread);
00124 CentralThread.m_ThreadHandle = 0;
00125 }
00126 return EPHIDGET_OK;
00127 }
00128
00129
00130
00131
00132
00133
00134 int
00135 RegisterLocalDevice(CPhidgetHandle phid)
00136 {
00137 int result;
00138
00139 TESTPTR(phid)
00140
00141 if(!phidgetLocksInitialized)
00142 {
00143 CThread_mutex_init(&activeDevicesLock);
00144 CThread_mutex_init(&attachedDevicesLock);
00145 phidgetLocksInitialized = PTRUE;
00146 }
00147 CThread_mutex_lock(&activeDevicesLock);
00148
00149 if(phid->specificDevice == PHIDGETOPEN_SERIAL || phid->specificDevice == PHIDGETOPEN_LABEL)
00150 result = CList_addToList((CListHandle *)&ActiveDevices, phid, CPhidget_areEqual);
00151 else
00152 result = CList_addToList((CListHandle *)&ActiveDevices, phid, CPhidgetHandle_areEqual);
00153
00154 if (result)
00155 {
00156 CThread_mutex_unlock(&activeDevicesLock);
00157 return result;
00158 }
00159 CThread_mutex_unlock(&activeDevicesLock);
00160
00161 result = StartCentralThread();
00162 return result;
00163 }
00164
00165 #ifdef _MACOSX
00166
00167 void macPeriodicTimerFunction(CFRunLoopTimerRef timer, void *Handle) {
00168 CPhidgetList *trav = 0;
00169
00170
00171 CThread_mutex_lock(&activeDevicesLock);
00172 for (trav=ActiveDevices; trav; trav = trav->next)
00173 {
00174 if(CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG))
00175 {
00176 if(CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_USB_ERROR_FLAG))
00177 {
00178 LOG(PHIDGET_LOG_WARNING,"PHIDGET_USB_ERROR_FLAG is set - cycling device through a reenumeration.");
00179 reenumerateDevice(trav->phid);
00180 }
00181 }
00182 }
00183 CThread_mutex_unlock(&activeDevicesLock);
00184
00185
00186
00187 if(ActiveDevices) {
00188 findActiveDevices();
00189 }
00190
00191 return;
00192 }
00193
00194
00195 void macFindActiveDevicesSource(void *nothing) {
00196 if(ActiveDevices) {
00197 findActiveDevices();
00198 }
00199 return;
00200 }
00201 #endif
00202
00203
00204
00205
00206 CThread_func_return_t CentralThreadFunction(CThread_func_arg_t lpdwParam)
00207 {
00208 #ifdef _MACOSX
00209 CentralThread.runLoop = CFRunLoopGetCurrent();
00210
00211 CFRunLoopAddTimer(CentralThread.runLoop, timer, kCFRunLoopDefaultMode);
00212 CFRunLoopAddSource(CentralThread.runLoop, findActiveDevicesSource, kCFRunLoopDefaultMode);
00213
00214 CentralThread.macInitDone = PTRUE;
00215
00216
00217 CPhidgetManager_setupNotifications(CentralThread.runLoop);
00218
00219
00220 CFRunLoopRun();
00221 #else
00222
00223 while(ActiveDevices || ActivePhidgetManagers) {
00224 CPhidgetManager_poll();
00225 findActiveDevices();
00226
00227
00228
00229 CThread_wait_on_event(&checkForDevicesEvent, 250);
00230 CThread_reset_event(&checkForDevicesEvent);
00231 }
00232 #endif
00233
00234
00235
00236 CThread_mutex_lock(&attachedDevicesLock);
00237 CList_emptyList((CListHandle *)&AttachedDevices, TRUE, CPhidget_free);
00238 CThread_mutex_unlock(&attachedDevicesLock);
00239
00240 LOG(PHIDGET_LOG_INFO,"Central Thread exiting");
00241
00242 if(fptrJavaDetachCurrentThread)
00243 fptrJavaDetachCurrentThread();
00244 CentralThread.thread_status = FALSE;
00245 return EPHIDGET_OK;
00246 }
00247
00248
00249 CThread_func_return_t ReadThreadFunction(CThread_func_arg_t lpdwParam)
00250 {
00251 CPhidgetHandle phid = (CPhidgetHandle)lpdwParam;
00252 int result = EPHIDGET_OK;
00253 LOG(PHIDGET_LOG_INFO,"ReadThread running");
00254
00255 if (!phid)
00256 {
00257 LOG(PHIDGET_LOG_ERROR,"ReadThread exiting - Invalid device handle");
00258 return (CThread_func_return_t)EPHIDGET_INVALIDARG;
00259 }
00260
00261
00262 switch(phid->deviceID)
00263 {
00264 case PHIDCLASS_SERVO:
00265 if(phid->deviceVersion < 313)
00266 goto exit_not_needed;
00267 break;
00268 case PHIDCLASS_INTERFACEKIT:
00269 if(phid->deviceIDSpec == PHIDID_INTERFACEKIT_0_0_4 && phid->deviceVersion < 704)
00270 goto exit_not_needed;
00271 break;
00272 case PHIDCLASS_LED:
00273 if(phid->deviceIDSpec == PHIDID_LED_64)
00274 goto exit_not_needed;
00275 break;
00276 case PHIDCLASS_TEXTLCD:
00277 if(phid->deviceIDSpec != PHIDID_TEXTLCD_ADAPTER)
00278 goto exit_not_needed;
00279 break;
00280 case PHIDCLASS_TEXTLED:
00281 exit_not_needed:
00282 LOG(PHIDGET_LOG_INFO,"ReadThread exiting normally (Not Needed for this device)");
00283 goto exit;
00284 default:
00285 break;
00286 }
00287
00288 while (CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG))
00289 {
00290 if(pause_usb_traffic)
00291 {
00292 usb_read_paused = PTRUE;
00293 SLEEP(20);
00294 continue;
00295 }
00296 else
00297 usb_read_paused = PFALSE;
00298
00299 result=CPhidget_read(phid);
00300
00301 switch(result)
00302 {
00303 case EPHIDGET_OK:
00304 case EPHIDGET_TRYAGAIN:
00305 break;
00306 case EPHIDGET_NOTATTACHED:
00307 LOG(PHIDGET_LOG_INFO,"ReadThread exiting normally (Phidget detach detected in CPhidget_read)");
00308 goto exit;
00309 case EPHIDGET_INTERRUPTED:
00310 LOG(PHIDGET_LOG_INFO,"ReadThread exiting normally (signaled by CPhidget_close)");
00311 goto exit;
00312 case EPHIDGET_TIMEOUT:
00313
00314
00315 switch(phid->deviceID)
00316 {
00317 case PHIDCLASS_INTERFACEKIT:
00318 switch(phid->deviceIDSpec)
00319 {
00320 case PHIDID_INTERFACEKIT_0_16_16:
00321 if(phid->deviceVersion >= 601)
00322 goto timeout_not_ok;
00323 else
00324 goto timeout_ok;
00325 case PHIDID_INTERFACEKIT_0_8_8_w_LCD:
00326 goto timeout_ok;
00327 default:
00328 goto timeout_not_ok;
00329 }
00330 case PHIDCLASS_RFID:
00331 if(phid->deviceVersion >= 201)
00332 goto timeout_not_ok;
00333 else
00334 goto timeout_ok;
00335 case PHIDCLASS_ENCODER:
00336 if(phid->deviceIDSpec == PHIDID_ENCODER_HS_4ENCODER_4INPUT)
00337 goto timeout_not_ok;
00338 else
00339 goto timeout_ok;
00340 case PHIDCLASS_GENERIC:
00341 goto timeout_ok;
00342 default:
00343 goto timeout_not_ok;
00344 }
00345 timeout_not_ok:
00346 CPhidget_setStatusFlag(&phid->status, PHIDGET_USB_ERROR_FLAG, &phid->lock);
00347 LOG(PHIDGET_LOG_ERROR,"ReadThread exiting - unexpected timeout (could be an ESD event)");
00348 goto exit;
00349 timeout_ok:
00350 LOG(PHIDGET_LOG_VERBOSE,"CUSBReadPacket expected time out");
00351 break;
00352 case EPHIDGET_UNEXPECTED:
00353 default:
00354 LOG(PHIDGET_LOG_ERROR,"ReadThread exiting - CPhidget_read returned : %d",result);
00355 CPhidget_setStatusFlag(&phid->status, PHIDGET_USB_ERROR_FLAG, &phid->lock);
00356 goto exit;
00357 }
00358 }
00359
00360 LOG(PHIDGET_LOG_INFO,"ReadThread exiting normally (Phidget detached)");
00361 exit:
00362 if(fptrJavaDetachCurrentThread)
00363 fptrJavaDetachCurrentThread();
00364 phid->readThread.thread_status = FALSE;
00365 return (CThread_func_return_t)(size_t)result;
00366 }
00367
00368
00369 CThread_func_return_t WriteThreadFunction(CThread_func_arg_t lpdwParam)
00370 {
00371 CPhidgetHandle phid = (CPhidgetHandle)lpdwParam;
00372 int result = EPHIDGET_OK, wait_return = 0;
00373 LOG(PHIDGET_LOG_INFO,"WriteThread running");
00374
00375 if (!phid)
00376 {
00377 LOG(PHIDGET_LOG_ERROR,"WriteThread exiting - Invalid device handle");
00378 return (CThread_func_return_t)EPHIDGET_INVALIDARG;
00379 }
00380
00381
00382 switch(phid->deviceID)
00383 {
00384 case PHIDCLASS_INTERFACEKIT:
00385 if(phid->deviceIDSpec == PHIDID_LINEAR_TOUCH
00386 || phid->deviceIDSpec == PHIDID_ROTARY_TOUCH)
00387 goto exit_not_needed;
00388 break;
00389 case PHIDCLASS_RFID:
00390 if(phid->deviceIDSpec == PHIDID_RFID)
00391 goto exit_not_needed;
00392 break;
00393 case PHIDCLASS_ENCODER:
00394 if(phid->deviceIDSpec == PHIDID_ENCODER_1ENCODER_1INPUT
00395 || phid->deviceIDSpec == PHIDID_ENCODER_HS_1ENCODER)
00396 goto exit_not_needed;
00397 break;
00398 case PHIDCLASS_ACCELEROMETER:
00399 case PHIDCLASS_TEMPERATURESENSOR:
00400 case PHIDCLASS_PHSENSOR:
00401 case PHIDCLASS_WEIGHTSENSOR:
00402 exit_not_needed:
00403 LOG(PHIDGET_LOG_INFO,"WriteThread exiting normally (Not Needed for this device)");
00404 goto exit;
00405 default:
00406 break;
00407 }
00408
00409 while (CPhidget_statusFlagIsSet(phid->status, PHIDGET_ATTACHED_FLAG))
00410 {
00411
00412 wait_return = CThread_wait_on_event(&phid->writeAvailableEvent, 200);
00413 switch (wait_return) {
00414 case WAIT_TIMEOUT:
00415
00416 if(phid->writeStopFlag)
00417 {
00418 LOG(PHIDGET_LOG_INFO,"WriteThread exiting normally (signaled by writeStopFlag)");
00419 goto exit;
00420 }
00421 if(!phid->awdc_enabled)
00422 break;
00423 case WAIT_OBJECT_0:
00424 if(pause_usb_traffic)
00425 {
00426 usb_write_paused = PTRUE;
00427 break;
00428 }
00429 else
00430 usb_write_paused = PFALSE;
00431
00432 if((result = CPhidget_write(phid)))
00433 {
00434 switch(result)
00435 {
00436 case EPHIDGET_NOTATTACHED:
00437 LOG(PHIDGET_LOG_INFO,"WriteThread exiting normally (Phidget detach detected in CPhidget_write)");
00438 break;
00439 case EPHIDGET_INTERRUPTED:
00440 LOG(PHIDGET_LOG_INFO,"WriteThread exiting normally (signaled by CPhidget_close)");
00441 break;
00442 case EPHIDGET_TIMEOUT:
00443 LOG(PHIDGET_LOG_ERROR,"WriteThread exiting - unexpected timeout (could be an ESD event)");
00444 CPhidget_setStatusFlag(&phid->status, PHIDGET_USB_ERROR_FLAG, &phid->lock);
00445 break;
00446 case EPHIDGET_UNEXPECTED:
00447 default:
00448 LOG(PHIDGET_LOG_ERROR,"WriteThread exiting - CPhidget_write returned : %d",result);
00449 CPhidget_setStatusFlag(&phid->status, PHIDGET_USB_ERROR_FLAG, &phid->lock);
00450 break;
00451 }
00452 goto exit;
00453 }
00454 break;
00455 default:
00456 LOG(PHIDGET_LOG_ERROR,"WriteThread exiting - wait on phid->writeAvailableEvent failed");
00457 CPhidget_setStatusFlag(&phid->status, PHIDGET_USB_ERROR_FLAG, &phid->lock);
00458 result = EPHIDGET_UNEXPECTED;
00459 goto exit;
00460 }
00461 }
00462 LOG(PHIDGET_LOG_INFO,"WriteThread exiting normally (Phidget detached)");
00463
00464 exit:
00465 if(fptrJavaDetachCurrentThread)
00466 fptrJavaDetachCurrentThread();
00467 phid->writeStopFlag = FALSE;
00468 phid->writeThread.thread_status = FALSE;
00469 return (CThread_func_return_t)(size_t)result;
00470 }
00471
00472 int
00473 CThread_create(CThread *cp, CThread_func_t fp, CThread_func_arg_t arg)
00474 {
00475 #ifdef _WINDOWS
00476 initializeThreadSecurityAttributes();
00477 cp->m_ThreadHandle = CreateThread(pSA, 0, (LPTHREAD_START_ROUTINE)fp, arg, 0, &cp->m_ThreadIdentifier);
00478 if(cp->m_ThreadHandle) return EPHIDGET_OK;
00479 else return GetLastError();
00480 #else
00481 return pthread_create(&cp->m_ThreadHandle, NULL, fp, arg);
00482 #endif
00483 }
00484
00485 int
00486 CThread_create_detached(CThread *cp, CThread_func_t fp, CThread_func_arg_t arg)
00487 {
00488 #ifdef _WINDOWS
00489 cp->m_ThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)fp, arg, 0, &cp->m_ThreadIdentifier);
00490 if(cp->m_ThreadHandle) return EPHIDGET_OK;
00491 else return GetLastError();
00492 #else
00493 pthread_attr_t attr;
00494 int err;
00495 if((err = pthread_attr_init(&attr)) == 0)
00496 {
00497 if((err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) == 0)
00498 {
00499 return pthread_create(&cp->m_ThreadHandle, &attr, fp, arg);
00500 }
00501 else
00502 {
00503 LOG(PHIDGET_LOG_ERROR, "pthread_attr_setdetachstate failed with error: %d",err);
00504 return err;
00505 }
00506 }
00507 else
00508 {
00509 LOG(PHIDGET_LOG_ERROR, "pthread_attr_init failed with error: %d",err);
00510 return err;
00511 }
00512 #endif
00513 }
00514
00515 int
00516 CThread_is_my_thread(CThread cp)
00517 {
00518 #ifdef _WINDOWS
00519 return (cp.m_ThreadIdentifier == GetCurrentThreadId());
00520 #else
00521 return pthread_equal(cp.m_ThreadHandle, pthread_self());
00522 #endif
00523 }
00524
00525 void
00526 CThread_join(CThread *cp)
00527 {
00528 #ifdef _WINDOWS
00529 DWORD ec;
00530
00531 while (GetExitCodeThread(cp->m_ThreadHandle, &ec) && ec == STILL_ACTIVE)
00532 SLEEP(10);
00533 CloseHandle(cp->m_ThreadHandle);
00534 cp->m_ThreadHandle = NULL;
00535
00536 #else
00537 if (cp->thread_status == TRUE)
00538 pthread_join(cp->m_ThreadHandle, 0);
00539 #endif
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552 int
00553 CThread_mutex_init(CThread_mutex_t *mp)
00554 {
00555 #ifdef _WINDOWS
00556 InitializeCriticalSection(mp);
00557 return 1;
00558 #else
00559 return pthread_mutex_init(mp, NULL) == 0;
00560 #endif
00561 }
00562
00563 int
00564 CThread_mutex_destroy(CThread_mutex_t *mp)
00565 {
00566 #ifdef _WINDOWS
00567 DeleteCriticalSection(mp);
00568 return 1;
00569 #else
00570 return pthread_mutex_destroy(mp) == 0;
00571 #endif
00572 }
00573
00574 void
00575 CThread_mutex_lock(CThread_mutex_t *mp)
00576 {
00577 #ifdef _WINDOWS
00578 EnterCriticalSection(mp);
00579 #else
00580 pthread_mutex_lock(mp);
00581 #endif
00582 }
00583
00584 void
00585 CThread_mutex_unlock(CThread_mutex_t *mp)
00586 {
00587 #ifdef _WINDOWS
00588 LeaveCriticalSection(mp);
00589 #else
00590 pthread_mutex_unlock(mp);
00591 #endif
00592 }
00593
00594 void CThread_create_event(EVENT *ev)
00595 {
00596 #ifdef _WINDOWS
00597 *ev = CreateEvent(NULL, FALSE, FALSE, NULL);
00598 #else
00599 pthread_mutex_init(&ev->mutex, NULL);
00600 pthread_cond_init(&ev->condition, NULL);
00601 ev->ready_to_go = PFALSE;
00602 #endif
00603 }
00604
00605 int CThread_destroy_event(EVENT *ev)
00606 {
00607 #ifdef _WINDOWS
00608 return CloseHandle(*ev);
00609 #else
00610 if(pthread_mutex_destroy(&ev->mutex)) return 0;
00611 if(pthread_cond_destroy(&ev->condition)) return 0;
00612 return 1;
00613 #endif
00614 }
00615
00616 int CThread_wait_on_event(EVENT *ev, EVENT_TIME time)
00617 {
00618 #ifdef _WINDOWS
00619 return WaitForSingleObject(*ev, time);
00620 #else
00621 int retval;
00622 struct timespec timeout;
00623 struct timeval now;
00624
00625
00626 pthread_mutex_lock(&ev->mutex);
00627
00628
00629
00630 if(ev->ready_to_go == PFALSE)
00631 {
00632 if(time == INFINITE)
00633 retval = pthread_cond_wait(&ev->condition, &ev->mutex);
00634 else {
00635 gettimeofday(&now,0);
00636 timeout.tv_sec = now.tv_sec + time/1000;
00637 timeout.tv_nsec = now.tv_usec*1000 + (time%1000 * 1000000);
00638 if(timeout.tv_nsec >= 1000000000)
00639 {
00640 timeout.tv_sec++;
00641 timeout.tv_nsec -= 1000000000;
00642 }
00643 retval = pthread_cond_timedwait(&ev->condition, &ev->mutex, &timeout);
00644 }
00645
00646 switch(retval)
00647 {
00648 case ETIMEDOUT:
00649 pthread_mutex_unlock(&ev->mutex);
00650 return WAIT_TIMEOUT;
00651 case 0:
00652 pthread_mutex_unlock(&ev->mutex);
00653 return WAIT_OBJECT_0;
00654 case EINVAL:
00655 pthread_mutex_unlock(&ev->mutex);
00656 return WAIT_FAILED;
00657 default:
00658 pthread_mutex_unlock(&ev->mutex);
00659 return WAIT_FAILED;
00660 }
00661 }
00662 pthread_mutex_unlock(&ev->mutex);
00663 return WAIT_OBJECT_0;
00664 #endif
00665 }
00666
00667 void CThread_reset_event(EVENT *ev)
00668 {
00669 #ifdef _WINDOWS
00670 ResetEvent(*ev);
00671 #else
00672
00673 pthread_mutex_lock(&ev->mutex);
00674 ev->ready_to_go = PFALSE;
00675 pthread_mutex_unlock(&ev->mutex);
00676 #endif
00677 }
00678
00679 void CThread_set_event(EVENT *ev)
00680 {
00681 #ifdef _WINDOWS
00682 SetEvent(*ev);
00683 #else
00684
00685 pthread_mutex_lock(&ev->mutex);
00686 ev->ready_to_go = PTRUE;
00687
00688 pthread_cond_signal(&ev->condition);
00689 pthread_mutex_unlock(&ev->mutex);
00690
00691 #endif
00692 }
00693