Skip to content
This repository

-Codechange: move GameLoop_Main() into a thread #206

Open
wants to merge 3 commits into from

5 participants

glx22 rofl0r TrueBrain Thomas BERNARD wangds
glx22
Collaborator
glx22 commented April 07, 2013

Another approach to try to fix the deadlock issue.

rofl0r

how is that supposed to help ?
the video display functions access global objects, which are also accessed from the game logic functions.
accessing those vars is inherently non-thread safe unless you impose a global lock or shield each of the vars with a separate mutex.

TrueBrain
Owner

@miniupnp : does this work on OSX?

To all: does this fix Linux issues?

(basically: bump :D )

Thomas BERNARD
Collaborator

@TrueBrain on OS X it doesn't get Mouse/Keyboard events
and output a lot of
2013-04-17 19:30:18.158 opendune[927] *** _NSAutoreleaseNoPool(): Object 0x6ab420 of class NSCFArray autoreleased with no pool in place - just leaking
2013-04-17 19:30:18.160 opendune[927] *** _NSAutoreleaseNoPool(): Object 0x6161b0 of class NSWindowGraphicsContext autoreleased with no pool in place - just leaking

errors.

TrueBrain
Owner

I don't mean this the bad way, but are you sure you are testing a clean version of this PR? The errors are a bit weird for what this patch does ... silly OSX :(

Thomas BERNARD
Collaborator

I'll test again, but it's quite simple : just don't call any Cocoa code (SDL does) outside the main thread if you want to keep out of trouble :)

TrueBrain
Owner

This is why your findings are weird: it all happens in the main thread. At least, that was the idea :)

glx22
Collaborator
glx22 commented April 17, 2013

It just works in my 10.6.2 VM (but I had no deadlocks in this VM nor in the debian VM)

Thomas BERNARD
Collaborator
glx22
Collaborator
glx22 commented April 17, 2013

Indeed Video_SetPalette() can be the cause, it's called at the begining of GameLoop_Main(), and many other times from callees of this loop, especially on palette animation (GUI_PaletteAnimate()). I guess it should be possible to delegate Video_SetPalette() to the main thread via some kind of communication between the threads.

Thomas BERNARD
Collaborator

It works on my OS X 10.6.8 but not on 10.4.11...

TrueBrain
Owner

How about we ifdef OSX 10.4 (and 10.5?) to use signals, and switch the rest to threads? It is a dirty solution, but at least it makes a workable version for most of the platforms with MIDI enabled.

Good idea / bad idea?

wangds
Collaborator

This doesn't work very well for me in Linux. Switching between the main game and the F2 menu usually crashes. Video_SetPalette seems to be the cause. So, bad idea.

TrueBrain
Owner

Ah, that is feedback we need. I didnt know it didn't work on linux. But I believe there was a solution for that problem .. @glx22: didnt you had a patch for it?

TrueBrain
Owner

Maybe I should stress this a bit more: both me and glx22 cannot reproduce it on any of our machines, the problems with signals and threads etc. So we really depend on your feedback to tell us if it works now yes/no ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
47  src/opendune.c
@@ -20,6 +20,7 @@
20 20
 #include "os/math.h"
21 21
 #include "os/strings.h"
22 22
 #include "os/sleep.h"
  23
+#include "os/thread.h"
23 24
 
24 25
 #include "opendune.h"
25 26
 
@@ -59,6 +60,8 @@
59 60
 #include "unit.h"
60 61
 #include "video/video.h"
61 62
 
  63
+static Semaphore s_start_sem = NULL;
  64
+static Semaphore s_stop_sem = NULL;
62 65
 
63 66
 const char *window_caption = "OpenDUNE - Pre v0.8";
64 67
 
@@ -881,7 +884,7 @@ static void InGame_Numpad_Move(uint16 key)
881 884
 /**
882 885
  * Main game loop.
883 886
  */
884  
-static void GameLoop_Main(void)
  887
