//============================================================ // // sdlsync.c - SDL core synchronization functions // // Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team. // Visit http://mamedev.org for licensing and usage restrictions. // // SDLMAME by Olivier Galibert and R. Belmont // //============================================================ #include "SDL/SDL.h" // standard C headers #include // MAME headers #include "osdcore.h" #include "osinline.h" #include "sdlsync.h" #include "eminline.h" #define VERBOSE (0) #if VERBOSE #define LOG( x ) do { printf x; printf("\n"); } while (0) #else #define LOG( x ) #endif typedef struct _hidden_mutex_t hidden_mutex_t; struct _hidden_mutex_t { SDL_mutex * id; volatile INT32 locked; volatile INT32 threadid; }; struct _osd_event { SDL_mutex * mutex; SDL_cond * cond; volatile INT32 autoreset; volatile INT32 signalled; }; //============================================================ // TYPE DEFINITIONS //============================================================ struct _osd_thread { SDL_Thread * thread; osd_thread_callback callback; void *param; }; struct _osd_scalable_lock { SDL_mutex * mutex; }; //============================================================ // Scalable Locks //============================================================ osd_scalable_lock *osd_scalable_lock_alloc(void) { osd_scalable_lock *lock; lock = (osd_scalable_lock *)calloc(1, sizeof(*lock)); lock->mutex = SDL_CreateMutex(); return lock; } INT32 osd_scalable_lock_acquire(osd_scalable_lock *lock) { SDL_mutexP(lock->mutex); return 0; } void osd_scalable_lock_release(osd_scalable_lock *lock, INT32 myslot) { SDL_mutexV(lock->mutex); } void osd_scalable_lock_free(osd_scalable_lock *lock) { SDL_DestroyMutex(lock->mutex); free(lock); } //============================================================ // osd_lock_alloc //============================================================ osd_lock *osd_lock_alloc(void) { hidden_mutex_t *mutex; mutex = (hidden_mutex_t *)calloc(1, sizeof(hidden_mutex_t)); mutex->id = SDL_CreateMutex(); return (osd_lock *)mutex; } //============================================================ // osd_lock_acquire //============================================================ void osd_lock_acquire(osd_lock *lock) { hidden_mutex_t *mutex = (hidden_mutex_t *) lock; LOG(("osd_lock_acquire")); /* get the lock */ mutex->locked++; /* signal that we are *about* to lock - prevent osd_lock_try */ SDL_mutexP(mutex->id); mutex->threadid = SDL_ThreadID(); } //============================================================ // osd_lock_try //============================================================ int osd_lock_try(osd_lock *lock) { hidden_mutex_t *mutex = (hidden_mutex_t *) lock; LOG(("osd_lock_try")); if (mutex->locked && mutex->threadid == SDL_ThreadID()) { /* get the lock */ SDL_mutexP(mutex->id); mutex->locked++; mutex->threadid = SDL_ThreadID(); return 1; } else if ((mutex->locked == 0)) { /* get the lock */ mutex->locked++; SDL_mutexP(mutex->id); mutex->threadid = SDL_ThreadID(); return 1; } else { /* fail */ return 0; } } //============================================================ // osd_lock_release //============================================================ void osd_lock_release(osd_lock *lock) { hidden_mutex_t *mutex = (hidden_mutex_t *) lock; LOG(("osd_lock_release")); mutex->locked--; if (mutex->locked == 0) mutex->threadid = -1; SDL_mutexV(mutex->id); } //============================================================ // osd_lock_free //============================================================ void osd_lock_free(osd_lock *lock) { hidden_mutex_t *mutex = (hidden_mutex_t *) lock; LOG(("osd_lock_free")); //osd_lock_release(lock); SDL_DestroyMutex(mutex->id); free(mutex); } //============================================================ // osd_event_alloc //============================================================ osd_event *osd_event_alloc(int manualreset, int initialstate) { osd_event *ev; ev = (osd_event *)calloc(1, sizeof(osd_event)); ev->mutex = SDL_CreateMutex(); ev->cond = SDL_CreateCond(); ev->signalled = initialstate; ev->autoreset = !manualreset; return ev; } //============================================================ // osd_event_free //============================================================ void osd_event_free(osd_event *event) { SDL_DestroyMutex(event->mutex); SDL_DestroyCond(event->cond); free(event); } //============================================================ // osd_event_set //============================================================ void osd_event_set(osd_event *event) { LOG(("osd_event_set")); SDL_mutexP(event->mutex); if (event->signalled == FALSE) { event->signalled = TRUE; if (event->autoreset) SDL_CondSignal(event->cond); else SDL_CondBroadcast(event->cond); } SDL_mutexV(event->mutex); } //============================================================ // osd_event_reset //============================================================ void osd_event_reset(osd_event *event) { LOG(("osd_event_reset")); SDL_mutexP(event->mutex); event->signalled = FALSE; SDL_mutexV(event->mutex); } //============================================================ // osd_event_wait //============================================================ int osd_event_wait(osd_event *event, osd_ticks_t timeout) { LOG(("osd_event_wait")); SDL_mutexP(event->mutex); if (!timeout) { if (!event->signalled) { SDL_mutexV(event->mutex); return FALSE; } } else { if (!event->signalled) { UINT64 msec = (timeout * 1000) / osd_ticks_per_second(); do { int ret = SDL_CondWaitTimeout(event->cond, event->mutex, msec); if ( ret == SDL_MUTEX_TIMEDOUT ) { if (!event->signalled) { SDL_mutexV(event->mutex); return FALSE; } else break; } if (ret == 0) break; printf("Error %d while waiting for pthread_cond_timedwait: %s\n", ret, strerror(ret)); } while (TRUE); } } if (event->autoreset) event->signalled = 0; SDL_mutexV(event->mutex); return TRUE; } //============================================================ // osd_thread_create //============================================================ static int worker_thread_entry(void *param) { osd_thread *thread = (osd_thread *) param; void *res; res = thread->callback(thread->param); #ifdef PTR64 return (int) (INT64) res; #else return (int) res; #endif } osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam) { osd_thread *thread; thread = (osd_thread *)calloc(1, sizeof(osd_thread)); thread->callback = callback; thread->param = cbparam; thread->thread = SDL_CreateThread(worker_thread_entry, thread); if ( thread->thread == NULL ) { free(thread); return NULL; } return thread; } //============================================================ // osd_thread_adjust_priority //============================================================ int osd_thread_adjust_priority(osd_thread *thread, int adjust) { return TRUE; } //============================================================ // osd_thread_cpu_affinity //============================================================ int osd_thread_cpu_affinity(osd_thread *thread, UINT32 mask) { return TRUE; } //============================================================ // osd_thread_wait_free //============================================================ void osd_thread_wait_free(osd_thread *thread) { int status; SDL_WaitThread(thread->thread, &status); free(thread); }