Quantum-erase GraphicsLock; Some changes needed to accomplish this:

* comm/trackplayer Callbacks are now queued instead of asynchronously called on the stream decoder thread
* libs/callback now guards the list with a mutex (called from different threads)
* only one thread (Starcon2Main) is allowed to queue draw commands right now; a sanity check is in place (define DEBUG_DCQ_THREADS)
Fixes: Alarms and Callbacks are used for more than just Netplay, reflect this.

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3761 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2012-02-11 23:41:06 +00:00
parent 8e8b812cb7
commit 6be6491c05
72 changed files with 76 additions and 905 deletions
-104
View File
@@ -1,104 +0,0 @@
HOW TO NOT GET HOSED BY DOUBLE-LOCK/UNLOCKS WITH GraphicsLock
For the kinds of modifications you're likely to be doing, there only a
few functions that you must take care to ensure that you hold
GraphicsLock before calling. There are also some general guidelines.
GENERAL GUIDELINES
- Don't hold the GraphicsLock in Generate* functions.
- Always hold it while doing ship operations - they're all only called
by RedrawQueue. (preprocess, postprocess, etc.)
- On ConcludeTask, you must not be holding *anything* or you could
cause a deadlock if the thread you're waiting to conclude needs
whatever lock you hold before it can safely exit. It is
acceptable to hold the GraphicsLock when merely calling
Task_SetState.
Specific Guidelines:
Always hold the GraphicsLock when calling...
- SetFlashRect in sis.c; this changes which part of the screen is
flashing. Very common.
- RedrawQueue in process.c; this is for updating all the the graphics
for ship animations.
- GetMeleeStarShip in pickmele.c. That this is extern at all is
probably a sign of lousy code organization.
- DoMenuOptions in hyper.c; this is a consequence of being called from
a ship operation when in hyperspace, which means that it must assume
that it's called with the GraphicsLock held.
- DoDiscoveryReport in planets/report.c; this is called by the
Generate* functions, which always start out not holding the Lock.
- ClearSISRect and DeltaSISGauges in sis.c; you might call these if
working on code that modifies fuel or crew somehow.
THE GORY DETAILS
[functionname] means that the function is static and demands lockedness.
<functionname> means that the function is static and demands unlockedness.
*functionname* means that the function is extern and demands lockedness
(functionname) means that the function is extern and demands unlockedness.
This information is incomplete, and the result of a fairly informal
hand-analysis of the code. In the case of extern-requires-lock,
context and calling sites have been tracked so that all such functions
are reached.
battle.c: (Battle)
border.c: (DrawSISFrame)
build.c: (ActivateStarShip)
clock.c: (clock_task_func)
comm.c: (ambient_anim_task) [SpewPhrases] (AlienTalkSegue)
<DoCommunication> [HailAlien] (InitCommunication)
confirm.c: (DoConfirmExit)
credits.c: (Credits) (OutTakes)
encount.c: <DoSelectAction> (InitEncounter) [DrawFadeText]
(UninitEncounter) (EncounterBattle)
fmv.c: (Introduction)
gameopt.c: <FeedbackSetting> <FeedbackQuit> <DrawDescriptionString>
<DoNaming> <DoSettings> <DoQuitMenu> [ShowSummary]
<DoPickGame> <PickGame>
hyper.c: *LoadHyperspace* *FreeHyperspace* *DoMenuOptions*
init.c: *InitShips* *UninitShips*
melee.c: [DrawPickFrame] (flash_selection_func) <DrawMeleeShipStrings>
<DoLoadTeam> <DoSaveTeam> <DoEdit> <DoPickShip>
<FreeMeleeInfo> <DoMelee>
menu.c: (DrawMenuStateStrings)
outfit.c: <DoInstallModule> (ChangeFuelQuantity) (DoOutfit)
pickmele.c: *GetMeleeStarShip*
pickship.c: <DoPickBattleShip> [GetArmadaStarShip]
process.c: *RedrawQueue*
restart.c: <DrawRestartMenu> <DoRestart> (StartGame)
save.c: (SaveProblem)
ship.c: *ship_preprocess*
shipyard.c: (hangar_anim_func) <DrawRaceStrings> <ShowCombatShip>
[CrewTransaction] <DoModifyShips> <DrawBluePrint>
(DoShipyard)
sis.c: *ClearSISRect* *DeltaSISGauges* (flash_rect_func)
*SetFlashRect*
starbase.c: (rotate_starbase) (DoStarBase)
starcon.c: (arilou_gate_task) (Starcon2Main)
utils.c: (PauseGame)
cargo.c: (DrawCargoStrings) <DoDiscardCargo> (Cargo)
devices.c: <DrawDevices> <DoManipulateDevices> (Devices)
lander.c: <ScrollPlanetSide> [AnimateLaunch] <InitPlanetSide>
<ReturnToOrbit> (PlanetSide) (InitLander)
planets.c: (LoadPlanet) (FreePlanet)
plangen.c: (rotate_planet_task)
pstarmap.c: (flash_cursor_func) (DrawStarMap) [EraseCursor]
<DoMoveCursor> [DoStarMap] (DoFlagshipCommands)
report.c: [MakeReport] *DoDiscoveryReport*
roster.c: (flash_ship_task) <DoModifyRoster>
scan.c: <EraseCoarseScan> <PrintCoarseScanPC> <PrintCoarseScan3DO>
<SetPlanetLoc> (flash_planet_loc_func) <PickPlanetSide>
<DoScan> (ScanSystem)
solarsys.c: <FreeSolarSys> (IPtask_func) <DrawInnerSystem>
(ChangeSolarSys) <InitSolarSys>
+1 -4
View File
@@ -97,10 +97,7 @@ The simplest form of lock. If a thread tries to lock a mutex, it will
sleep if the mutex is already locked, and awaken once the mutex
becomes available. A Mutex must be unlocked by the same thread that
locked it, and a thread must never lock a mutex it has already locked
(without unlocking it first). The most important Mutex in the program
the GraphicsLock. Code in UQM that does things like change the
screen's clipping rectangle always grabs the GraphicsLock first, to
ensure that the screen doesn't go crazy.
(without unlocking it first).
API:
Mutex CreateMutex (const char *name, DWORD syncClass);