+static ThreadStatus WINAPI GameLoop_Main(void *data)
885 888
 {
886 889
 	static uint32 l_timerNext = 0;
887 890
 	static uint32 l_timerUnitStatus = 0;
@@ -889,6 +892,10 @@ static void GameLoop_Main(void)
889 892
 
890 893
 	uint16 key;
891 894
 
  895
+	VARIABLE_NOT_USED(data);
  896
+
  897
+	if (s_start_sem != NULL) Semaphore_Lock(s_start_sem);
  898
+
892 899
 	String_Init();
893 900
 	Sprites_Init();
894 901
 
@@ -1117,6 +1124,9 @@ static void GameLoop_Main(void)
1117 1124
 	GFX_ClearScreen();
1118 1125
 
1119 1126
 	GUI_Screen_FadeIn(g_curWidgetXBase, g_curWidgetYBase, g_curWidgetXBase, g_curWidgetYBase, g_curWidgetWidth, g_curWidgetHeight, SCREEN_1, SCREEN_0);
  1127
+
  1128
+	if (s_stop_sem != NULL) Semaphore_Unlock(s_stop_sem);
  1129
+	return 0;
1120 1130
 }
1121 1131
 
1122 1132
 static bool Unknown_25C4_000E(void)
@@ -1169,6 +1179,8 @@ int SDL_main(int argc, char **argv)
1169 1179
 int main(int argc, char **argv)
1170 1180
 #endif /* __APPLE__ */
