trunk/src/osd/windows/winsync.c
| r32097 | r32098 | |
| 36 | 36 | CRITICAL_SECTION critsect; |
| 37 | 37 | }; |
| 38 | 38 | |
| 39 | struct osd_event |
| 40 | { |
| 41 | void * ptr; |
| 42 | }; |
| 43 | |
| 39 | 44 | struct osd_scalable_lock |
| 40 | 45 | { |
| 41 | 46 | #if USE_SCALABLE_LOCKS |
| r32097 | r32098 | |
| 185 | 190 | } |
| 186 | 191 | |
| 187 | 192 | //============================================================ |
| 193 | // osd_event_alloc |
| 194 | //============================================================ |
| 195 | |
| 196 | osd_event *osd_event_alloc(int manualreset, int initialstate) |
| 197 | { |
| 198 | return (osd_event *) CreateEvent(NULL, manualreset, initialstate, NULL); |
| 199 | } |
| 200 | |
| 201 | //============================================================ |
| 202 | // osd_event_free |
| 203 | //============================================================ |
| 204 | |
| 205 | void osd_event_free(osd_event *event) |
| 206 | { |
| 207 | CloseHandle((HANDLE) event); |
| 208 | } |
| 209 | |
| 210 | //============================================================ |
| 211 | // osd_event_set |
| 212 | //============================================================ |
| 213 | |
| 214 | void osd_event_set(osd_event *event) |
| 215 | { |
| 216 | SetEvent((HANDLE) event); |
| 217 | } |
| 218 | |
| 219 | //============================================================ |
| 220 | // osd_event_reset |
| 221 | //============================================================ |
| 222 | |
| 223 | void osd_event_reset(osd_event *event) |
| 224 | { |
| 225 | ResetEvent((HANDLE) event); |
| 226 | } |
| 227 | |
| 228 | //============================================================ |
| 229 | // osd_event_wait |
| 230 | //============================================================ |
| 231 | |
| 232 | int osd_event_wait(osd_event *event, osd_ticks_t timeout) |
| 233 | { |
| 234 | int ret = WaitForSingleObject((HANDLE) event, timeout * 1000 / osd_ticks_per_second()); |
| 235 | return ( ret == WAIT_OBJECT_0); |
| 236 | } |
| 237 | |
| 238 | //============================================================ |
| 188 | 239 | // Scalable Locks |
| 189 | 240 | //============================================================ |
| 190 | 241 | |
trunk/src/osd/windows/winsync.h
| r32097 | r32098 | |
| 10 | 10 | #ifndef __WINSYNC__ |
| 11 | 11 | #define __WINSYNC__ |
| 12 | 12 | |
| 13 | /*************************************************************************** |
| 14 | SYNCHRONIZATION INTERFACES - Events |
| 15 | ***************************************************************************/ |
| 16 | |
| 17 | /* osd_event is an opaque type which represents a setable/resetable event */ |
| 18 | |
| 19 | struct osd_event; |
| 20 | |
| 21 | |
| 22 | /*----------------------------------------------------------------------------- |
| 23 | osd_lock_event_alloc: allocate a new event |
| 24 | |
| 25 | Parameters: |
| 26 | |
| 27 | manualreset - boolean. If true, the event will be automatically set |
| 28 | to non-signalled after a thread successfully waited for |
| 29 | it. |
| 30 | initialstate - boolean. If true, the event is signalled initially. |
| 31 | |
| 32 | Return value: |
| 33 | |
| 34 | A pointer to the allocated event. |
| 35 | -----------------------------------------------------------------------------*/ |
| 36 | osd_event *osd_event_alloc(int manualreset, int initialstate); |
| 37 | |
| 38 | |
| 39 | /*----------------------------------------------------------------------------- |
| 40 | osd_event_wait: wait for an event to be signalled |
| 41 | |
| 42 | Parameters: |
| 43 | |
| 44 | event - The event to wait for. If the event is in signalled state, the |
| 45 | function returns immediately. If not it will wait for the event |
| 46 | to become signalled. |
| 47 | timeout - timeout in osd_ticks |
| 48 | |
| 49 | Return value: |
| 50 | |
| 51 | TRUE: The event was signalled |
| 52 | FALSE: A timeout occurred |
| 53 | -----------------------------------------------------------------------------*/ |
| 54 | int osd_event_wait(osd_event *event, osd_ticks_t timeout); |
| 55 | |
| 56 | |
| 57 | /*----------------------------------------------------------------------------- |
| 58 | osd_event_reset: reset an event to non-signalled state |
| 59 | |
| 60 | Parameters: |
| 61 | |
| 62 | event - The event to set to non-signalled state |
| 63 | |
| 64 | Return value: |
| 65 | |
| 66 | None |
| 67 | -----------------------------------------------------------------------------*/ |
| 68 | void osd_event_reset(osd_event *event); |
| 69 | |
| 70 | |
| 71 | /*----------------------------------------------------------------------------- |
| 72 | osd_event_set: set an event to signalled state |
| 73 | |
| 74 | Parameters: |
| 75 | |
| 76 | event - The event to set to signalled state |
| 77 | |
| 78 | Return value: |
| 79 | |
| 80 | None |
| 81 | |
| 82 | Notes: |
| 83 | |
| 84 | All threads waiting for the event will be signalled. |
| 85 | -----------------------------------------------------------------------------*/ |
| 86 | void osd_event_set(osd_event *event); |
| 87 | |
| 88 | |
| 89 | /*----------------------------------------------------------------------------- |
| 90 | osd_event_free: free the memory and resources associated with an osd_event |
| 91 | |
| 92 | Parameters: |
| 93 | |
| 94 | event - a pointer to a previously allocated osd_event. |
| 95 | |
| 96 | Return value: |
| 97 | |
| 98 | None. |
| 99 | -----------------------------------------------------------------------------*/ |
| 100 | void osd_event_free(osd_event *event); |
| 101 | |
| 13 | 102 | //============================================================ |
| 14 | 103 | // Scalable Locks |
| 15 | 104 | //============================================================ |
trunk/src/osd/windows/winwork.c
| r32097 | r32098 | |
| 83 | 83 | { |
| 84 | 84 | osd_work_queue * queue; // pointer back to the queue |
| 85 | 85 | HANDLE handle; // handle to the thread |
| 86 | | HANDLE wakeevent; // wake event for the thread |
| 86 | osd_event * wakeevent; // wake event for the thread |
| 87 | 87 | volatile INT32 active; // are we actively processing work? |
| 88 | 88 | |
| 89 | 89 | #if KEEP_STATISTICS |
| r32097 | r32098 | |
| 109 | 109 | UINT32 threads; // number of threads in this queue |
| 110 | 110 | UINT32 flags; // creation flags |
| 111 | 111 | work_thread_info * thread; // array of thread information |
| 112 | | HANDLE doneevent; // event signalled when work is complete |
| 112 | osd_event * doneevent; // event signalled when work is complete |
| 113 | 113 | |
| 114 | 114 | #if KEEP_STATISTICS |
| 115 | 115 | volatile INT32 itemsqueued; // total items queued |
| r32097 | r32098 | |
| 127 | 127 | osd_work_callback callback; // callback function |
| 128 | 128 | void * param; // callback parameter |
| 129 | 129 | void * result; // callback result |
| 130 | | HANDLE event; // event signalled when complete |
| 130 | osd_event * event; // event signalled when complete |
| 131 | 131 | UINT32 flags; // creation flags |
| 132 | 132 | volatile INT32 done; // is the item done? |
| 133 | 133 | }; |
| r32097 | r32098 | |
| 169 | 169 | queue->flags = flags; |
| 170 | 170 | |
| 171 | 171 | // allocate events for the queue |
| 172 | | queue->doneevent = CreateEvent(NULL, TRUE, TRUE, NULL); // manual reset, signalled |
| 172 | queue->doneevent = osd_event_alloc(TRUE, TRUE); // manual reset, signalled |
| 173 | 173 | if (queue->doneevent == NULL) |
| 174 | 174 | goto error; |
| 175 | 175 | |
| r32097 | r32098 | |
| 214 | 214 | thread->queue = queue; |
| 215 | 215 | |
| 216 | 216 | // create the per-thread wake event |
| 217 | | thread->wakeevent = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset, not signalled |
| 217 | thread->wakeevent = osd_event_alloc(FALSE, FALSE); // auto-reset, not signalled |
| 218 | 218 | if (thread->wakeevent == NULL) |
| 219 | 219 | goto error; |
| 220 | 220 | |
| r32097 | r32098 | |
| 295 | 295 | } |
| 296 | 296 | |
| 297 | 297 | // reset our done event and double-check the items before waiting |
| 298 | | ResetEvent(queue->doneevent); |
| 298 | osd_event_reset(queue->doneevent); |
| 299 | 299 | atomic_exchange32(&queue->waiting, TRUE); |
| 300 | 300 | if (queue->items != 0) |
| 301 | | WaitForSingleObject(queue->doneevent, timeout * 1000 / osd_ticks_per_second()); |
| 301 | osd_event_wait(queue->doneevent, timeout); |
| 302 | 302 | atomic_exchange32(&queue->waiting, FALSE); |
| 303 | 303 | |
| 304 | 304 | // return TRUE if we actually hit 0 |
| r32097 | r32098 | |
| 326 | 326 | { |
| 327 | 327 | work_thread_info *thread = &queue->thread[threadnum]; |
| 328 | 328 | if (thread->wakeevent != NULL) |
| 329 | | SetEvent(thread->wakeevent); |
| 329 | osd_event_set(thread->wakeevent); |
| 330 | 330 | } |
| 331 | 331 | |
| 332 | 332 | // wait for all the threads to go away |
| r32097 | r32098 | |
| 343 | 343 | |
| 344 | 344 | // clean up the wake event |
| 345 | 345 | if (thread->wakeevent != NULL) |
| 346 | | CloseHandle(thread->wakeevent); |
| 346 | osd_event_free(thread->wakeevent); |
| 347 | 347 | } |
| 348 | 348 | |
| 349 | 349 | #if KEEP_STATISTICS |
| r32097 | r32098 | |
| 368 | 368 | |
| 369 | 369 | // free all the events |
| 370 | 370 | if (queue->doneevent != NULL) |
| 371 | | CloseHandle(queue->doneevent); |
| 371 | osd_event_free(queue->doneevent); |
| 372 | 372 | |
| 373 | 373 | // free all items in the free list |
| 374 | 374 | while (queue->free != NULL) |
| r32097 | r32098 | |
| 376 | 376 | osd_work_item *item = (osd_work_item *)queue->free; |
| 377 | 377 | queue->free = item->next; |
| 378 | 378 | if (item->event != NULL) |
| 379 | | CloseHandle(item->event); |
| 379 | osd_event_free(item->event); |
| 380 | 380 | osd_free(item); |
| 381 | 381 | } |
| 382 | 382 | |
| r32097 | r32098 | |
| 386 | 386 | osd_work_item *item = (osd_work_item *)queue->list; |
| 387 | 387 | queue->list = item->next; |
| 388 | 388 | if (item->event != NULL) |
| 389 | | CloseHandle(item->event); |
| 389 | osd_event_free(item->event); |
| 390 | 390 | osd_free(item); |
| 391 | 391 | } |
| 392 | 392 | |
| r32097 | r32098 | |
| 474 | 474 | // if this thread is not active, wake him up |
| 475 | 475 | if (!thread->active) |
| 476 | 476 | { |
| 477 | | SetEvent(thread->wakeevent); |
| 477 | osd_event_set(thread->wakeevent); |
| 478 | 478 | add_to_stat(&queue->setevents, 1); |
| 479 | 479 | |
| 480 | 480 | // for non-shared, the first one we find is good enough |
| r32097 | r32098 | |
| 505 | 505 | |
| 506 | 506 | // if we don't have an event, create one |
| 507 | 507 | if (item->event == NULL) |
| 508 | | item->event = CreateEvent(NULL, TRUE, FALSE, NULL); // manual reset, not signalled |
| 508 | item->event = osd_event_alloc(TRUE, FALSE); // manual reset, not signalled |
| 509 | 509 | else |
| 510 | | ResetEvent(item->event); |
| 510 | osd_event_reset(item->event); |
| 511 | 511 | |
| 512 | 512 | // if we don't have an event, we need to spin (shouldn't ever really happen) |
| 513 | 513 | if (item->event == NULL) |
| r32097 | r32098 | |
| 519 | 519 | |
| 520 | 520 | // otherwise, block on the event until done |
| 521 | 521 | else if (!item->done) |
| 522 | | WaitForSingleObject(item->event, timeout * 1000 / osd_ticks_per_second()); |
| 522 | osd_event_wait(item->event, timeout); |
| 523 | 523 | |
| 524 | 524 | // return TRUE if the refcount actually hit 0 |
| 525 | 525 | return item->done; |
| r32097 | r32098 | |
| 598 | 598 | // loop until we exit |
| 599 | 599 | for ( ;; ) |
| 600 | 600 | { |
| 601 | // block waiting for work or exit |
| 601 | 602 | // bail on exit, and only wait if there are no pending items in queue |
| 602 | 603 | if (!queue->exiting && queue->list == NULL) |
| 603 | 604 | { |
| 604 | 605 | begin_timing(thread->waittime); |
| 605 | | WaitForSingleObject(thread->wakeevent, INFINITE); |
| 606 | osd_event_wait(thread->wakeevent, INFINITE); |
| 606 | 607 | end_timing(thread->waittime); |
| 607 | 608 | } |
| 608 | 609 | if (queue->exiting) |
| r32097 | r32098 | |
| 695 | 696 | // set the result and signal the event |
| 696 | 697 | else if (item->event != NULL) |
| 697 | 698 | { |
| 698 | | SetEvent(item->event); |
| 699 | osd_event_set(item->event); |
| 699 | 700 | add_to_stat(&item->queue->setevents, 1); |
| 700 | 701 | } |
| 701 | 702 | |
| r32097 | r32098 | |
| 708 | 709 | // we don't need to set the doneevent for multi queues because they spin |
| 709 | 710 | if (queue->waiting) |
| 710 | 711 | { |
| 711 | | SetEvent(queue->doneevent); |
| 712 | osd_event_set(queue->doneevent); |
| 712 | 713 | add_to_stat(&queue->setevents, 1); |
| 713 | 714 | } |
| 714 | 715 | |