HTTPServerAgent::~HTTPServerAgent() { // flush the queue SDL_LockMutex(m_requestQueueLock); while (m_requestQueue.size() > 0) m_requestQueue.pop(); SDL_UnlockMutex(m_requestQueueLock); // signal the thread. empty queue will cause it to exit SDL_CondBroadcast(m_requestQueueCond); // first thing the queue does is check the queue, so we must // not shut down until its done that. it will release the queue // lock before it dies, so try to take it SDL_LockMutex(m_requestQueueLock); // we have the lock, so we know the thread won't doing anything // else. we can clean up now SDL_DestroyMutex(m_responseQueueLock); SDL_DestroyMutex(m_requestQueueLock); SDL_DestroyCond(m_requestQueueCond); curl_slist_free_all(m_curlHeaders); curl_easy_cleanup(m_curl); }
ThreadPool::~ThreadPool() { waitAll(); // this is the hint for all available threads to break SDL_mutexP(mutex); // lock to be sure that every thread is outside that region, we could get crashes otherwise nextAction = NULL; quitting = true; SDL_CondBroadcast(awakeThread); for(std::set<ThreadPoolItem*>::iterator i = availableThreads.begin(); i != availableThreads.end(); ++i) { SDL_mutexV(mutex); SDL_WaitThread((*i)->thread, NULL); SDL_mutexP(mutex); SDL_DestroyCond((*i)->finishedSignal); SDL_DestroyCond((*i)->readyForNewWork); delete *i; } availableThreads.clear(); SDL_mutexV(mutex); SDL_DestroyMutex(startMutex); SDL_DestroyCond(threadStartedWork); SDL_DestroyCond(threadStatusChanged); SDL_DestroyCond(awakeThread); SDL_DestroyMutex(mutex); }
int _Thread_CondBroadcast(void *cond, const char *filename, int fileline) { #ifdef THREADDEBUG Sys_PrintfToTerminal("%p cond broadcast %s:%i\n" , cond, filename, fileline); #endif return SDL_CondBroadcast((SDL_cond *)cond); }
JobQueue::~JobQueue() { // flag shutdown. protected by the queue lock for convenience in GetJob SDL_LockMutex(m_queueLock); m_shutdown = true; SDL_UnlockMutex(m_queueLock); // broadcast to any waiting runners that they should try (and fail) to get // a new job right now SDL_CondBroadcast(m_queueWaitCond); const uint32_t numThreads = m_runners.size(); // delete the runners. this will tear down their underlying threads for (std::vector<JobRunner*>::iterator i = m_runners.begin(); i != m_runners.end(); ++i) delete (*i); // delete any remaining jobs for (std::deque<Job*>::iterator i = m_queue.begin(); i != m_queue.end(); ++i) delete (*i); for (uint32_t threadIdx=0; threadIdx<numThreads; threadIdx++) { for (std::deque<Job*>::iterator i = m_finished[threadIdx].begin(); i != m_finished[threadIdx].end(); ++i) { delete (*i); } } // only us left now, we can clean up and get out of here for (uint32_t threadIdx=0; threadIdx<numThreads; threadIdx++) { SDL_DestroyMutex(m_finishedLock[threadIdx]); } SDL_DestroyCond(m_queueWaitCond); SDL_DestroyMutex(m_queueLock); }
void Event::trigger(void) { SDL_LockMutex(mut); triggered = true; SDL_CondBroadcast(cond); SDL_UnlockMutex(mut); }
void HTTPServerAgent::Call(const std::string &method, const Json::Value &data, SuccessCallback onSuccess, FailCallback onFail, void *userdata) { SDL_LockMutex(m_requestQueueLock); m_requestQueue.push(Request(method, data, onSuccess, onFail, userdata)); SDL_UnlockMutex(m_requestQueueLock); SDL_CondBroadcast(m_requestQueueCond); }
bool condition::notify_all() { if(SDL_CondBroadcast(cond_) < 0) { ERR_G << "SDL_CondBroadcast: " << SDL_GetError() << std::endl; return false; } return true; }
bool condition::notify_all() { if(SDL_CondBroadcast(cond_) < 0) { std::cerr << "SDL_CondBroadcast: " << SDL_GetError() << "\n"; return false; } return true; }
void SyncPoint::Util::unlock(bool multi) { locked.clear(); if (multi) SDL_CondBroadcast(cond); else SDL_CondSignal(cond); }
static mrb_value mrb_sdl2_cond_broadcast(mrb_state *mrb, mrb_value self) { mrb_sdl2_cond_data_t *data = (mrb_sdl2_cond_data_t*)mrb_data_get_ptr(mrb, self, &mrb_sdl2_cond_data_type); if (NULL == data->cond) { return mrb_nil_value(); } if (0 > SDL_CondBroadcast(data->cond)) { mruby_sdl2_raise_error(mrb); } return self; }
static int SDLCALL threadpoolThread(void* poolPtr) { threadpool_t* pool = (threadpool_t*)poolPtr; task_t task; for(;;) { /* Lock must be taken to wait on conditional variable */ SDL_LockMutex(pool->lock); /* Wait on condition variable, check for spurious wakeups. When returning from pthread_cond_wait(), we own the lock. */ while((pool->count == 0) && (!pool->shutdown)) { SDL_CondWait(pool->notify, pool->lock); } if(pool->shutdown) { break; } /* Grab our task */ task.function = pool->queue[pool->head].function; task.argument = pool->queue[pool->head].argument; task.event = pool->queue[pool->head].event; pool->head += 1; pool->head = (pool->head == pool->queue_size) ? 0 : pool->head; pool->count -= 1; /* Unlock */ SDL_UnlockMutex(pool->lock); (*(task.function))(task.argument); if (task.event) { SDL_LockMutex(task.event->mutex); task.event->signaled = true; SDL_CondBroadcast(task.event->cond); SDL_UnlockMutex(task.event->mutex); } } pool->started--; SDL_UnlockMutex(pool->lock); return 0; }
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); }
int physics_loop (void *d) { printlog(1, "Starting physics loop"); Uint32 simtime = SDL_GetTicks(); //set simulated time to realtime Uint32 realtime; //real time (with possible delay since last update) Uint32 stepsize_ms = internal.stepsize*1000+0.0001; while (runlevel == running) { //technically, collision detection doesn't need this, but this is easier SDL_mutexP(ode_mutex); Car::Physics_Step(); //control, antigrav... Body::Physics_Step(); //drag (air/liquid "friction") dSpaceCollide (space, 0, &Geom::Collision_Callback); dWorldQuickStep (world, internal.stepsize); dJointGroupEmpty (contactgroup); Collision_Feedback::Physics_Step(); //forces from collisions Joint::Physics_Step(); //joint forces Geom::Physics_Step(); //sensor/radar handling camera.Physics_Step(); //move camera to wanted postion //done with ode SDL_mutexV(ode_mutex); Graphic_List_Update(); //make copy of position/rotation for rendering //broadcast to wake up sleeping threads if (internal.sync_events || internal.sync_graphics) { SDL_mutexP(sync_mutex); SDL_CondBroadcast (sync_cond); SDL_mutexV(sync_mutex); } simtime += stepsize_ms; realtime = SDL_GetTicks(); if (simtime > realtime) SDL_Delay (simtime - realtime); else ++stepsize_warnings; } return 0; }
~WorkQueue() { { LockMutex m(queueMutex); queueAlive = false; SDL_CondBroadcast(queueCond); } for (int i = 0; i < 8; ++i) { int status; if (threads[i]) SDL_WaitThread(threads[i], &status); } SDL_DestroyMutex(queueMutex); SDL_DestroyCond(queueCond); }
/* Nescessary logic: * 1) All threads must pass unblocked * 2) Current handler must always pass unblocked * 3) Threads must be excluded when irq routine is running * 4) No more than one handler routine should execute at a time */ int set_irq_level(int level) { SDL_LockMutex(sim_irq_mtx); int oldlevel = interrupt_level; if (status_reg == 0 && level == 0 && oldlevel != 0) { /* Not in a handler and "interrupts" are going from disabled to * enabled; signal any pending handlers still waiting */ if (handlers_pending > 0) SDL_CondBroadcast(sim_thread_cond); } interrupt_level = level; /* save new level */ SDL_UnlockMutex(sim_irq_mtx); return oldlevel; }
void Async_Free() { int i; // Stop all threads G_is_running = 0; // Notify all threads SDL_CondBroadcast(G_queue_cond); // Wait for threads for (i = 0; i < G_thread_count; i++) { if (G_threads[i]) { SDL_WaitThread(G_threads[i], NULL); } } free(G_threads); SDL_DestroyCond(G_queue_cond); SDL_DestroyMutex(G_queue_guard); }
AsyncJobQueue::~AsyncJobQueue() { // flag shutdown. protected by the queue lock for convenience in GetJob SDL_LockMutex(m_queueLock); m_shutdown = true; SDL_UnlockMutex(m_queueLock); // broadcast to any waiting runners that they should try (and fail) to get // a new job right now SDL_CondBroadcast(m_queueWaitCond); // Flag each job runner that we're being destroyed (with lock so no one // else is running one of our functions). Both the flag and the mutex // must be owned by the runner, because we may not exist when it's // checked. for (std::vector<JobRunner*>::iterator i = m_runners.begin(); i != m_runners.end(); ++i) { SDL_LockMutex((*i)->GetQueueDestroyingLock()); (*i)->SetQueueDestroyed(); SDL_UnlockMutex((*i)->GetQueueDestroyingLock()); } const uint32_t numThreads = m_runners.size(); // delete the runners. this will tear down their underlying threads for (std::vector<JobRunner*>::iterator i = m_runners.begin(); i != m_runners.end(); ++i) delete (*i); // delete any remaining jobs for (std::deque<Job*>::iterator i = m_queue.begin(); i != m_queue.end(); ++i) delete (*i); for (uint32_t threadIdx=0; threadIdx<numThreads; threadIdx++) { for (std::deque<Job*>::iterator i = m_finished[threadIdx].begin(); i != m_finished[threadIdx].end(); ++i) { delete (*i); } } // only us left now, we can clean up and get out of here for (uint32_t threadIdx=0; threadIdx<numThreads; threadIdx++) { SDL_DestroyMutex(m_finishedLock[threadIdx]); } SDL_DestroyCond(m_queueWaitCond); SDL_DestroyMutex(m_queueLock); }
void OSystem_SDL::deinitThreadedMixer() { // Kill thread?? _soundThread if (_soundThreadIsRunning) { // Signal the producer thread to end, and wait for it to actually finish. _soundThreadShouldQuit = true; SDL_CondBroadcast(_soundCond); SDL_WaitThread(_soundThread, NULL); // Kill the mutex & cond variables. // Attention: AT this point, the mixer callback must not be running // anymore, else we will crash! SDL_DestroyMutex(_soundMutex); SDL_DestroyCond(_soundCond); _soundThreadIsRunning = false; free(_soundBuffers[0]); free(_soundBuffers[1]); } }
void BXBGProcess::Resume() { if (!m_bPaused) return; Lock(); std::map<int, BXBGJob*>::iterator it = m_inProgressMap.begin(); for (;it != m_inProgressMap.end(); it++) { BXBGJob *pJob = it->second; if (pJob) { pJob->Resume(); } } Unlock(); // Lock the pause mutex SDL_LockMutex(m_pPauseLock); // Update the pause protected variable m_bPaused = false; // Signal the condition variable so that the threads would resume working SDL_CondBroadcast(m_pPauseCond); // Unlock the mutex back SDL_UnlockMutex(m_pPauseLock); }
static void wait_for_threads(download_files_thread_data_t *data, Uint32* error) { Sint32 result; Uint32 i; CHECK_AND_LOCK_MUTEX(data->mutex); if (*error == 0) { data->running = 2; } else { data->running = 0; } CHECK_AND_UNLOCK_MUTEX(data->mutex); for (i = 0; i < UPDATE_DOWNLOAD_THREAD_COUNT; i++) { SDL_CondBroadcast(data->condition); SDL_WaitThread(data->threads[i], &result); if (*error == 0) { *error = result; } } SDL_DestroyMutex(data->mutex); SDL_DestroyCond(data->condition); while (queue_pop(data->files) != 0); queue_destroy(data->files); }
void fini() { if (SDL_LockMutex(pool.lock) != 0) { return; } do { /* Already shutting down */ if(pool.shutdown) { break; } pool.shutdown = 1; /* Wake up all worker threads */ if (SDL_CondBroadcast(pool.notify) != 0 || SDL_UnlockMutex(pool.lock) != 0) { break; } /* Join all worker thread */ for(int i = 0; i < pool.thread_count; i++) { SDL_WaitThread(pool.threads[i], NULL); } } while(0); SDL_UnlockMutex(pool.lock); releaseMTResources(); }
static void taskmgr_finalize_and_wait(TaskManager *mgr, bool abort) { log_debug( "%08lx [%p] waiting for %u tasks (abort = %i)", SDL_ThreadID(), (void*)mgr, taskmgr_remaining(mgr), abort ); assert(mgr->running); assert(!mgr->aborted); SDL_LockMutex(mgr->mutex); mgr->running = false; mgr->aborted = abort; SDL_CondBroadcast(mgr->cond); SDL_UnlockMutex(mgr->mutex); for(uint i = 0; i < mgr->numthreads; ++i) { SDL_WaitThread(mgr->threads[i], NULL); } taskmgr_free(mgr); }
void Conditional::broadcast() { SDL_CondBroadcast(cond); }
void fe_mt_cond_broadcast(fe_mt_cond *cond) { SDL_CondBroadcast(*cond); }
/** * @brief The music thread. * * @param unused Unused. */ static int music_thread( void* unused ) { (void)unused; int ret; int active; /* active buffer */ ALint state; ALuint removed[2]; ALenum value; music_state_t cur_state; ALfloat gain; int fadein_start = 0; uint32_t fade, fade_timer = 0; while (1) { /* Handle states. */ musicLock(); /* Handle new command. */ switch (music_command) { case MUSIC_CMD_KILL: if (music_state != MUSIC_STATE_IDLE) music_state = MUSIC_STATE_STOPPING; else { music_state = MUSIC_STATE_DEAD; } /* Does not clear command. */ break; case MUSIC_CMD_STOP: /* Notify of stopped. */ if (music_state == MUSIC_STATE_IDLE) SDL_CondBroadcast( music_state_cond ); else music_state = MUSIC_STATE_STOPPING; break; case MUSIC_CMD_PLAY: /* Set appropriate state. */ if (music_state == MUSIC_STATE_PAUSING) music_state = MUSIC_STATE_RESUMING; else if (music_state == MUSIC_STATE_FADEIN) fade_timer = SDL_GetTicks() - MUSIC_FADEIN_DELAY; else music_state = MUSIC_STATE_LOADING; /* Disable fadein. */ fadein_start = 0; /* Clear command. */ music_command = MUSIC_CMD_NONE; SDL_CondBroadcast( music_state_cond ); break; case MUSIC_CMD_FADEOUT: /* Notify of stopped. */ if (music_state != MUSIC_STATE_IDLE) { music_state = MUSIC_STATE_FADEOUT; /* Set timer. */ fade_timer = SDL_GetTicks(); } /* Clear command. */ music_command = MUSIC_CMD_NONE; SDL_CondBroadcast( music_state_cond ); break; case MUSIC_CMD_FADEIN: if ((music_state == MUSIC_STATE_FADEIN) || (music_state == MUSIC_STATE_PLAYING)) SDL_CondBroadcast( music_state_cond ); else { music_state = MUSIC_STATE_LOADING; /* Set timer. */ fade_timer = SDL_GetTicks(); fadein_start = 1; } /* Clear command. */ music_command = MUSIC_CMD_NONE; break; case MUSIC_CMD_PAUSE: if (music_state == MUSIC_STATE_PAUSED) SDL_CondBroadcast( music_state_cond ); else if ((music_state == MUSIC_STATE_PLAYING) || (music_state == MUSIC_STATE_FADEIN)) music_state = MUSIC_STATE_PAUSING; music_command = MUSIC_CMD_NONE; break; case MUSIC_CMD_NONE: break; } cur_state = music_state; musicUnlock(); /* * Main processing loop. */ switch (cur_state) { /* * Basically send a message that thread is up and running. */ case MUSIC_STATE_STARTUP: musicLock(); music_state = MUSIC_STATE_IDLE; SDL_CondBroadcast( music_state_cond ); musicUnlock(); break; /* * We died. */ case MUSIC_STATE_DEAD: return 0; break; /* * Delays at the end. */ case MUSIC_STATE_PAUSED: case MUSIC_STATE_IDLE: break; /* * Resumes the paused song. */ case MUSIC_STATE_RESUMING: soundLock(); alSourcePlay( music_source ); alSourcef( music_source, AL_GAIN, music_vol ); /* Check for errors. */ al_checkErr(); soundUnlock(); musicLock(); music_state = MUSIC_STATE_PLAYING; SDL_CondBroadcast( music_state_cond ); musicUnlock(); break; /* * Pause the song. */ case MUSIC_STATE_PAUSING: soundLock(); alSourcePause( music_source ); /* Check for errors. */ al_checkErr(); soundUnlock(); musicLock(); music_state = MUSIC_STATE_PAUSED; SDL_CondBroadcast( music_state_cond ); musicUnlock(); break; /* * Stop song setting to IDLE. */ case MUSIC_STATE_STOPPING: soundLock(); /* Stop and remove buffers. */ alSourceStop( music_source ); alGetSourcei( music_source, AL_BUFFERS_PROCESSED, &value ); if (value > 0) alSourceUnqueueBuffers( music_source, value, removed ); /* Clear timer. */ fade_timer = 0; /* Reset volume. */ alSourcef( music_source, AL_GAIN, music_vol ); soundUnlock(); musicLock(); music_state = MUSIC_STATE_IDLE; SDL_CondBroadcast( music_state_cond ); if (!music_forced) music_rechoose(); musicUnlock(); break; /* * Load the song. */ case MUSIC_STATE_LOADING: /* Load buffer and start playing. */ active = 0; /* load first buffer */ ret = stream_loadBuffer( music_buffer[active] ); soundLock(); alSourceQueueBuffers( music_source, 1, &music_buffer[active] ); /* Special case NULL file or error. */ if (ret < 0) { soundUnlock(); /* Force state to stopped. */ musicLock(); music_state = MUSIC_STATE_IDLE; SDL_CondBroadcast( music_state_cond ); if (!music_forced) music_rechoose(); musicUnlock(); break; } /* Force volume level. */ alSourcef( music_source, AL_GAIN, (fadein_start) ? 0. : music_vol ); /* Start playing. */ alSourcePlay( music_source ); /* Check for errors. */ al_checkErr(); soundUnlock(); /* Special case of a very short song. */ if (ret > 1) { active = -1; musicLock(); if (fadein_start) music_state = MUSIC_STATE_FADEIN; else music_state = MUSIC_STATE_PLAYING; SDL_CondBroadcast( music_state_cond ); musicUnlock(); break; } /* Load second buffer. */ active = 1; ret = stream_loadBuffer( music_buffer[active] ); if (ret < 0) { active = -1; } else { soundLock(); alSourceQueueBuffers( music_source, 1, &music_buffer[active] ); /* Check for errors. */ al_checkErr(); soundUnlock(); active = 1 - active; } musicLock(); if (fadein_start) music_state = MUSIC_STATE_FADEIN; else music_state = MUSIC_STATE_PLAYING; SDL_CondBroadcast( music_state_cond ); musicUnlock(); break; /* * Fades in the music. */ case MUSIC_STATE_FADEOUT: case MUSIC_STATE_FADEIN: /* See if must still fade. */ fade = SDL_GetTicks() - fade_timer; if (cur_state == MUSIC_STATE_FADEIN) { if (fade < MUSIC_FADEIN_DELAY) { gain = (ALfloat)fade / (ALfloat)MUSIC_FADEIN_DELAY; soundLock(); alSourcef( music_source, AL_GAIN, gain*music_vol ); /* Check for errors. */ al_checkErr(); soundUnlock(); } /* No need to fade anymore. */ else { /* Set volume to normal level. */ soundLock(); alSourcef( music_source, AL_GAIN, music_vol ); /* Check for errors. */ al_checkErr(); soundUnlock(); /* Change state to playing. */ musicLock(); music_state = MUSIC_STATE_PLAYING; musicUnlock(); } } else if (cur_state == MUSIC_STATE_FADEOUT) { if (fade < MUSIC_FADEOUT_DELAY) { gain = 1. - (ALfloat)fade / (ALfloat)MUSIC_FADEOUT_DELAY; soundLock(); alSourcef( music_source, AL_GAIN, gain*music_vol ); /* Check for errors. */ al_checkErr(); soundUnlock(); } else { /* Music should stop. */ musicLock(); music_state = MUSIC_STATE_STOPPING; musicUnlock(); break; } } /* Purpose fallthrough. */ /* * Play the song if needed. */ case MUSIC_STATE_PLAYING: /* Special case where file has ended. */ if (active < 0) { soundLock(); alGetSourcei( music_source, AL_SOURCE_STATE, &state ); if (state == AL_STOPPED) { alGetSourcei( music_source, AL_BUFFERS_PROCESSED, &value ); if (value > 0) alSourceUnqueueBuffers( music_source, value, removed ); soundUnlock(); musicLock(); music_state = MUSIC_STATE_IDLE; if (!music_forced) music_rechoose(); musicUnlock(); break; } soundUnlock(); break; } soundLock(); /* See if needs another buffer set. */ alGetSourcei( music_source, AL_BUFFERS_PROCESSED, &state ); if (state > 0) { /* refill active buffer */ alSourceUnqueueBuffers( music_source, 1, removed ); ret = stream_loadBuffer( music_buffer[active] ); if (ret < 0) { active = -1; } else { alSourceQueueBuffers( music_source, 1, &music_buffer[active] ); active = 1 - active; } } /* Check for errors. */ al_checkErr(); soundUnlock(); } /* * Global thread delay. */ SDL_Delay(0); } return 0; }
// For performance, we're using multiple threads so that the game state can // be updating in the background while openGL renders. // The general plan is: // 1. Vsync happens. Everything begins. // 2. Renderthread activates. (The update thread is currently blocked.) // 3. Renderthread dumps everything into opengl, via RenderAllEntities. (And // any other similar calls, such as calls to IMGUI) Updatethread is // still blocked. When this is complete, OpenGL now has its own copy of // everything, and we can safely change world state data. // 4. Renderthread signals updatethread to wake up. // 5a.Renderthread calls gl_flush, (via Renderer.advanceframe) and waits for // everything render. Once complete, it goes to sleep and waits for the // next vsync event. // 5b.Updatethread goes and updates the game state and gets us all ready for // next frame. Once complete, it also goes to sleep and waits for the next // vsync event. void Game::Run() { // Start the update thread: UpdateThreadData rt_data(&game_exiting_, &world_, &state_machine_, &renderer_, &input_, &audio_engine_, &sync_); input_.AdvanceFrame(&renderer_.window_size()); state_machine_.AdvanceFrame(16); SDL_Thread* update_thread = SDL_CreateThread(UpdateThread, "Zooshi Update Thread", &rt_data); if (!update_thread) { LogError("Error creating update thread."); assert(false); } #if DISPLAY_FRAMERATE_HISTOGRAM for (int i = 0; i < kHistogramSize; i++) { histogram[i] = 0; } last_printout = 0; #endif // DISPLAY_FRAMERATE_HISTOGRAM // variables used for regulating our framerate: // Total size of our history, in frames: const int kHistorySize = 60 * 5; // Max number of frames we can have dropped in our history, before we // switch to queue-stuffing mode, and ignore vsync pauses. const int kMaxDroppedFrames = 3; // Variable bool missed_frame_history[kHistorySize]; for (int i = 0; i < kHistorySize; i++) { missed_frame_history[i] = false; } int history_index = 0; int total_dropped_frames = 0; global_vsync_context = &sync_; #ifdef __ANDROID__ fplbase::RegisterVsyncCallback(HandleVsync); #else // We don't need this on android because we'll just get vsync events directly. SDL_Thread* vsync_simulator_thread = SDL_CreateThread( VsyncSimulatorThread, "Zooshi Simulated Vsync Thread", nullptr); if (!vsync_simulator_thread) { LogError("Error creating vsync simulator thread."); assert(false); } #endif // __ANDROID__ int last_frame_id = 0; // We basically own the lock all the time, except when we're waiting // for a vsync event. SDL_LockMutex(sync_.renderthread_mutex_); while (!game_exiting_) { #ifdef __ANDROID__ int current_frame_id = fplbase::GetVsyncFrameId(); #else int current_frame_id = 0; #endif // __ANDROID__ // Update our framerate history: // The oldest value falls off and is replaced with the most recent frame. // Also, we update our counts. if (missed_frame_history[history_index]) { total_dropped_frames--; } // We count it as a dropped frame if more than one vsync event passed since // we started rendering it. The check is implemented via equality // comparisons because current_frame_id will eventually wrap.) missed_frame_history[history_index] = (current_frame_id != last_frame_id + 1) && (current_frame_id != last_frame_id); if (missed_frame_history[history_index]) { total_dropped_frames++; } history_index = (history_index + 1) % kHistorySize; last_frame_id = current_frame_id; // ------------------------------------------- // Steps 1, 2. // Wait for start of frame. (triggered at vsync start on android.) // For performance, we only wait if we're not dropping frames. Otherwise, // we just keep rendering as fast as we can and stuff the render queue. if (total_dropped_frames <= kMaxDroppedFrames) { SDL_CondWait(sync_.start_render_cv_, sync_.renderthread_mutex_); } // Grab the lock to make sure the game isn't still updating. SDL_LockMutex(sync_.gameupdate_mutex_); SystraceBegin("RenderFrame"); // Input update must happen from the render thread. // From the SDL documentation on SDL_PollEvent(), // https://wiki.libsdl.org/SDL_PollEvent): // "As this function implicitly calls SDL_PumpEvents(), you can only call // this function in the thread that set the video mode." SystraceBegin("Input::AdvanceFrame()"); input_.AdvanceFrame(&renderer_.window_size()); game_exiting_ |= input_.exit_requested(); SystraceEnd(); // Milliseconds elapsed since last update. rt_data.frame_start = CurrentWorldTimeSubFrame(input_); // ------------------------------------------- // Step 3. // Render everything. // ------------------------------------------- SystraceBegin("StateMachine::Render()"); fplbase::RenderTarget::ScreenRenderTarget(renderer_).SetAsRenderTarget(); renderer_.ClearDepthBuffer(); renderer_.SetCulling(fplbase::Renderer::kCullBack); state_machine_.Render(&renderer_); SystraceEnd(); SDL_UnlockMutex(sync_.gameupdate_mutex_); SystraceBegin("StateMachine::HandleUI()"); state_machine_.HandleUI(&renderer_); SystraceEnd(); // ------------------------------------------- // Step 4. // Signal the update thread that it is safe to start messing with // data, now that we've already handed it all off to openGL. // ------------------------------------------- SDL_CondBroadcast(sync_.start_update_cv_); // ------------------------------------------- // Step 5a. // Start openGL actually rendering. AdvanceFrame will (among other things) // trigger a gl_flush. This thread will block until it is completed, // but that's ok because the update thread is humming in the background // preparing the worlds tate for next frame. // ------------------------------------------- SystraceBegin("AdvanceFrame"); renderer_.AdvanceFrame(input_.minimized(), input_.Time()); SystraceEnd(); // AdvanceFrame SystraceEnd(); // RenderFrame gpg_manager_.Update(); // Process input device messages since the last game loop. // Update render window size. if (input_.GetButton(fplbase::FPLK_BACKQUOTE).went_down()) { ToggleRelativeMouseMode(); } int new_time = CurrentWorldTimeSubFrame(input_); int frame_time = new_time - rt_data.frame_start; #if DISPLAY_FRAMERATE_HISTOGRAM UpdateProfiling(frame_time); #endif // DISPLAY_FRAMERATE_HISTOGRAM SystraceCounter("FrameTime", frame_time); } SDL_UnlockMutex(sync_.renderthread_mutex_); // Clean up asynchronous callbacks to prevent crashing on garbage data. #ifdef __ANDROID__ fplbase::RegisterVsyncCallback(nullptr); #endif // __ANDROID__ input_.AddAppEventCallback(nullptr); }
void HandleVsync() { SDL_CondBroadcast(global_vsync_context->start_render_cv_); }
int CondBroadcast(Cond *cond) { return SDL_CondBroadcast(cond); }
static int taskmgr_thread(void *arg) { TaskManager *mgr = arg; attr_unused SDL_threadID tid = SDL_ThreadID(); if(SDL_SetThreadPriority(mgr->thread_prio) < 0) { log_sdl_error(LOG_WARN, "SDL_SetThreadPriority"); } bool running; bool aborted; do { SDL_LockMutex(mgr->mutex); running = mgr->running; aborted = mgr->aborted; if(!running && !aborted) { SDL_CondWait(mgr->cond, mgr->mutex); } SDL_UnlockMutex(mgr->mutex); } while(!running && !aborted); while(running && !aborted) { SDL_LockMutex(mgr->mutex); Task *task = alist_pop(&mgr->queue); running = mgr->running; aborted = mgr->aborted; if(running && task == NULL && !aborted) { SDL_CondWait(mgr->cond, mgr->mutex); } SDL_UnlockMutex(mgr->mutex); if(task != NULL) { SDL_LockMutex(task->mutex); bool task_disowned = task->disowned; if(aborted && task->status == TASK_PENDING) { task->status = TASK_CANCELLED; } if(task->status == TASK_PENDING) { task->status = TASK_RUNNING; SDL_UnlockMutex(task->mutex); task->result = task->callback(task->userdata); SDL_LockMutex(task->mutex); assert(task->in_queue); task->in_queue = false; (void)SDL_AtomicDecRef(&mgr->numtasks); if((task_disowned = task->disowned)) { SDL_UnlockMutex(task->mutex); task_free(task); } else { task->status = TASK_FINISHED; SDL_CondBroadcast(task->cond); SDL_UnlockMutex(task->mutex); } } else if(task->status == TASK_CANCELLED) { assert(task->in_queue); task->in_queue = false; (void)SDL_AtomicDecRef(&mgr->numtasks); SDL_UnlockMutex(task->mutex); if(task_disowned) { task_free(task); } } else { UNREACHABLE; } } } return 0; }
def_dll int sdl_condition::broadcast() { return SDL_CondBroadcast(_condition); }