1171 1181
 {
  1182
+	Thread thread = NULL;
  1183
+
1172 1184
 #if defined(_WIN32)
1173 1185
 	#if defined(__MINGW32__) && defined(__STRICT_ANSI__)
1174 1186
 		int __cdecl __MINGW_NOTHROW _fileno (FILE*);
@@ -1201,13 +1213,40 @@ int main(int argc, char **argv)
1201 1213
 
1202 1214
 	Input_Init();
1203 1215
 
1204  
-	Drivers_All_Init();
1205  
-
1206 1216
 	if (!Unknown_25C4_000E()) exit(1);
1207 1217
 
1208 1218
 	g_var_7097 = 0;
1209 1219
 
1210  
-	GameLoop_Main();
  1220
+	s_start_sem = Semaphore_Create(0);
  1221
+	s_stop_sem = Semaphore_Create(0);
  1222
+	if (s_start_sem != NULL && s_stop_sem != NULL) {
  1223
+		thread = Thread_Create(GameLoop_Main, NULL);
  1224
+	}
  1225
+
  1226
+	if (thread == NULL) {
  1227
+		Warning("Failed to create GameLoop thread.\nOpenDUNE will run without any audio output.\n");
  1228
+		g_enableSoundMusic = false;
  1229
+		g_enableVoices = false;
  1230
+	}
  1231
+
  1232
+	Drivers_All_Init();
  1233
+
  1234
+	if (s_start_sem != NULL) Semaphore_Unlock(s_start_sem);
  1235
+
  1236
+	if (thread != NULL) {
  1237
+		while (!Semaphore_TryLock(s_stop_sem)) {
  1238
+			msleep(g_timerSpeed / 1000);
  1239
+			Timer_InterruptRun(0);
  1240
+		}
  1241
+		Thread_Wait(thread, NULL);
  1242
+	} else {
  1243
+		Timer_InterruptResume();
  1244
+		GameLoop_Main(NULL);
  1245
+		Timer_InterruptSuspend();
  1246
+	}
  1247
+
  1248
+	if (s_start_sem != NULL) Semaphore_Destroy(s_start_sem);
  1249
+	if (s_stop_sem != NULL) Semaphore_Destroy(s_stop_sem);
1211 1250
 
1212 1251
 	printf("%s\n", String_Get_ByIndex(STR_THANK_YOU_FOR_PLAYING_DUNE_II));
1213 1252
 
16  src/timer.c
@@ -49,7 +49,7 @@ static int s_timerNodeSize  = 0;
49 49
 
50 50
 static uint32 s_timerLastTime;
51 51
 
52  
-static const uint32 s_timerSpeed = 10000; /* Our timer runs at 100Hz */
  52
+const uint32 g_timerSpeed = 10000; /* Our timer runs at 100Hz */
53 53
 
54 54
 
55 55
 static uint32 Timer_GetTime(void)
@@ -68,7 +68,7 @@ static uint32 Timer_GetTime(void)
68 68
 /**
69 69
  * Run the timer interrupt handler.
70 70
  */
71  
-static void Timer_InterruptRun(int arg)
  71
+void Timer_InterruptRun(int arg)
72 72
 {
73 73
 	TimerNode *node;
74 74
 	uint32 new_time, usec_delta, delta;
@@ -122,7 +122,7 @@ void CALLBACK Timer_InterruptWindows(LPVOID arg, BOOLEAN TimerOrWaitFired) {
122 122
 /**
123 123
  * Suspend the timer interrupt handling.
124 124
  */
125  
-static void Timer_InterruptSuspend(void)
  125
+void Timer_InterruptSuspend(void)
126 126
 {
127 127
 #if defined(_WIN32)
128 128
 	if (s_timerThread != NULL) DeleteTimerQueueTimer(NULL, s_timerThread, NULL);
@@ -135,7 +135,7 @@ static void Timer_InterruptSuspend(void)
135 135
 /**
136 136
  * Resume the timer interrupt handling.
137 137
  */
138  
-static void Timer_InterruptResume(void)
  138
+void Timer_InterruptResume(void)
139 139
 {
140 140
 #if defined(_WIN32)
141 141
 	CreateTimerQueueTimer(&s_timerThread, NULL, Timer_InterruptWindows, NULL, s_timerTime, s_timerTime, WT_EXECUTEINTIMERTHREAD);
@@ -152,13 +152,13 @@ void Timer_Init(void)
152 152
 	s_timerLastTime = Timer_GetTime();
153 153
 
154 154
 #if defined(_WIN32)
155  
-	s_timerTime = s_timerSpeed / 1000;
  155
+	s_timerTime = g_timerSpeed / 1000;
156 156
 	DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &s_timerMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
157 157
 #else
158 158
 	s_timerTime.it_value.tv_sec = 0;
159  
-	s_timerTime.it_value.tv_usec = s_timerSpeed;
  159
+	s_timerTime.it_value.tv_usec = g_timerSpeed;
160 160
 	s_timerTime.it_interval.tv_sec = 0;
161  
-	s_timerTime.it_interval.tv_usec = s_timerSpeed;
  161
+	s_timerTime.it_interval.tv_usec = g_timerSpeed;
162 162
 
163 163
 	{
164 164
 		struct sigaction timerSignal;
@@ -169,7 +169,6 @@ void Timer_Init(void)
169 169
 		sigaction(SIGALRM, &timerSignal, NULL);
170 170
 	}
171 171
 #endif /* _WIN32 */
172  
-	Timer_InterruptResume();
173 172
 }
174 173
 
175 174
 /**
@@ -177,7 +176,6 @@ void Timer_Init(void)
177 176
  */
178 177
 void Timer_Uninit(void)
179 178
 {
180  
-	Timer_InterruptSuspend();
181 179
 #if defined(_WIN32)
182 180
 	CloseHandle(s_timerMainThread);
183 181
 #endif /* _WIN32 */
5  src/timer.h
@@ -13,6 +13,7 @@ extern uint32 g_timerGame;
13 13
 extern uint32 g_timerInput;
14 14
 extern uint32 g_timerSleep;
15 15
 extern uint32 g_timerTimeout;
  16
+extern const uint32 g_timerSpeed;
16 17
 
17 18
 extern void Timer_Sleep(uint16 ticks);
18 19
 extern bool Timer_SetTimer(TimerType timer, bool set);
@@ -26,4 +27,8 @@ extern void Timer_Add(void (*callback)(void), uint32 usec_delay);
26 27
 extern void Timer_Change(void (*callback)(void), uint32 usec_delay);
27 28
 extern void Timer_Remove(void (*callback)(void));
28 29
 
  30
+extern void Timer_InterruptSuspend(void);
  31
+extern void Timer_InterruptResume(void);
  32
+extern void Timer_InterruptRun(int arg);
  33
+
29 34
 #endif /* OPENDUNE_H */
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.