int SDL_TimerInit(void) { SDL_TimerData *data = &SDL_timer_data; if (!SDL_AtomicGet(&data->active)) { const char *name = "SDLTimer"; data->timermap_lock = SDL_CreateMutex(); if (!data->timermap_lock) { return -1; } data->sem = SDL_CreateSemaphore(0); if (!data->sem) { SDL_DestroyMutex(data->timermap_lock); return -1; } SDL_AtomicSet(&data->active, 1); /* Timer threads use a callback into the app, so we can't set a limited stack size here. */ data->thread = SDL_CreateThreadInternal(SDL_TimerThread, name, 0, data); if (!data->thread) { SDL_TimerQuit(); return -1; } SDL_AtomicSet(&data->nextID, 1); } return 0; }
static void XAUDIO2_WaitDevice(_THIS) { if (SDL_AtomicGet(&this->enabled)) { SDL_SemWait(this->hidden->semaphore); } }
SDL_bool SDL_RemoveTimer(SDL_TimerID id) { SDL_TimerData *data = &SDL_timer_data; SDL_TimerMap *prev, *entry; SDL_bool canceled = SDL_FALSE; /* Find the timer */ SDL_LockMutex(data->timermap_lock); prev = NULL; for (entry = data->timermap; entry; prev = entry, entry = entry->next) { if (entry->timerID == id) { if (prev) { prev->next = entry->next; } else { data->timermap = entry->next; } break; } } SDL_UnlockMutex(data->timermap_lock); if (entry) { if (!SDL_AtomicGet(&entry->timer->canceled)) { SDL_AtomicSet(&entry->timer->canceled, 1); canceled = SDL_TRUE; } SDL_free(entry); } return canceled; }
static SDL_bool DequeueEvent_LockFree(SDL_EventQueue *queue, SDL_Event *event) { SDL_EventQueueEntry *entry; unsigned queue_pos; unsigned entry_seq; int delta; SDL_bool status; #ifdef TEST_SPINLOCK_FIFO /* This is a gate so an external thread can lock the queue */ SDL_AtomicLock(&queue->lock); SDL_assert(SDL_AtomicGet(&queue->watcher) == 0); SDL_AtomicIncRef(&queue->rwcount); SDL_AtomicUnlock(&queue->lock); #endif queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos); for ( ; ; ) { entry = &queue->entries[queue_pos & WRAP_MASK]; entry_seq = (unsigned)SDL_AtomicGet(&entry->sequence); delta = (int)(entry_seq - (queue_pos + 1)); if (delta == 0) { /* The entry and the queue position match, try to increment the queue position */ if (SDL_AtomicCAS(&queue->dequeue_pos, (int)queue_pos, (int)(queue_pos+1))) { /* We own the object, fill it! */ *event = entry->event; SDL_AtomicSet(&entry->sequence, (int)(queue_pos+MAX_ENTRIES)); status = SDL_TRUE; break; } } else if (delta < 0) { /* We ran into an old queue entry, which means we've hit empty */ status = SDL_FALSE; break; } else { /* We ran into a new queue entry, get the new queue position */ queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos); } } #ifdef TEST_SPINLOCK_FIFO SDL_AtomicDecRef(&queue->rwcount); #endif return status; }
/* Pause (block) all non already paused audio devices by taking their mixer lock */ void ANDROIDAUDIO_PauseDevices(void) { /* TODO: Handle multiple devices? */ struct SDL_PrivateAudioData *private; if(audioDevice != NULL && audioDevice->hidden != NULL) { private = (struct SDL_PrivateAudioData *) audioDevice->hidden; if (SDL_AtomicGet(&audioDevice->paused)) { /* The device is already paused, leave it alone */ private->resume = SDL_FALSE; }
static void destroy(LuaThread *t) { (void)SDL_AtomicDecRef(&t->ref); if (SDL_AtomicGet(&t->ref) == 0) { lua_close(t->L); free(t); } }
static void PULSEAUDIO_PlayDevice(_THIS) { /* Write the audio data */ struct SDL_PrivateAudioData *h = this->hidden; if (SDL_AtomicGet(&this->enabled)) { if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) { SDL_OpenedAudioDeviceDisconnected(this); } } }
static void ALSA_PlayDevice(_THIS) { const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf; const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) * this->spec.channels; snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples); swizzle_alsa_channels(this, this->hidden->mixbuf, frames_left); while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) { int status; /* This wait is a work-around for a hang when USB devices are unplugged. Normally it should not result in any waiting, but in the case of a USB unplug, it serves as a way to join the playback thread after the timeout occurs */ status = ALSA_snd_pcm_wait(this->hidden->pcm_handle, 1000); if (status == 0) { /*fprintf(stderr, "ALSA timeout waiting for available buffer space\n");*/ SDL_OpenedAudioDeviceDisconnected(this); return; } status = ALSA_snd_pcm_writei(this->hidden->pcm_handle, sample_buf, frames_left); if (status < 0) { if (status == -EAGAIN) { /* Apparently snd_pcm_recover() doesn't handle this case - does it assume snd_pcm_wait() above? */ SDL_Delay(1); continue; } status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0); if (status < 0) { /* Hmm, not much we can do - abort */ fprintf(stderr, "ALSA write failed (unrecoverable): %s\n", ALSA_snd_strerror(status)); SDL_OpenedAudioDeviceDisconnected(this); return; } continue; } sample_buf += status * frame_size; frames_left -= status; } }
static int PULSEAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen) { struct SDL_PrivateAudioData *h = this->hidden; const void *data = NULL; size_t nbytes = 0; while (SDL_AtomicGet(&this->enabled)) { if (h->capturebuf != NULL) { const int cpy = SDL_min(buflen, h->capturelen); SDL_memcpy(buffer, h->capturebuf, cpy); /*printf("PULSEAUDIO: fed %d captured bytes\n", cpy);*/ h->capturebuf += cpy; h->capturelen -= cpy; if (h->capturelen == 0) { h->capturebuf = NULL; PULSEAUDIO_pa_stream_drop(h->stream); /* done with this fragment. */ } return cpy; /* new data, return it. */ } if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { SDL_OpenedAudioDeviceDisconnected(this); return -1; /* uhoh, pulse failed! */ } if (PULSEAUDIO_pa_stream_readable_size(h->stream) == 0) { continue; /* no data available yet. */ } /* a new fragment is available! */ PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes); SDL_assert(nbytes > 0); if (data == NULL) { /* NULL==buffer had a hole. Ignore that. */ PULSEAUDIO_pa_stream_drop(h->stream); /* drop this fragment. */ } else { /* store this fragment's data, start feeding it to SDL. */ /*printf("PULSEAUDIO: captured %d new bytes\n", (int) nbytes);*/ h->capturebuf = (const Uint8 *) data; h->capturelen = nbytes; } } return -1; /* not enabled? */ }
void Object::destroy() throw() { GC::collect_mutex.lock(); // If another thread just dereferenced a weak pointer to this // object, we might now have references. Now that we have the // lock, check the refcount again. if (SDL_AtomicGet(&refcount) > 0) { GC::collect_mutex.unlock(); return; } SDL_AtomicSet(&refcount, 0); untrack(); weakptrbase* cur = weak; weakptrbase* old; while (cur) { old = cur; cur = cur->next; old->set_ref(NULL); } // Avoid stack overflow. if (trashlevel < max_trashlevel) { ++trashlevel; delete this; if (trashlevel == 1) { while (!trashcan.empty()) { Object* op = static_cast<Object*>(trashcan.next); op->remove(); delete op; } } --trashlevel; } else { moveto(&trashcan); } GC::collect_mutex.unlock(); }
/* This function waits until it is possible to write a full sound buffer */ static void PULSEAUDIO_WaitDevice(_THIS) { struct SDL_PrivateAudioData *h = this->hidden; while (SDL_AtomicGet(&this->enabled)) { if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { SDL_OpenedAudioDeviceDisconnected(this); return; } if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) { return; } } }
static int ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen) { Uint8 *sample_buf = (Uint8 *) buffer; const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) * this->spec.channels; const int total_frames = buflen / frame_size; snd_pcm_uframes_t frames_left = total_frames; SDL_assert((buflen % frame_size) == 0); while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) { /* !!! FIXME: This works, but needs more testing before going live */ /* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */ int status = ALSA_snd_pcm_readi(this->hidden->pcm_handle, sample_buf, frames_left); if (status < 0) { /*printf("ALSA: capture error %d\n", status);*/ if (status == -EAGAIN) { /* Apparently snd_pcm_recover() doesn't handle this case - does it assume snd_pcm_wait() above? */ SDL_Delay(1); continue; } status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0); if (status < 0) { /* Hmm, not much we can do - abort */ fprintf(stderr, "ALSA read failed (unrecoverable): %s\n", ALSA_snd_strerror(status)); return -1; } continue; } /*printf("ALSA: captured %d bytes\n", status * frame_size);*/ sample_buf += status * frame_size; frames_left -= status; } swizzle_alsa_channels(this, buffer, total_frames - frames_left); return (total_frames - frames_left) * frame_size; }
/* This thread periodically locks the queue for no particular reason */ static int FIFO_Watcher(void* _data) { SDL_EventQueue *queue = (SDL_EventQueue *)_data; while (queue->active) { SDL_AtomicLock(&queue->lock); SDL_AtomicIncRef(&queue->watcher); while (SDL_AtomicGet(&queue->rwcount) > 0) { SDL_Delay(0); } /* Do queue manipulation here... */ SDL_AtomicDecRef(&queue->watcher); SDL_AtomicUnlock(&queue->lock); /* Wait a bit... */ SDL_Delay(1); } return 0; }
static int DSOUND_CaptureFromDevice(_THIS, void *buffer, int buflen) { struct SDL_PrivateAudioData *h = this->hidden; DWORD junk, cursor, ptr1len, ptr2len; VOID *ptr1, *ptr2; SDL_assert(buflen == this->spec.size); while (SDL_TRUE) { if (SDL_AtomicGet(&this->shutdown)) { /* in case the buffer froze... */ SDL_memset(buffer, this->spec.silence, buflen); return buflen; } if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) { return -1; } if ((cursor / this->spec.size) == h->lastchunk) { SDL_Delay(1); /* FIXME: find out how much time is left and sleep that long */ } else { break; } } if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * this->spec.size, this->spec.size, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) { return -1; } SDL_assert(ptr1len == this->spec.size); SDL_assert(ptr2 == NULL); SDL_assert(ptr2len == 0); SDL_memcpy(buffer, ptr1, ptr1len); if (IDirectSoundCaptureBuffer_Unlock(h->capturebuf, ptr1, ptr1len, ptr2, ptr2len) != DS_OK) { return -1; } h->lastchunk = (h->lastchunk + 1) % h->num_buffers; return ptr1len; }
/* Since XInput doesn't offer a way to vibrate for X time, we hook into * SDL_PumpEvents() to check if it's time to stop vibrating with some * frequency. * In practice, this works for 99% of use cases. But in an ideal world, * we do this in a separate thread so that: * - we aren't bound to when the app chooses to pump the event queue. * - we aren't adding more polling to the event queue * - we can emulate all the haptic effects correctly (start on a delay, * mix multiple effects, etc). * * Mostly, this is here to get rumbling to work, and all the other features * are absent in the XInput path for now. :( */ static int SDLCALL SDL_RunXInputHaptic(void *arg) { struct haptic_hwdata *hwdata = (struct haptic_hwdata *) arg; while (!SDL_AtomicGet(&hwdata->stopThread)) { SDL_Delay(50); SDL_LockMutex(hwdata->mutex); /* If we're currently running and need to stop... */ if (hwdata->stopTicks) { if ((hwdata->stopTicks != SDL_HAPTIC_INFINITY) && SDL_TICKS_PASSED(SDL_GetTicks(), hwdata->stopTicks)) { XINPUT_VIBRATION vibration = { 0, 0 }; hwdata->stopTicks = 0; XINPUTSETSTATE(hwdata->userid, &vibration); } } SDL_UnlockMutex(hwdata->mutex); } return 0; }
static void XAUDIO2_WaitDone(_THIS) { IXAudio2SourceVoice *source = this->hidden->source; XAUDIO2_VOICE_STATE state; SDL_assert(!SDL_AtomicGet(&this->enabled)); /* flag that stops playing. */ IXAudio2SourceVoice_Discontinuity(source); #if SDL_XAUDIO2_WIN8 IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED); #else IXAudio2SourceVoice_GetState(source, &state); #endif while (state.BuffersQueued > 0) { SDL_SemWait(this->hidden->semaphore); #if SDL_XAUDIO2_WIN8 IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED); #else IXAudio2SourceVoice_GetState(source, &state); #endif } }
static void XAUDIO2_PlayDevice(_THIS) { XAUDIO2_BUFFER buffer; Uint8 *mixbuf = this->hidden->mixbuf; Uint8 *nextbuf = this->hidden->nextbuf; const int mixlen = this->hidden->mixlen; IXAudio2SourceVoice *source = this->hidden->source; HRESULT result = S_OK; if (!SDL_AtomicGet(&this->enabled)) { /* shutting down? */ return; } /* Submit the next filled buffer */ SDL_zero(buffer); buffer.AudioBytes = mixlen; buffer.pAudioData = nextbuf; buffer.pContext = this; if (nextbuf == mixbuf) { nextbuf += mixlen; } else { nextbuf = mixbuf; } this->hidden->nextbuf = nextbuf; result = IXAudio2SourceVoice_SubmitSourceBuffer(source, &buffer, NULL); if (result == XAUDIO2_E_DEVICE_INVALIDATED) { /* !!! FIXME: possibly disconnected or temporary lost. Recover? */ } if (result != S_OK) { /* uhoh, panic! */ IXAudio2SourceVoice_FlushSourceBuffers(source); SDL_OpenedAudioDeviceDisconnected(this); } }
static void ALSA_PlayDevice(_THIS) { const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf; const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) * this->spec.channels; snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples); swizzle_alsa_channels(this, this->hidden->mixbuf, frames_left); while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) { /* !!! FIXME: This works, but needs more testing before going live */ /* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */ int status = ALSA_snd_pcm_writei(this->hidden->pcm_handle, sample_buf, frames_left); if (status < 0) { if (status == -EAGAIN) { /* Apparently snd_pcm_recover() doesn't handle this case - does it assume snd_pcm_wait() above? */ SDL_Delay(1); continue; } status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0); if (status < 0) { /* Hmm, not much we can do - abort */ fprintf(stderr, "ALSA write failed (unrecoverable): %s\n", ALSA_snd_strerror(status)); SDL_OpenedAudioDeviceDisconnected(this); return; } continue; } sample_buf += status * frame_size; frames_left -= status; } }
static void runAdder(void) { Uint32 start, end; int T=NThreads; start = SDL_GetTicks(); threadDone = SDL_CreateSemaphore(0); SDL_AtomicSet(&threadsRunning, NThreads); while (T--) SDL_CreateThread(adder, "Adder", NULL); while (SDL_AtomicGet(&threadsRunning) > 0) SDL_SemWait(threadDone); SDL_DestroySemaphore(threadDone); end = SDL_GetTicks(); printf("Finished in %f sec\n", (end - start) / 1000.f); }
JNIEXPORT jint JNICALL Java_com_libaldaron_LibAldaronActivity_nativeLaDraw(JNIEnv *env, jobject obj) { la_window_loop__(la_window); if(SDL_AtomicGet(&la_rmcexit) == 0) return 100; else return 0; }
/** * This is the main entry point of a native application that is using * android_native_app_glue. It runs in its own thread, with its own * event loop for receiving input events and doing other things. */ void android_main(struct android_app* state) { la_window_t* window = la_memory_allocate(sizeof(la_window_t)); int ident; int events; struct android_poll_source* source; // Make sure glue isn't stripped. app_dummy(); state->userData = window; state->onAppCmd = window_handle_cmd; state->onInputEvent = window_handle_input; window->app = state; // Prepare to monitor accelerometer window->sensorManager = ASensorManager_getInstance(); window->accelerometerSensor = ASensorManager_getDefaultSensor( window->sensorManager, ASENSOR_TYPE_ACCELEROMETER); window->sensorEventQueue = ASensorManager_createEventQueue( window->sensorManager, state->looper, LOOPER_ID_USER, NULL, NULL); // if (state->savedState != NULL) { // We are starting with a previous saved state; restore from it. // window->state = *(struct saved_state*)state->savedState; // } // Run main(): la_window = window; // TODO: is needed? SDL_AtomicSet(&la_rmcexit, 1); // Window thread ( Drawing + Events ). while (SDL_AtomicGet(&la_rmcexit)) { // Poll Events ident = ALooper_pollAll(0, NULL, &events, (void**)&source); // Process this event. if (source != NULL) { source->process(state, source); } // If a sensor has data, process it now. if (ident == LOOPER_ID_USER) { if (window->accelerometerSensor != NULL) { ASensorEvent event; while (ASensorEventQueue_getEvents( window->sensorEventQueue, &event, 1) > 0) { window->input.accel.x = event.acceleration.x; window->input.accel.y = event.acceleration.y; window->input.accel.z = event.acceleration.z; } } } // Run the cross-platform window loop. if(window->context) la_window_loop__(window); // Update the screen. la_port_swap_buffers(window); } la_print("port-android quitting...."); // The cross-platform window kill. la_window_kill__(window); // The window is being hidden or closed, clean it up. window_term_display(window); la_print("port-android quitted...."); exit(0); return; }
inline void GC::update_refs(GCList* containers) { for (GCList *gc = containers->next; gc != containers; gc = gc->next) { Object* op = static_cast<Object*>(gc); op->gc_refs = SDL_AtomicGet(&op->refcount); } }
Object::~Object() { --num_objects; if (SDL_AtomicGet(&refcount) > 0) cerr << "Foo! deleting object " << str() << " with references!"<<endl; }
void Object::track() throw() { GC::collect_mutex.lock(); if ((gc_refs == GC_TRACK_NOT_NEEDED) || !(gc_refs == GC_UNTRACKED || gc_refs == GC_NEW) || SDL_AtomicGet(&refcount) == -1) { GC::collect_mutex.unlock(); return; } generations[0].count++; // number of allocated GC objects if (generations[0].count > generations[0].threshold && GC::enabled && !GC::collecting && generations[0].threshold) { GC::collecting = true; GC::collect_generations(); GC::collecting = false; } gc_refs = GC_REACHABLE; next = &generations[0]; prev = generations[0].prev; prev->next = this; generations[0].prev = this; GC::collect_mutex.unlock(); }
static int SDL_TimerThread(void *_data) { SDL_TimerData *data = (SDL_TimerData *)_data; SDL_Timer *pending; SDL_Timer *current; SDL_Timer *freelist_head = NULL; SDL_Timer *freelist_tail = NULL; Uint32 tick, now, interval, delay; /* Threaded timer loop: * 1. Queue timers added by other threads * 2. Handle any timers that should dispatch this cycle * 3. Wait until next dispatch time or new timer arrives */ for ( ; ; ) { /* Pending and freelist maintenance */ SDL_AtomicLock(&data->lock); { /* Get any timers ready to be queued */ pending = data->pending; data->pending = NULL; /* Make any unused timer structures available */ if (freelist_head) { freelist_tail->next = data->freelist; data->freelist = freelist_head; } } SDL_AtomicUnlock(&data->lock); /* Sort the pending timers into our list */ while (pending) { current = pending; pending = pending->next; SDL_AddTimerInternal(data, current); } freelist_head = NULL; freelist_tail = NULL; /* Check to see if we're still running, after maintenance */ if (!SDL_AtomicGet(&data->active)) { break; } /* Initial delay if there are no timers */ delay = SDL_MUTEX_MAXWAIT; tick = SDL_GetTicks(); /* Process all the pending timers for this tick */ while (data->timers) { current = data->timers; if ((Sint32)(tick-current->scheduled) < 0) { /* Scheduled for the future, wait a bit */ delay = (current->scheduled - tick); break; } /* We're going to do something with this timer */ data->timers = current->next; if (SDL_AtomicGet(¤t->canceled)) { interval = 0; } else { interval = current->callback(current->interval, current->param); } if (interval > 0) { /* Reschedule this timer */ current->scheduled = tick + interval; SDL_AddTimerInternal(data, current); } else { if (!freelist_head) { freelist_head = current; } if (freelist_tail) { freelist_tail->next = current; } freelist_tail = current; SDL_AtomicSet(¤t->canceled, 1); } } /* Adjust the delay based on processing time */ now = SDL_GetTicks(); interval = (now - tick); if (interval > delay) { delay = 0; } else { delay -= interval; } /* Note that each time a timer is added, this will return immediately, but we process the timers added all at once. That's okay, it just means we run through the loop a few extra times. */ SDL_SemWaitTimeout(data->sem, delay); } return 0; }
static void RunEpicTest() { int b; atomicValue v; printf("\nepic test---------------------------------------\n\n"); printf("Size asserted to be >= 32-bit\n"); SDL_assert(sizeof(atomicValue)>=4); printf("Check static initializer\n"); v=SDL_AtomicGet(&good); SDL_assert(v==42); SDL_assert(bad==42); printf("Test negative values\n"); SDL_AtomicSet(&good, -5); v=SDL_AtomicGet(&good); SDL_assert(v==-5); printf("Verify maximum value\n"); SDL_AtomicSet(&good, CountTo); v=SDL_AtomicGet(&good); SDL_assert(v==CountTo); printf("Test compare and exchange\n"); b=SDL_AtomicCAS(&good, 500, 43); SDL_assert(!b); /* no swap since CountTo!=500 */ v=SDL_AtomicGet(&good); SDL_assert(v==CountTo); /* ensure no swap */ b=SDL_AtomicCAS(&good, CountTo, 44); SDL_assert(!!b); /* will swap */ v=SDL_AtomicGet(&good); SDL_assert(v==44); printf("Test Add\n"); v=SDL_AtomicAdd(&good, 1); SDL_assert(v==44); v=SDL_AtomicGet(&good); SDL_assert(v==45); v=SDL_AtomicAdd(&good, 10); SDL_assert(v==45); v=SDL_AtomicGet(&good); SDL_assert(v==55); printf("Test Add (Negative values)\n"); v=SDL_AtomicAdd(&good, -20); SDL_assert(v==55); v=SDL_AtomicGet(&good); SDL_assert(v==35); v=SDL_AtomicAdd(&good, -50); /* crossing zero down */ SDL_assert(v==35); v=SDL_AtomicGet(&good); SDL_assert(v==-15); v=SDL_AtomicAdd(&good, 30); /* crossing zero up */ SDL_assert(v==-15); v=SDL_AtomicGet(&good); SDL_assert(v==15); printf("Reset before count down test\n"); SDL_AtomicSet(&good, CountTo); v=SDL_AtomicGet(&good); SDL_assert(v==CountTo); bad=CountTo; SDL_assert(bad==CountTo); printf("Counting down from %d, Expect %d remaining\n",CountTo,Expect); runAdder(); v=SDL_AtomicGet(&good); printf("Atomic %d Non-Atomic %d\n",v,bad); SDL_assert(v==Expect); SDL_assert(bad!=Expect); }
SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param) { SDL_TimerData *data = &SDL_timer_data; SDL_Timer *timer; SDL_TimerMap *entry; SDL_AtomicLock(&data->lock); if (!SDL_AtomicGet(&data->active)) { if (SDL_TimerInit() < 0) { SDL_AtomicUnlock(&data->lock); return 0; } } timer = data->freelist; if (timer) { data->freelist = timer->next; } SDL_AtomicUnlock(&data->lock); if (timer) { SDL_RemoveTimer(timer->timerID); } else { timer = (SDL_Timer *)SDL_malloc(sizeof(*timer)); if (!timer) { SDL_OutOfMemory(); return 0; } } timer->timerID = SDL_AtomicIncRef(&data->nextID); timer->callback = callback; timer->param = param; timer->interval = interval; timer->scheduled = SDL_GetTicks() + interval; SDL_AtomicSet(&timer->canceled, 0); entry = (SDL_TimerMap *)SDL_malloc(sizeof(*entry)); if (!entry) { SDL_free(timer); SDL_OutOfMemory(); return 0; } entry->timer = timer; entry->timerID = timer->timerID; SDL_LockMutex(data->timermap_lock); entry->next = data->timermap; data->timermap = entry; SDL_UnlockMutex(data->timermap_lock); /* Add the timer to the pending list for the timer thread */ SDL_AtomicLock(&data->lock); timer->next = data->pending; data->pending = timer; SDL_AtomicUnlock(&data->lock); /* Wake up the timer thread if necessary */ SDL_SemPost(data->sem); return entry->timerID; }
static void RunBasicTest() { int value; SDL_SpinLock lock = 0; SDL_atomic_t v; SDL_bool tfret = SDL_FALSE; printf("\nspin lock---------------------------------------\n\n"); SDL_AtomicLock(&lock); printf("AtomicLock lock=%d\n", lock); SDL_AtomicUnlock(&lock); printf("AtomicUnlock lock=%d\n", lock); printf("\natomic -----------------------------------------\n\n"); SDL_AtomicSet(&v, 0); tfret = SDL_AtomicSet(&v, 10) == 0; printf("AtomicSet(10) tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); tfret = SDL_AtomicAdd(&v, 10) == 10; printf("AtomicAdd(10) tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); SDL_AtomicSet(&v, 0); SDL_AtomicIncRef(&v); tfret = (SDL_AtomicGet(&v) == 1); printf("AtomicIncRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); SDL_AtomicIncRef(&v); tfret = (SDL_AtomicGet(&v) == 2); printf("AtomicIncRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); tfret = (SDL_AtomicDecRef(&v) == SDL_FALSE); printf("AtomicDecRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); tfret = (SDL_AtomicDecRef(&v) == SDL_TRUE); printf("AtomicDecRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); SDL_AtomicSet(&v, 10); tfret = (SDL_AtomicCAS(&v, 0, 20) == SDL_FALSE); printf("AtomicCAS() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); value = SDL_AtomicGet(&v); tfret = (SDL_AtomicCAS(&v, value, 20) == SDL_TRUE); printf("AtomicCAS() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v)); }
static void RunFIFOTest(SDL_bool lock_free) { SDL_EventQueue queue; WriterData writerData[NUM_WRITERS]; ReaderData readerData[NUM_READERS]; Uint32 start, end; int i, j; int grand_total; printf("\nFIFO test---------------------------------------\n\n"); printf("Mode: %s\n", lock_free ? "LockFree" : "Mutex"); readersDone = SDL_CreateSemaphore(0); writersDone = SDL_CreateSemaphore(0); SDL_memset(&queue, 0xff, sizeof(queue)); InitEventQueue(&queue); if (!lock_free) { queue.mutex = SDL_CreateMutex(); } start = SDL_GetTicks(); #ifdef TEST_SPINLOCK_FIFO /* Start a monitoring thread */ if (lock_free) { SDL_CreateThread(FIFO_Watcher, "FIFOWatcher", &queue); } #endif /* Start the readers first */ printf("Starting %d readers\n", NUM_READERS); SDL_zero(readerData); SDL_AtomicSet(&readersRunning, NUM_READERS); for (i = 0; i < NUM_READERS; ++i) { char name[64]; SDL_snprintf(name, sizeof (name), "FIFOReader%d", i); readerData[i].queue = &queue; readerData[i].lock_free = lock_free; SDL_CreateThread(FIFO_Reader, name, &readerData[i]); } /* Start up the writers */ printf("Starting %d writers\n", NUM_WRITERS); SDL_zero(writerData); SDL_AtomicSet(&writersRunning, NUM_WRITERS); for (i = 0; i < NUM_WRITERS; ++i) { char name[64]; SDL_snprintf(name, sizeof (name), "FIFOWriter%d", i); writerData[i].queue = &queue; writerData[i].index = i; writerData[i].lock_free = lock_free; SDL_CreateThread(FIFO_Writer, name, &writerData[i]); } /* Wait for the writers */ while (SDL_AtomicGet(&writersRunning) > 0) { SDL_SemWait(writersDone); } /* Shut down the queue so readers exit */ queue.active = SDL_FALSE; /* Wait for the readers */ while (SDL_AtomicGet(&readersRunning) > 0) { SDL_SemWait(readersDone); } end = SDL_GetTicks(); SDL_DestroySemaphore(readersDone); SDL_DestroySemaphore(writersDone); if (!lock_free) { SDL_DestroyMutex(queue.mutex); } printf("Finished in %f sec\n", (end - start) / 1000.f); printf("\n"); for (i = 0; i < NUM_WRITERS; ++i) { printf("Writer %d wrote %d events, had %d waits\n", i, EVENTS_PER_WRITER, writerData[i].waits); } printf("Writers wrote %d total events\n", NUM_WRITERS*EVENTS_PER_WRITER); /* Print a breakdown of which readers read messages from which writer */ printf("\n"); grand_total = 0; for (i = 0; i < NUM_READERS; ++i) { int total = 0; for (j = 0; j < NUM_WRITERS; ++j) { total += readerData[i].counters[j]; } grand_total += total; printf("Reader %d read %d events, had %d waits\n", i, total, readerData[i].waits); printf(" { "); for (j = 0; j < NUM_WRITERS; ++j) { if (j > 0) { printf(", "); } printf("%d", readerData[i].counters[j]); } printf(" }\n"); } printf("Readers read %d total events\n", grand_total); }
static void HandleAudioProcess(_THIS) { Uint8 *buf = NULL; int byte_len = 0; int bytes = SDL_AUDIO_BITSIZE(this->spec.format) / 8; /* Only do something if audio is enabled */ if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) { return; } if (this->convert.needed) { const int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8; if (this->hidden->conv_in_len != 0) { this->convert.len = this->hidden->conv_in_len * bytes_in * this->spec.channels; } (*this->spec.callback) (this->spec.userdata, this->convert.buf, this->convert.len); SDL_ConvertAudio(&this->convert); buf = this->convert.buf; byte_len = this->convert.len_cvt; /* size mismatch*/ if (byte_len != this->spec.size) { if (!this->hidden->mixbuf) { this->hidden->mixlen = this->spec.size > byte_len ? this->spec.size * 2 : byte_len * 2; this->hidden->mixbuf = SDL_malloc(this->hidden->mixlen); } /* copy existing data */ byte_len = copyData(this); /* read more data*/ while (byte_len < this->spec.size) { (*this->spec.callback) (this->spec.userdata, this->convert.buf, this->convert.len); SDL_ConvertAudio(&this->convert); byte_len = copyData(this); } byte_len = this->spec.size; buf = this->hidden->mixbuf + this->hidden->read_off; this->hidden->read_off += byte_len; } } else { if (!this->hidden->mixbuf) { this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = SDL_malloc(this->hidden->mixlen); } (*this->spec.callback) (this->spec.userdata, this->hidden->mixbuf, this->hidden->mixlen); buf = this->hidden->mixbuf; byte_len = this->hidden->mixlen; } if (buf) { EM_ASM_ARGS({ var numChannels = SDL2.audio.currentOutputBuffer['numberOfChannels']; for (var c = 0; c < numChannels; ++c) { var channelData = SDL2.audio.currentOutputBuffer['getChannelData'](c); if (channelData.length != $1) { throw 'Web Audio output buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!'; } for (var j = 0; j < $1; ++j) { channelData[j] = HEAPF32[$0 + ((j*numChannels + c) << 2) >> 2]; } } }, buf, byte_len / bytes / this->spec.channels); }