From d8d201ee5469c84529679b1a0e191b5e1441488a Mon Sep 17 00:00:00 2001 From: Meep-Eep Date: Fri, 27 Jan 2012 23:29:03 +0000 Subject: [PATCH] Annihigate flash thread. git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3750 8092fc87-c524-0410-9efc-e669fe64eaf9 --- sc2/ChangeLog | 3 +- sc2/build/msvc6/UrQuanMasters.dsp | 12 ++ sc2/src/libs/Makeinfo | 8 +- sc2/src/libs/async.h | 10 ++ sc2/src/libs/callback/Makeinfo | 4 +- sc2/src/libs/callback/alarm.c | 57 ++++++- sc2/src/libs/callback/alarm.h | 16 +- sc2/src/libs/callback/async.c | 56 +++++++ sc2/src/libs/callback/async.h | 28 ++++ sc2/src/libs/callback/callback.c | 10 ++ sc2/src/libs/callback/callback.h | 1 + .../sound/mixer/nosound/audiodrv_nosound.c | 2 +- sc2/src/libs/sound/stream.c | 2 +- sc2/src/libs/threadlib.h | 2 + sc2/src/libs/threads/thrcommon.c | 68 ++++++++- sc2/src/uqm/battle.c | 2 + sc2/src/uqm/confirm.c | 7 + sc2/src/uqm/gameinp.c | 2 + sc2/src/uqm/sis.c | 139 ++++++++++-------- sc2/src/uqm/sis.h | 3 + sc2/src/uqm/starcon.c | 8 + sc2/src/uqm/supermelee/netplay/netmelee.c | 13 +- sc2/src/uqm/supermelee/pickmele.c | 2 + 23 files changed, 359 insertions(+), 96 deletions(-) create mode 100644 sc2/src/libs/async.h create mode 100644 sc2/src/libs/callback/async.c create mode 100644 sc2/src/libs/callback/async.h diff --git a/sc2/ChangeLog b/sc2/ChangeLog index bd5b297fc..e0bb59373 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -1,5 +1,6 @@ Changes towards version 0.8: -- Switch SetFlashRect() to the new flash code -- SvdB +- Annihigate flash thread - SvdB +- Switch SetFlashRect() to the new flash code - SvdB - Add C++ support to the build system, from Scott A. Colcord - Cleaning up DoModifyShips() - SvdB - Added Valgrind suppression file, from Louis Delacroix diff --git a/sc2/build/msvc6/UrQuanMasters.dsp b/sc2/build/msvc6/UrQuanMasters.dsp index 15b79b44d..381b6680b 100644 --- a/sc2/build/msvc6/UrQuanMasters.dsp +++ b/sc2/build/msvc6/UrQuanMasters.dsp @@ -215,6 +215,14 @@ SOURCE=..\..\src\libs\callback\alarm.h # End Source File # Begin Source File +SOURCE=..\..\src\libs\callback\async.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\libs\callback\async.h +# End Source File +# Begin Source File + SOURCE=..\..\src\libs\callback\callback.c # End Source File # Begin Source File @@ -1470,6 +1478,10 @@ SOURCE=..\..\src\libs\alarm.h # End Source File # Begin Source File +SOURCE=..\..\src\libs\async.h +# End Source File +# Begin Source File + SOURCE=..\..\src\libs\callback.h # End Source File # Begin Source File diff --git a/sc2/src/libs/Makeinfo b/sc2/src/libs/Makeinfo index 019165540..dbaa7d455 100644 --- a/sc2/src/libs/Makeinfo +++ b/sc2/src/libs/Makeinfo @@ -12,8 +12,8 @@ fi # uqm_SUBDIRS="$UQM_SUBDIRS debug" #fi -uqm_HFILES="alarm.h callback.h cdplib.h compiler.h declib.h file.h gfxlib.h - heap.h inplib.h list.h log.h mathlib.h md5.h memlib.h misc.h net.h - platform.h reslib.h sndlib.h strlib.h tasklib.h threadlib.h - timelib.h uio.h uioutils.h unicode.h vidlib.h" +uqm_HFILES="alarm.h async.h callback.h cdplib.h compiler.h declib.h file.h + gfxlib.h heap.h inplib.h list.h log.h mathlib.h md5.h memlib.h + misc.h net.h platform.h reslib.h sndlib.h strlib.h tasklib.h + threadlib.h timelib.h uio.h uioutils.h unicode.h vidlib.h" diff --git a/sc2/src/libs/async.h b/sc2/src/libs/async.h new file mode 100644 index 000000000..25b71af6e --- /dev/null +++ b/sc2/src/libs/async.h @@ -0,0 +1,10 @@ +#if defined(__cplusplus) +extern "C" { +#endif + +#include "callback/async.h" + +#if defined(__cplusplus) +} +#endif + diff --git a/sc2/src/libs/callback/Makeinfo b/sc2/src/libs/callback/Makeinfo index 50c586a71..8842cba48 100644 --- a/sc2/src/libs/callback/Makeinfo +++ b/sc2/src/libs/callback/Makeinfo @@ -1,2 +1,2 @@ -uqm_CFILES="alarm.c callback.c" -uqm_HFILES="alarm.h callback.h" +uqm_CFILES="alarm.c async.c callback.c" +uqm_HFILES="alarm.h async.h callback.h" diff --git a/sc2/src/libs/callback/alarm.c b/sc2/src/libs/callback/alarm.c index d92ce23ec..6e31e0a2e 100644 --- a/sc2/src/libs/callback/alarm.c +++ b/sc2/src/libs/callback/alarm.c @@ -18,6 +18,7 @@ #include "alarm.h" +#include SDL_INCLUDE(SDL.h) #include "libs/heap.h" #include @@ -71,19 +72,36 @@ Alarm_uninit(void) { } static inline AlarmTime -AlarmTime_nowMS(void) { +AlarmTime_nowMs(void) { return SDL_GetTicks(); } Alarm * -Alarm_addRelativeMs(Uint32 ms, AlarmCallback callback, +Alarm_addAbsoluteMs(uint32 ms, AlarmCallback callback, AlarmCallbackArg arg) { Alarm *alarm; assert(alarmHeap != NULL); alarm = Alarm_alloc(); - alarm->time = AlarmTime_nowMS() + ms; + alarm->time = ms; + alarm->callback = callback; + alarm->arg = arg; + + Heap_add(alarmHeap, (HeapValue *) alarm); + + return alarm; +} + +Alarm * +Alarm_addRelativeMs(uint32 ms, AlarmCallback callback, + AlarmCallbackArg arg) { + Alarm *alarm; + + assert(alarmHeap != NULL); + + alarm = Alarm_alloc(); + alarm->time = AlarmTime_nowMs() + ms; alarm->callback = callback; alarm->arg = arg; @@ -99,15 +117,40 @@ Alarm_remove(Alarm *alarm) { Alarm_free(alarm); } +// Process at most one alarm, if its time has come. +// It is safe to call this function again from inside a callback function +// that it called. It should not be called from multiple threads at once. +bool +Alarm_processOne(void) +{ + AlarmTime now; + Alarm *alarm; + + assert(alarmHeap != NULL); + if (!Heap_hasMore(alarmHeap)) + return false; + + now = AlarmTime_nowMs(); + alarm = (Alarm *) Heap_first(alarmHeap); + if (now < alarm->time) + return false; + + Heap_pop(alarmHeap); + alarm->callback(alarm->arg); + Alarm_free(alarm); + return true; +} + +#if 0 // It is safe to call this function again from inside a callback function // that it called. It should not be called from multiple threads at once. void -Alarm_process(void) { +Alarm_processAll(void) { AlarmTime now; assert(alarmHeap != NULL); - now = AlarmTime_nowMS(); + now = AlarmTime_nowMs(); while (Heap_hasMore(alarmHeap)) { Alarm *alarm = (Alarm *) Heap_first(alarmHeap); @@ -119,8 +162,9 @@ Alarm_process(void) { Alarm_free(alarm); } } +#endif -Uint32 +uint32 Alarm_timeBeforeNextMs(void) { Alarm *alarm; @@ -131,4 +175,3 @@ Alarm_timeBeforeNextMs(void) { return alarmTimeToMsUint32(alarm->time); } - diff --git a/sc2/src/libs/callback/alarm.h b/sc2/src/libs/callback/alarm.h index 54e0e7a2f..d3782c8cf 100644 --- a/sc2/src/libs/callback/alarm.h +++ b/sc2/src/libs/callback/alarm.h @@ -22,11 +22,10 @@ #include "port.h" #include "types.h" -#include SDL_INCLUDE(SDL.h) -typedef Uint32 AlarmTime; -static inline Uint32 +typedef uint32 AlarmTime; +static inline uint32 alarmTimeToMsUint32(AlarmTime time) { - return (Uint32) time; + return (uint32) time; } typedef struct Alarm Alarm; @@ -44,11 +43,14 @@ struct Alarm { void Alarm_init(void); void Alarm_uninit(void); -Alarm *Alarm_addRelativeMs(Uint32 ms, AlarmCallback callback, +Alarm *Alarm_addAbsoluteMs(uint32 ms, AlarmCallback callback, + AlarmCallbackArg arg); +Alarm *Alarm_addRelativeMs(uint32 ms, AlarmCallback callback, AlarmCallbackArg arg); void Alarm_remove(Alarm *alarm); -void Alarm_process(void); -Uint32 Alarm_timeBeforeNextMs(void); +bool Alarm_processOne(void); +void Alarm_processAll(void); +uint32 Alarm_timeBeforeNextMs(void); #endif /* _ALARM_H */ diff --git a/sc2/src/libs/callback/async.c b/sc2/src/libs/callback/async.c new file mode 100644 index 000000000..d901158d3 --- /dev/null +++ b/sc2/src/libs/callback/async.c @@ -0,0 +1,56 @@ +/* + * Copyright 2012 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "async.h" + +#include "libs/alarm.h" +#include "libs/callback.h" + + +// Process all alarms and callbacks. +// First, all scheduled callbacks are called. +// Then each alarm due is called, and after each of these alarms, the +// callbacks scheduled by this alarm are called. +void +Async_process(void) +{ + // Call pending callbacks. + Callback_process(); + + for (;;) { + if (!Alarm_processOne()) + return; + + // Call callbacks scheduled from the last alarm. + Callback_process(); + } +} + +// Returns the next time that some asynchronous callback is +// to be called. Note that all values lower than the current time +// should be considered as 'somewhere in the past'. +uint32 +Async_timeBeforeNextMs(void) { + if (Callback_haveMore()) { + // Any time before the current time is ok, though we reserve 0 so + // that the caller may use it as a special value in its own code. + return 1; + } + return Alarm_timeBeforeNextMs(); +} + diff --git a/sc2/src/libs/callback/async.h b/sc2/src/libs/callback/async.h new file mode 100644 index 000000000..8cfae39df --- /dev/null +++ b/sc2/src/libs/callback/async.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ASYNC_H +#define _ASYNC_H + +#include "types.h" + +void Async_process(void); +uint32 Async_timeBeforeNextMs(void); + +#endif /* _ASYNC_H */ + diff --git a/sc2/src/libs/callback/callback.c b/sc2/src/libs/callback/callback.c index dfcd5cef0..cd9e04351 100644 --- a/sc2/src/libs/callback/callback.c +++ b/sc2/src/libs/callback/callback.c @@ -170,4 +170,14 @@ Callback_process(void) { } } +bool +Callback_haveMore(void) { + bool result; + + CallbackList_lock(); + result = (callbacks != NULL); + CallbackList_unlock(); + + return result; +} diff --git a/sc2/src/libs/callback/callback.h b/sc2/src/libs/callback/callback.h index 2686cb6ac..4aef59e29 100644 --- a/sc2/src/libs/callback/callback.h +++ b/sc2/src/libs/callback/callback.h @@ -36,6 +36,7 @@ void Callback_init(void); CallbackID Callback_add(CallbackFunction callback, CallbackArg arg); bool Callback_remove(CallbackID id); void Callback_process(void); +bool Callback_haveMore(void); #endif /* _CALLBACK_H */ diff --git a/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.c b/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.c index b4d27a921..c879c19cb 100644 --- a/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.c +++ b/sc2/src/libs/sound/mixer/nosound/audiodrv_nosound.c @@ -211,7 +211,7 @@ PlaybackTaskFunc (void *data) mixer_MixFake (NULL, stream, len); delay = period - (GetTimeCounter () - entryTime); if (delay > 0) - SleepThread (delay); + HibernateThread (delay); } HFree (stream); diff --git a/sc2/src/libs/sound/stream.c b/sc2/src/libs/sound/stream.c index bf9763f4e..b7d271819 100644 --- a/sc2/src/libs/sound/stream.c +++ b/sc2/src/libs/sound/stream.c @@ -568,7 +568,7 @@ StreamDecoderTaskFunc (void *data) if (active_streams == 0) { // Throttle down the thread when there are no active streams - SleepThread (ONE_SECOND / 10); + HibernateThread (ONE_SECOND / 10); } else TaskSwitch (); diff --git a/sc2/src/libs/threadlib.h b/sc2/src/libs/threadlib.h index 80db0a533..faed76233 100644 --- a/sc2/src/libs/threadlib.h +++ b/sc2/src/libs/threadlib.h @@ -145,6 +145,8 @@ ThreadLocal *CreateThreadLocal (void); void DestroyThreadLocal (ThreadLocal *tl); ThreadLocal *GetMyThreadLocal (void); +void HibernateThread (TimePeriod timePeriod); +void HibernateThreadUntil (TimeCount wakeTime); void SleepThread (TimePeriod timePeriod); void SleepThreadUntil (TimeCount wakeTime); void DestroyThread (Thread); diff --git a/sc2/src/libs/threads/thrcommon.c b/sc2/src/libs/threads/thrcommon.c index 041712cf1..bc5475137 100644 --- a/sc2/src/libs/threads/thrcommon.c +++ b/sc2/src/libs/threads/thrcommon.c @@ -19,6 +19,7 @@ #include "libs/threadlib.h" #include "libs/timelib.h" #include "libs/log.h" +#include "libs/async.h" #include "libs/memlib.h" #include "thrcommon.h" @@ -284,16 +285,79 @@ WaitThread (Thread thread, int *status) NativeWaitThread (thread, status); } +#ifdef DEBUG_SLEEP +extern uint32 mainThreadId; +extern uint32 SDL_ThreadID(void); +#endif /* DEBUG_SLEEP */ + void -SleepThread (TimePeriod timePeriod) +HibernateThread (TimePeriod timePeriod) { +#ifdef DEBUG_SLEEP + if (SDL_ThreadID() == mainThreadId) + log_add (log_Debug, "HibernateThread called from main thread.\n"); +#endif /* DEBUG_SLEEP */ + NativeSleepThread (timePeriod); } +void +HibernateThreadUntil (TimeCount wakeTime) +{ +#ifdef DEBUG_SLEEP + if (SDL_ThreadID() == mainThreadId) + log_add (log_Debug, "HibernateThreadUntil called from main " + "thread.\n"); +#endif /* DEBUG_SLEEP */ + + NativeSleepThreadUntil (wakeTime); +} + +void +SleepThread (TimePeriod timePeriod) +{ + TimeCount now; + +#ifdef DEBUG_SLEEP + if (SDL_ThreadID() != mainThreadId) + log_add (log_Debug, "SleepThread called from non-main " + "thread.\n"); +#endif /* DEBUG_SLEEP */ + + now = GetTimeCounter (); + SleepThreadUntil (now + timePeriod); +} + +// Sleep until wakeTime, but call asynchrounous operations until then. void SleepThreadUntil (TimeCount wakeTime) { - NativeSleepThreadUntil (wakeTime); +#ifdef DEBUG_SLEEP + if (SDL_ThreadID() != mainThreadId) + log_add (log_Debug, "SleepThreadUntil called from non-main " + "thread.\n"); +#endif /* DEBUG_SLEEP */ + + for (;;) { + uint32 nextTimeMs; + TimeCount nextTime; + TimeCount now; + + Async_process (); + + now = GetTimeCounter (); + if (wakeTime <= now) + return; + + nextTimeMs = Async_timeBeforeNextMs (); + nextTime = (nextTimeMs / 1000) * ONE_SECOND + + ((nextTimeMs % 1000) * ONE_SECOND / 1000); + // Overflow-safe conversion. + if (wakeTime < nextTime) + nextTime = wakeTime; + + NativeSleepThreadUntil (nextTime); + } } void diff --git a/sc2/src/uqm/battle.c b/sc2/src/uqm/battle.c index 7774aaab0..49ed7d2ad 100644 --- a/sc2/src/uqm/battle.c +++ b/sc2/src/uqm/battle.c @@ -40,6 +40,7 @@ #include "setup.h" #include "settings.h" #include "sounds.h" +#include "libs/async.h" #include "libs/graphics/gfx_common.h" #include "libs/log.h" #include "libs/mathlib.h" @@ -334,6 +335,7 @@ DoBattle (BATTLE_STATE *bs) battle_speed = HIBYTE (nth_frame); if (battle_speed == (BYTE)~0) { // maximum speed, nothing rendered at all + Async_process (); TaskSwitch (); } else diff --git a/sc2/src/uqm/confirm.c b/sc2/src/uqm/confirm.c index 06434d4ed..2dfa3ed0a 100644 --- a/sc2/src/uqm/confirm.c +++ b/sc2/src/uqm/confirm.c @@ -83,6 +83,8 @@ DoConfirmExit (void) if (PlayingTrack ()) PauseTrack (); + PauseFlash (); + LockMutex (GraphicsLock); { RECT r; @@ -160,6 +162,8 @@ DoConfirmExit (void) } UnlockMutex (GraphicsLock); + ContinueFlash (); + if (PlayingTrack ()) ResumeTrack (); @@ -212,6 +216,7 @@ DoPopupWindow (const char *msg) label.line_count = SplitString (msg, '\n', 30, lines, bank); label.lines = lines; + PauseFlash (); LockMutex (GraphicsLock); oldContext = SetContext (ScreenContext); @@ -242,6 +247,8 @@ DoPopupWindow (const char *msg) SetContextClipRect (&oldRect); SetContext (oldContext); UnlockMutex (GraphicsLock); + ContinueFlash (); SetMenuSounds (s0, s1); StringBank_Free (bank); } + diff --git a/sc2/src/uqm/gameinp.c b/sc2/src/uqm/gameinp.c index cd2745599..befd9937e 100644 --- a/sc2/src/uqm/gameinp.c +++ b/sc2/src/uqm/gameinp.c @@ -28,6 +28,7 @@ #include "sounds.h" #include "tactrans.h" #include "uqmdebug.h" +#include "libs/async.h" #include "libs/inplib.h" #include "libs/timelib.h" #include "libs/threadlib.h" @@ -359,6 +360,7 @@ DoInput (void *pInputState, BOOLEAN resetInput) do { MENU_SOUND_FLAGS soundFlags; + Async_process (); TaskSwitch (); UpdateInputState (); diff --git a/sc2/src/uqm/sis.c b/sc2/src/uqm/sis.c index 8388b7e0e..19f92d40e 100644 --- a/sc2/src/uqm/sis.c +++ b/sc2/src/uqm/sis.c @@ -34,6 +34,7 @@ #include "flash.h" #include "libs/graphics/gfx_common.h" #include "libs/tasklib.h" +#include "libs/alarm.h" #include "libs/log.h" #include @@ -1590,28 +1591,32 @@ DrawAutoPilotMessage (BOOLEAN Reset) } -static Task flash_task = 0; static FlashContext *flashContext = NULL; static RECT flash_rect; -static Mutex flash_mutex = 0; +static Alarm *flashAlarm = NULL; +static BOOLEAN flashPaused = FALSE; -static int -flash_rect_func (void *data) +static void scheduleFlashAlarm (void); + +static void +updateFlashRect (void *arg) { - Task task = (Task)data; + if (flashContext == NULL) + return; - while (!Task_ReadState(task, TASK_EXIT)) - { - TimeCount nextTime; - LockMutex (flash_mutex); - Flash_process (flashContext); - nextTime = Flash_nextTime (flashContext); - UnlockMutex (flash_mutex); - SleepThreadUntil (nextTime); - } + Flash_process (flashContext); + scheduleFlashAlarm (); + (void) arg; +} - FinishTask (task); - return 0; +static void +scheduleFlashAlarm (void) +{ + TimeCount nextTime = Flash_nextTime (flashContext); + DWORD nextTimeMs = (nextTime / ONE_SECOND) * 1000 + + ((nextTime % ONE_SECOND) * 1000 / ONE_SECOND); + // Overflow-safe conversion. + flashAlarm = Alarm_addAbsoluteMs (nextTimeMs, updateFlashRect, NULL); } // Pre: the caller holds the GraphicsLock @@ -1621,10 +1626,6 @@ SetFlashRect (const RECT *pRect) RECT clip_r = {{0, 0}, {0, 0}}; RECT temp_r; - if (!flash_mutex) - flash_mutex = CreateMutex ("FlashRect Lock", - SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO); - if (pRect != SFR_MENU_3DO && pRect != SFR_MENU_ANY) { // The caller specified their own flash area, or NULL (stop flashing). @@ -1654,47 +1655,42 @@ SetFlashRect (const RECT *pRect) } } - // Conclude an old flash task. - if (flashContext != NULL) - { - UnlockMutex (GraphicsLock); - ConcludeTask (flash_task); - LockMutex (GraphicsLock); - flash_task = 0; - - Flash_terminate (flashContext); - flashContext = 0; - } - - // Start a new flash task. if (pRect != 0 && pRect->extent.width != 0) { + // Flash rectangle is not empty, start or continue flashing. flash_rect = *pRect; flash_rect.corner.x += clip_r.corner.x; flash_rect.corner.y += clip_r.corner.y; - flashContext = Flash_createHighlight (ScreenContext, &flash_rect); - Flash_setMergeFactors(flashContext, 3, 2, 2); - Flash_setSpeed (flashContext, 0, ONE_SECOND / 16, 0, ONE_SECOND / 16); - Flash_setFrameTime (flashContext, ONE_SECOND / 16); - Flash_start (flashContext); - - flash_task = AssignTask (flash_rect_func, 2048, "flash rectangle"); + if (flashContext == NULL) + { + // Create a new flash context. + flashContext = Flash_createHighlight (ScreenContext, &flash_rect); + Flash_setMergeFactors(flashContext, 3, 2, 2); + Flash_setSpeed (flashContext, 0, ONE_SECOND / 16, 0, ONE_SECOND / 16); + Flash_setFrameTime (flashContext, ONE_SECOND / 16); + Flash_start (flashContext); + scheduleFlashAlarm (); + } + else + { + // Reuse an existing flash context + Flash_setRect (flashContext, &flash_rect); + } } -} - -// Sleep while calling the flash rectangle update when necessary. -void -FlashRectSleepUntil (TimeCount wakeTime) -{ - while (GetTimeCounter() < wakeTime) + else { - TimeCount flashNextTime = Flash_nextTime (flashContext); - TimeCount nextTime = (flashNextTime < wakeTime) ? - flashNextTime : wakeTime; - SleepThreadUntil (nextTime); - if (nextTime == flashNextTime) - Flash_process (flashContext); + // Flash rectangle is empty. Stop flashing. + if (flashContext != NULL) + { + UnlockMutex (GraphicsLock); + Alarm_remove(flashAlarm); + LockMutex (GraphicsLock); + flashAlarm = 0; + + Flash_terminate (flashContext); + flashContext = NULL; + } } } @@ -1708,18 +1704,12 @@ COUNT updateFlashRectRecursion = 0; void PreUpdateFlashRect (void) { - if (flash_task) + if (flashAlarm) { updateFlashRectRecursion++; if (updateFlashRectRecursion > 1) return; - - LockMutex (flash_mutex); - Flash_pause (flashContext); - // We need to actually pause, as the flash update function - // is called from another thread. Flash_preUpdate (flashContext); - UnlockMutex (flash_mutex); } } @@ -1727,16 +1717,13 @@ PreUpdateFlashRect (void) void PostUpdateFlashRect (void) { - if (flash_task) + if (flashAlarm) { updateFlashRectRecursion--; if (updateFlashRectRecursion > 0) return; - LockMutex (flash_mutex); Flash_postUpdate (flashContext); - Flash_continue (flashContext); - UnlockMutex (flash_mutex); } } @@ -1760,3 +1747,27 @@ PostUpdateFlashRectLocked (void) LockMutex (GraphicsLock); } +// Stop flashing if flashing is active. +void +PauseFlash (void) +{ + if (flashContext != NULL) + { + Alarm_remove(flashAlarm); + flashAlarm = 0; + flashPaused = TRUE; + } +} + +// Continue flashing after PauseFlash (), if flashing was active. +void +ContinueFlash (void) +{ + if (flashPaused) + { + scheduleFlashAlarm (); + flashPaused = FALSE; + } +} + + diff --git a/sc2/src/uqm/sis.h b/sc2/src/uqm/sis.h index a87d7f494..8963296b4 100644 --- a/sc2/src/uqm/sis.h +++ b/sc2/src/uqm/sis.h @@ -186,6 +186,9 @@ extern void PreUpdateFlashRect (void); extern void PostUpdateFlashRect (void); extern void PreUpdateFlashRectLocked (void); extern void PostUpdateFlashRectLocked (void); +extern void PauseFlash (void); +extern void ContinueFlash (void); + #define SFR_MENU_3DO ((RECT*)~0L) #define SFR_MENU_ANY ((RECT*)~1L) extern void DrawHyperCoords (POINT puniverse); diff --git a/sc2/src/uqm/starcon.c b/sc2/src/uqm/starcon.c index 969ecf75c..c18e2ad6a 100644 --- a/sc2/src/uqm/starcon.c +++ b/sc2/src/uqm/starcon.c @@ -50,6 +50,10 @@ #include "options.h" volatile int MainExited = FALSE; +#ifdef DEBUG_SLEEP +uint32 mainThreadId; +extern uint32 SDL_ThreadID(void); +#endif // Open or close the periodically occuring QuasiSpace portal. // It changes the appearant portal size when necessary. @@ -143,6 +147,10 @@ extern int snddriver, soundflags; int Starcon2Main (void *threadArg) { +#ifdef DEBUG_SLEEP + mainThreadId = SDL_ThreadID(); +#endif + #if CREATE_JOURNAL { int ac = argc; diff --git a/sc2/src/uqm/supermelee/netplay/netmelee.c b/sc2/src/uqm/supermelee/netplay/netmelee.c index 58f931b74..657bcd4d4 100644 --- a/sc2/src/uqm/supermelee/netplay/netmelee.c +++ b/sc2/src/uqm/supermelee/netplay/netmelee.c @@ -17,7 +17,7 @@ */ #include "netmelee.h" -#include "libs/alarm.h" +#include "libs/async.h" #include "libs/callback.h" #include "libs/log.h" #include "libs/net.h" @@ -146,8 +146,7 @@ netInputAux(uint32 timeoutMs) { NetManager_process(&timeoutMs); // This may cause more packets to be queued, hence the // flushPacketQueues(). - Alarm_process(); - Callback_process(); + Async_process(); flushPacketQueues(); // During the flush, a disconnect may be noticed, which triggers // another callback. It must be handled immediately, before @@ -166,11 +165,11 @@ netInput(void) { void netInputBlocking(uint32 timeoutMs) { - uint32 nextAlarmMs; + uint32 nextAsyncMs; - nextAlarmMs = Alarm_timeBeforeNextMs(); - if (nextAlarmMs < timeoutMs) - timeoutMs = nextAlarmMs; + nextAsyncMs = Async_timeBeforeNextMs(); + if (nextAsyncMs < timeoutMs) + timeoutMs = nextAsyncMs; netInputAux(timeoutMs); } diff --git a/sc2/src/uqm/supermelee/pickmele.c b/sc2/src/uqm/supermelee/pickmele.c index ea600a789..200f45f52 100644 --- a/sc2/src/uqm/supermelee/pickmele.c +++ b/sc2/src/uqm/supermelee/pickmele.c @@ -37,6 +37,7 @@ #include "../races.h" #include "../setup.h" #include "../sounds.h" +#include "libs/async.h" #include "libs/log.h" #include "libs/mathlib.h" @@ -676,6 +677,7 @@ MeleeGameOver (void) ButtonState = FALSE; } + Async_process (); TaskSwitch (); } while (!(GLOBAL (CurrentActivity) & CHECK_ABORT) && (!ButtonState && (!(PlayerControl[0] & PlayerControl[1] & PSYTRON_CONTROL)