src/osd/sdl/sdlsync.c
| r2146 | r2147 | |
| 41 | 41 | #define pthread_self _gettid |
| 42 | 42 | #endif |
| 43 | 43 | |
| 44 | #if THREAD_COOPERATIVE |
| 45 | typedef struct _hidden_mutex_t hidden_mutex_t; |
| 46 | struct _hidden_mutex_t { |
| 47 | pthread_mutex_t id; |
| 48 | }; |
| 49 | #else |
| 44 | 50 | struct _osd_lock { |
| 45 | 51 | volatile pthread_t holder; |
| 46 | 52 | INT32 count; |
| r2146 | r2147 | |
| 50 | 56 | INT8 padding[56]; // A bit more padding |
| 51 | 57 | #endif |
| 52 | 58 | }; |
| 59 | #endif |
| 53 | 60 | |
| 54 | 61 | #ifndef SDLMAME_OS2 |
| 55 | 62 | struct _osd_event { |
| r2146 | r2147 | |
| 69 | 76 | pthread_t thread; |
| 70 | 77 | }; |
| 71 | 78 | |
| 79 | |
| 80 | #if THREAD_COOPERATIVE |
| 81 | |
| 82 | //============================================================ |
| 83 | // osd_lock_alloc |
| 84 | //============================================================ |
| 85 | |
| 86 | osd_lock *osd_lock_alloc(void) |
| 87 | { |
| 88 | hidden_mutex_t *mutex; |
| 89 | pthread_mutexattr_t mtxattr; |
| 90 | |
| 91 | mutex = (hidden_mutex_t *)calloc(1, sizeof(hidden_mutex_t)); |
| 92 | |
| 93 | pthread_mutexattr_init(&mtxattr); |
| 94 | pthread_mutexattr_settype(&mtxattr, PTHREAD_MUTEX_RECURSIVE); |
| 95 | pthread_mutex_init(&mutex->id, &mtxattr); |
| 96 | |
| 97 | return (osd_lock *)mutex; |
| 98 | } |
| 99 | |
| 100 | //============================================================ |
| 101 | // osd_lock_acquire |
| 102 | //============================================================ |
| 103 | |
| 104 | void osd_lock_acquire(osd_lock *lock) |
| 105 | { |
| 106 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 107 | int r; |
| 108 | |
| 109 | r = pthread_mutex_lock(&mutex->id); |
| 110 | if (r==0) |
| 111 | return; |
| 112 | //mame_printf_error("Error on lock: %d: %s\n", r, strerror(r)); |
| 113 | } |
| 114 | |
| 115 | //============================================================ |
| 116 | // osd_lock_try |
| 117 | //============================================================ |
| 118 | |
| 119 | int osd_lock_try(osd_lock *lock) |
| 120 | { |
| 121 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 122 | int r; |
| 123 | |
| 124 | r = pthread_mutex_trylock(&mutex->id); |
| 125 | if (r==0) |
| 126 | return 1; |
| 127 | //if (r!=EBUSY) |
| 128 | // mame_printf_error("Error on trylock: %d: %s\n", r, strerror(r)); |
| 129 | return 0; |
| 130 | } |
| 131 | |
| 132 | //============================================================ |
| 133 | // osd_lock_release |
| 134 | //============================================================ |
| 135 | |
| 136 | void osd_lock_release(osd_lock *lock) |
| 137 | { |
| 138 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 139 | |
| 140 | pthread_mutex_unlock(&mutex->id); |
| 141 | } |
| 142 | |
| 143 | //============================================================ |
| 144 | // osd_lock_free |
| 145 | //============================================================ |
| 146 | |
| 147 | void osd_lock_free(osd_lock *lock) |
| 148 | { |
| 149 | hidden_mutex_t *mutex = (hidden_mutex_t *) lock; |
| 150 | |
| 151 | pthread_mutex_unlock(&mutex->id); |
| 152 | pthread_mutex_destroy(&mutex->id); |
| 153 | free(mutex); |
| 154 | } |
| 155 | #else |
| 156 | |
| 72 | 157 | INLINE pthread_t osd_compare_exchange_pthread_t(pthread_t volatile *ptr, pthread_t compare, pthread_t exchange) |
| 73 | 158 | { |
| 74 | 159 | #ifdef PTR64 |
| r2146 | r2147 | |
| 227 | 312 | { |
| 228 | 313 | free(lock); |
| 229 | 314 | } |
| 315 | #endif |
| 230 | 316 | |
| 231 | | |
| 232 | 317 | //============================================================ |
| 233 | 318 | // osd_num_processors |
| 234 | 319 | //============================================================ |
| r2146 | r2147 | |
| 486 | 571 | } |
| 487 | 572 | |
| 488 | 573 | //============================================================ |
| 574 | // osd_thread_cpu_affinity |
| 575 | //============================================================ |
| 576 | |
| 577 | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) |
| 578 | { |
| 579 | cpu_set_t cmask; |
| 580 | pthread_t lthread; |
| 581 | int bitnum; |
| 582 | |
| 583 | CPU_ZERO(&cmask); |
| 584 | for (bitnum=0; bitnum<32; bitnum++) |
| 585 | if (mask & (1<<bitnum)) |
| 586 | CPU_SET(bitnum, &cmask); |
| 587 | |
| 588 | if (thread == NULL) |
| 589 | lthread = pthread_self(); |
| 590 | else |
| 591 | lthread = thread->thread; |
| 592 | |
| 593 | if (pthread_setaffinity_np(lthread, sizeof(cmask), &cmask) <0) |
| 594 | { |
| 595 | fprintf(stderr, "error %d setting cpu affinity to mask %08x", errno, mask); |
| 596 | return FALSE; |
| 597 | } |
| 598 | else |
| 599 | return TRUE; |
| 600 | } |
| 601 | |
| 602 | //============================================================ |
| 489 | 603 | // osd_thread_wait_free |
| 490 | 604 | //============================================================ |
| 491 | 605 | |
src/osd/sdl/sdlsync.h
| r2146 | r2147 | |
| 16 | 16 | |
| 17 | 17 | #ifndef SDLMAME_OS2 |
| 18 | 18 | |
| 19 | #define THREAD_COOPERATIVE (1) |
| 20 | |
| 19 | 21 | /*************************************************************************** |
| 20 | 22 | SYNCHRONIZATION INTERFACES - Events |
| 21 | 23 | ***************************************************************************/ |
| r2146 | r2147 | |
| 142 | 144 | -----------------------------------------------------------------------------*/ |
| 143 | 145 | int osd_thread_adjust_priority(osd_thread *thread, int adjust); |
| 144 | 146 | |
| 147 | /*----------------------------------------------------------------------------- |
| 148 | osd_thread_cpu_affinity: change cpu affinity of a thread |
| 145 | 149 | |
| 150 | Parameters: |
| 151 | |
| 152 | thread - A pointer to a previously created thread |
| 153 | or NULL for main thread |
| 154 | mask - bitmask to which cpus to bind |
| 155 | i.e. 0x01 1st cpu, 0x02, 2nd cpu, 0x04 3rd cpu |
| 156 | |
| 157 | Return value: |
| 158 | |
| 159 | TRUE on success, FALSE on failure |
| 160 | -----------------------------------------------------------------------------*/ |
| 161 | int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask); |
| 162 | |
| 146 | 163 | /*----------------------------------------------------------------------------- |
| 147 | 164 | osd_thread_wait_free: wait for thread to finish and free resources |
| 148 | 165 | |
src/osd/sdl/sdlwork.c
| r2146 | r2147 | |
| 40 | 40 | // PARAMETERS |
| 41 | 41 | //============================================================ |
| 42 | 42 | |
| 43 | | #define INFINITE (osd_ticks_per_second()*10000) |
| 43 | #define INFINITE (osd_ticks_per_second() * (osd_ticks_t) 10000) |
| 44 | #if THREAD_COOPERATIVE |
| 45 | //FIXME: depends on <THREADS>/<PHYS PROCESSORS> |
| 46 | #define SPIN_LOOP_TIME (osd_ticks_per_second() / 10000) |
| 47 | //#define SPIN_LOOP_TIME ((osd_ticks_t) 0) |
| 48 | #else |
| 44 | 49 | #define SPIN_LOOP_TIME (osd_ticks_per_second() / 1000) |
| 50 | #endif |
| 45 | 51 | |
| 46 | 52 | |
| 47 | | |
| 48 | 53 | //============================================================ |
| 49 | 54 | // MACROS |
| 50 | 55 | //============================================================ |
| r2146 | r2147 | |
| 68 | 73 | typedef struct _scalable_lock scalable_lock; |
| 69 | 74 | struct _scalable_lock |
| 70 | 75 | { |
| 71 | | struct |
| 72 | | { |
| 73 | | volatile INT32 haslock; // do we have the lock? |
| 74 | | INT32 filler[64/4-1]; // assumes a 64-byte cache line |
| 75 | | } slot[WORK_MAX_THREADS]; // one slot per thread |
| 76 | | volatile INT32 nextindex; // index of next slot to use |
| 76 | #if THREAD_COOPERATIVE |
| 77 | osd_lock *lock; |
| 78 | #else |
| 79 | struct |
| 80 | { |
| 81 | volatile INT32 haslock; // do we have the lock? |
| 82 | INT32 filler[64/4-1]; // assumes a 64-byte cache line |
| 83 | } slot[WORK_MAX_THREADS]; // one slot per thread |
| 84 | volatile INT32 nextindex; // index of next slot to use |
| 85 | #endif |
| 77 | 86 | }; |
| 78 | 87 | |
| 79 | 88 | |
| r2146 | r2147 | |
| 138 | 147 | //============================================================ |
| 139 | 148 | |
| 140 | 149 | static int effective_num_processors(void); |
| 150 | #if THREAD_COOPERATIVE |
| 151 | static UINT32 effective_cpu_mask(int index); |
| 152 | #endif |
| 141 | 153 | static void * worker_thread_entry(void *param); |
| 142 | 154 | static void worker_thread_process(osd_work_queue *queue, work_thread_info *thread); |
| 143 | 155 | |
| r2146 | r2147 | |
| 175 | 187 | |
| 176 | 188 | INLINE void scalable_lock_init(scalable_lock *lock) |
| 177 | 189 | { |
| 190 | #if THREAD_COOPERATIVE |
| 191 | lock->lock = osd_lock_alloc(); |
| 192 | #else |
| 178 | 193 | memset(lock, 0, sizeof(*lock)); |
| 179 | 194 | lock->slot[0].haslock = TRUE; |
| 195 | #endif |
| 180 | 196 | } |
| 181 | 197 | |
| 182 | 198 | |
| 183 | 199 | INLINE INT32 scalable_lock_acquire(scalable_lock *lock) |
| 184 | 200 | { |
| 201 | #if THREAD_COOPERATIVE |
| 202 | osd_lock_acquire(lock->lock); |
| 203 | return 0; |
| 204 | #else |
| 185 | 205 | INT32 myslot = (atomic_increment32(&lock->nextindex) - 1) & (WORK_MAX_THREADS - 1); |
| 186 | 206 | |
| 187 | 207 | #if defined(__i386__) || defined(__x86_64__) |
| r2146 | r2147 | |
| 234 | 254 | } |
| 235 | 255 | #endif |
| 236 | 256 | return myslot; |
| 257 | #endif |
| 237 | 258 | } |
| 238 | 259 | |
| 239 | 260 | |
| 240 | 261 | INLINE void scalable_lock_release(scalable_lock *lock, INT32 myslot) |
| 241 | 262 | { |
| 263 | #if THREAD_COOPERATIVE |
| 264 | osd_lock_release(lock->lock); |
| 265 | return; |
| 266 | #else |
| 242 | 267 | #if defined(__i386__) || defined(__x86_64__) |
| 243 | 268 | register INT32 tmp = TRUE; |
| 244 | 269 | __asm__ __volatile__ ( |
| r2146 | r2147 | |
| 253 | 278 | #else |
| 254 | 279 | osd_exchange32(&lock->slot[(myslot + 1) & (WORK_MAX_THREADS - 1)].haslock, TRUE); |
| 255 | 280 | #endif |
| 281 | #endif |
| 256 | 282 | } |
| 257 | 283 | |
| 284 | INLINE void scalable_lock_free(scalable_lock *lock) |
| 285 | { |
| 286 | #if THREAD_COOPERATIVE |
| 287 | osd_lock_free(lock->lock); |
| 288 | #endif |
| 289 | } |
| 258 | 290 | |
| 291 | |
| 292 | |
| 259 | 293 | //============================================================ |
| 260 | 294 | // osd_work_queue_alloc |
| 261 | 295 | //============================================================ |
| r2146 | r2147 | |
| 326 | 360 | osd_thread_adjust_priority(thread->handle, 0); // TODO: specify appropriate priority |
| 327 | 361 | else |
| 328 | 362 | osd_thread_adjust_priority(thread->handle, 0); // TODO: specify appropriate priority |
| 363 | |
| 364 | #if THREAD_COOPERATIVE |
| 365 | // Bind main thread to cpu 0 |
| 366 | osd_thread_cpu_affinity(NULL, effective_cpu_mask(0)); |
| 367 | |
| 368 | if (flags & WORK_QUEUE_FLAG_IO) |
| 369 | osd_thread_cpu_affinity(thread->handle, effective_cpu_mask(1)); |
| 370 | else |
| 371 | osd_thread_cpu_affinity(thread->handle, effective_cpu_mask(2+threadnum) ); |
| 372 | #endif |
| 329 | 373 | } |
| 330 | 374 | |
| 331 | 375 | // start a timer going for "waittime" on the main thread |
| r2146 | r2147 | |
| 380 | 424 | // spin until we're done |
| 381 | 425 | begin_timing(thread->spintime); |
| 382 | 426 | while (queue->items != 0 && osd_ticks() < stopspin) |
| 383 | | osd_yield_processor(); |
| 427 | { |
| 428 | int spin = 10000; |
| 429 | while (--spin && queue->items != 0) |
| 430 | osd_yield_processor(); |
| 431 | } |
| 384 | 432 | end_timing(thread->spintime); |
| 385 | 433 | |
| 386 | 434 | begin_timing(thread->waittime); |
| r2146 | r2147 | |
| 491 | 539 | printf("Spin loops = %9d\n", queue->spinloops); |
| 492 | 540 | #endif |
| 493 | 541 | |
| 542 | scalable_lock_free(&queue->lock); |
| 494 | 543 | // free the queue itself |
| 495 | 544 | free(queue); |
| 496 | 545 | } |
| r2146 | r2147 | |
| 668 | 717 | return osd_num_processors(); |
| 669 | 718 | } |
| 670 | 719 | |
| 720 | //============================================================ |
| 721 | // effective_cpu_mask |
| 722 | //============================================================ |
| 671 | 723 | |
| 724 | #if THREAD_COOPERATIVE |
| 725 | static UINT32 effective_cpu_mask(int index) |
| 726 | { |
| 727 | char *s; |
| 728 | char buf[5]; |
| 729 | UINT32 mask = 0xFFFF; |
| 730 | |
| 731 | s = getenv("OSDCPUMASKS"); |
| 732 | if (s != NULL && strcmp(s,"none")) |
| 733 | { |
| 734 | if (!strcmp(s,"auto")) |
| 735 | { |
| 736 | if (index<2) |
| 737 | mask = 0x01; /* main thread and io threads on cpu #0 */ |
| 738 | else |
| 739 | mask = (1 << (((index - 1) % (osd_num_processors() - 1)) + 1)); |
| 740 | } |
| 741 | else |
| 742 | { |
| 743 | if (strlen(s) % 4 != 0 || strlen(s) < (index+1)*4) |
| 744 | { |
| 745 | fprintf(stderr,"Invalid cpu mask: %s\n", s); |
| 746 | } |
| 747 | else |
| 748 | { |
| 749 | memcpy(buf,s+4*index,4); |
| 750 | buf[4] = 0; |
| 751 | if (sscanf(buf, "%x", &mask) != 1) |
| 752 | fprintf(stderr,"Invalid cpu mask element %d: %s\n", index, buf); |
| 753 | } |
| 754 | } |
| 755 | } |
| 756 | return mask; |
| 757 | } |
| 758 | #endif |
| 759 | |
| 672 | 760 | //============================================================ |
| 673 | 761 | // worker_thread_entry |
| 674 | 762 | //============================================================ |
| r2146 | r2147 | |
| 711 | 799 | begin_timing(thread->spintime); |
| 712 | 800 | stopspin = osd_ticks() + SPIN_LOOP_TIME; |
| 713 | 801 | while (queue->list == NULL && osd_ticks() < stopspin) |
| 714 | | osd_yield_processor(); |
| 802 | { |
| 803 | int spin = 10000; |
| 804 | while (--spin && queue->list == NULL) |
| 805 | osd_yield_processor(); |
| 806 | } |
| 715 | 807 | end_timing(thread->spintime); |
| 716 | 808 | } |
| 717 | 809 | |