summaryrefslogtreecommitdiff
path: root/uisimulator/sdl/thread-sdl.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-09-08 12:20:53 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-09-08 12:20:53 +0000
commitf64ebb1c1f10e8d15fcc4879d781703c86c5fb8b (patch)
tree065072709c699ac6dc3eb640368bd3f4106144e4 /uisimulator/sdl/thread-sdl.c
parent69b4654ea28049c7e8637d521327ba10ae405f8b (diff)
downloadrockbox-f64ebb1c1f10e8d15fcc4879d781703c86c5fb8b.tar.gz
rockbox-f64ebb1c1f10e8d15fcc4879d781703c86c5fb8b.zip
Sim I/O and threading that runs more like on target. Tweakable if any genuine slowness imitation is required for any one of them. One point of concern is the sim shutdown on an OS other than Linux just because terminating threads in a manner other than having the do it themselves is kind of dirty IMHO.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14639 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'uisimulator/sdl/thread-sdl.c')
-rw-r--r--uisimulator/sdl/thread-sdl.c343
1 files changed, 310 insertions, 33 deletions
diff --git a/uisimulator/sdl/thread-sdl.c b/uisimulator/sdl/thread-sdl.c
index 90a4ecf4a7..5d2fe0b522 100644
--- a/uisimulator/sdl/thread-sdl.c
+++ b/uisimulator/sdl/thread-sdl.c
@@ -21,41 +21,157 @@
21#include <SDL.h> 21#include <SDL.h>
22#include <SDL_thread.h> 22#include <SDL_thread.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <memory.h>
24#include "thread-sdl.h" 25#include "thread-sdl.h"
25#include "kernel.h" 26#include "kernel.h"
26#include "thread.h" 27#include "thread.h"
27#include "debug.h" 28#include "debug.h"
28 29
29SDL_Thread *threads[256]; 30/* Define this as 1 to show informational messages that are not errors. */
30int threadCount = 0; 31#define THREAD_SDL_DEBUGF_ENABLED 0
31volatile long current_tick = 0;
32SDL_mutex *m;
33 32
34void yield(void) 33#if THREAD_SDL_DEBUGF_ENABLED
34#define THREAD_SDL_DEBUGF(...) DEBUGF(__VA_ARGS__)
35static char __name[32];
36#define THREAD_SDL_GET_NAME(thread) \
37 ({ thread_get_name(__name, sizeof(__name)/sizeof(__name[0]), thread); __name; })
38#else
39#define THREAD_SDL_DEBUGF(...)
40#define THREAD_SDL_GET_NAME(thread)
41#endif
42
43#define THREAD_PANICF(str...) \
44 ({ fprintf(stderr, str); exit(-1); })
45
46struct thread_entry threads[MAXTHREADS]; /* Thread entries as in core */
47static SDL_mutex *m;
48static SDL_sem *s;
49static struct thread_entry *running;
50
51void kill_sim_threads(void)
52{
53 int i;
54 SDL_LockMutex(m);
55 for (i = 0; i < MAXTHREADS; i++)
56 {
57 struct thread_entry *thread = &threads[i];
58 if (thread->context.t != NULL)
59 {
60 SDL_LockMutex(m);
61 if (thread->statearg == STATE_RUNNING)
62 SDL_SemPost(s);
63 else
64 SDL_CondSignal(thread->context.c);
65 SDL_KillThread(thread->context.t);
66 SDL_DestroyCond(thread->context.c);
67 }
68 }
69 SDL_DestroyMutex(m);
70 SDL_DestroySemaphore(s);
71}
72
73static int find_empty_thread_slot(void)
74{
75 int n;
76
77 for (n = 0; n < MAXTHREADS; n++)
78 {
79 if (threads[n].name == NULL)
80 break;
81 }
82
83 return n;
84}
85
86static void add_to_list(struct thread_entry **list,
87 struct thread_entry *thread)
88{
89 if (*list == NULL)
90 {
91 /* Insert into unoccupied list */
92 thread->next = thread;
93 thread->prev = thread;
94 *list = thread;
95 }
96 else
97 {
98 /* Insert last */
99 thread->next = *list;
100 thread->prev = (*list)->prev;
101 thread->prev->next = thread;
102 (*list)->prev = thread;
103 }
104}
105
106static void remove_from_list(struct thread_entry **list,
107 struct thread_entry *thread)
35{ 108{
36 static int counter = 0; 109 if (thread == thread->next)
110 {
111 /* The only item */
112 *list = NULL;
113 return;
114 }
37 115
38 SDL_mutexV(m); 116 if (thread == *list)
39 if (counter++ >= 50)
40 { 117 {
41 SDL_Delay(1); 118 /* List becomes next item */
42 counter = 0; 119 *list = thread->next;
43 } 120 }
44 SDL_mutexP(m); 121
122 /* Fix links to jump over the removed entry. */
123 thread->prev->next = thread->next;
124 thread->next->prev = thread->prev;
45} 125}
46 126
47void sim_sleep(int ticks) 127struct thread_entry *thread_get_current(void)
48{ 128{
49 SDL_mutexV(m); 129 return running;
50 SDL_Delay((1000/HZ) * ticks); 130}
51 SDL_mutexP(m); 131
132void switch_thread(bool save_context, struct thread_entry **blocked_list)
133{
134 struct thread_entry *current = running;
135
136 SDL_UnlockMutex(m);
137
138 SDL_SemWait(s);
139
140 SDL_LockMutex(m);
141 running = current;
142
143 SDL_SemPost(s);
144
145 (void)save_context; (void)blocked_list;
146}
147
148void sleep_thread(int ticks)
149{
150 struct thread_entry *current;
151
152 current = running;
153 current->statearg = STATE_SLEEPING;
154
155 SDL_CondWaitTimeout(current->context.c, m, (1000/HZ) * ticks);
156 running = current;
157
158 current->statearg = STATE_RUNNING;
52} 159}
53 160
54int runthread(void *data) 161int runthread(void *data)
55{ 162{
56 SDL_mutexP(m); 163 struct thread_entry *current;
57 ((void(*)())data) (); 164
58 SDL_mutexV(m); 165 /* Cannot access thread variables before locking the mutex as the
166 data structures may not be filled-in yet. */
167 SDL_LockMutex(m);
168 running = (struct thread_entry *)data;
169 current = running;
170 current->context.start();
171
172 THREAD_SDL_DEBUGF("Thread Done: %d (%s)\n",
173 current - threads, THREAD_SDL_GET_NAME(current));
174 remove_thread(NULL);
59 return 0; 175 return 0;
60} 176}
61 177
@@ -64,37 +180,198 @@ struct thread_entry*
64 const char *name) 180 const char *name)
65{ 181{
66 /** Avoid compiler warnings */ 182 /** Avoid compiler warnings */
67 (void)stack;
68 (void)stack_size;
69 (void)name;
70 SDL_Thread* t; 183 SDL_Thread* t;
184 SDL_cond *cond;
185 int slot;
186
187 THREAD_SDL_DEBUGF("Creating thread: (%s)\n", name ? name : "");
71 188
72 if (threadCount == 256) { 189 slot = find_empty_thread_slot();
190 if (slot >= MAXTHREADS)
191 {
192 DEBUGF("Failed to find thread slot\n");
73 return NULL; 193 return NULL;
74 } 194 }
75 195
76 t = SDL_CreateThread(runthread, function); 196 cond = SDL_CreateCond();
77 threads[threadCount++] = t; 197 if (cond == NULL)
198 {
199 DEBUGF("Failed to create condition variable\n");
200 return NULL;
201 }
202
203 t = SDL_CreateThread(runthread, &threads[slot]);
204 if (t == NULL)
205 {
206 DEBUGF("Failed to create SDL thread\n");
207 SDL_DestroyCond(cond);
208 return NULL;
209 }
210
211 threads[slot].stack = stack;
212 threads[slot].stack_size = stack_size;
213 threads[slot].name = name;
214 threads[slot].statearg = STATE_RUNNING;
215 threads[slot].context.start = function;
216 threads[slot].context.t = t;
217 threads[slot].context.c = cond;
218
219 THREAD_SDL_DEBUGF("New Thread: %d (%s)\n",
220 slot, THREAD_SDL_GET_NAME(&threads[slot]));
221
222 return &threads[slot];
223}
224
225void block_thread(struct thread_entry **list)
226{
227 struct thread_entry *thread = running;
228
229 thread->statearg = STATE_BLOCKED;
230 add_to_list(list, thread);
231
232 SDL_CondWait(thread->context.c, m);
233 running = thread;
234}
235
236void block_thread_w_tmo(struct thread_entry **list, int ticks)
237{
238 struct thread_entry *thread = running;
239
240 thread->statearg = STATE_BLOCKED_W_TMO;
241 add_to_list(list, thread);
242
243 SDL_CondWaitTimeout(thread->context.c, m, (1000/HZ) * ticks);
244 running = thread;
245
246 if (thread->statearg == STATE_BLOCKED_W_TMO)
247 {
248 /* Timed out */
249 remove_from_list(list, thread);
250 thread->statearg = STATE_RUNNING;
251 }
252}
253
254void wakeup_thread(struct thread_entry **list)
255{
256 struct thread_entry *thread = *list;
78 257
79 yield(); 258 if (thread == NULL)
259 {
260 return;
261 }
80 262
81 /* The return value is never de-referenced outside thread.c so this 263 switch (thread->statearg)
82 nastiness should be fine. However, a better solution would be nice. 264 {
83 */ 265 case STATE_BLOCKED:
84 return (struct thread_entry*)t; 266 case STATE_BLOCKED_W_TMO:
267 remove_from_list(list, thread);
268 thread->statearg = STATE_RUNNING;
269 SDL_CondSignal(thread->context.c);
270 break;
271 }
85} 272}
86 273
87void init_threads(void) 274void init_threads(void)
88{ 275{
276 int slot;
277
89 m = SDL_CreateMutex(); 278 m = SDL_CreateMutex();
279 s = SDL_CreateSemaphore(0);
280
281 memset(threads, 0, sizeof(threads));
282
283 slot = find_empty_thread_slot();
284 if (slot >= MAXTHREADS)
285 {
286 THREAD_PANICF("Couldn't find slot for main thread.\n");
287 }
288
289 threads[slot].stack = " ";
290 threads[slot].stack_size = 8;
291 threads[slot].name = "main";
292 threads[slot].statearg = STATE_RUNNING;
293 threads[slot].context.t = gui_thread;
294 threads[slot].context.c = SDL_CreateCond();
295
296 running = &threads[slot];
297
298 THREAD_SDL_DEBUGF("First Thread: %d (%s)\n",
299 slot, THREAD_SDL_GET_NAME(&threads[slot]));
300
301 if (SDL_LockMutex(m) == -1) {
302 THREAD_PANICF("Couldn't lock mutex\n");
303 }
90 304
91 if (SDL_mutexP(m) == -1) { 305 if (SDL_SemPost(s) == -1) {
92 fprintf(stderr, "Couldn't lock mutex\n"); 306 THREAD_PANICF("Couldn't post to semaphore\n");
93 exit(-1);
94 } 307 }
95} 308}
96 309
97void remove_thread(struct thread_entry *thread) 310void remove_thread(struct thread_entry *thread)
98{ 311{
99 SDL_KillThread((SDL_Thread*) thread); 312 struct thread_entry *current = running;
313 SDL_Thread *t;
314 SDL_cond *c;
315
316 if (thread == NULL)
317 {
318 thread = current;
319 }
320
321 t = thread->context.t;
322 c = thread->context.c;
323 thread->context.t = NULL;
324
325 if (thread != current)
326 {
327 if (thread->statearg == STATE_RUNNING)
328 SDL_SemPost(s);
329 else
330 SDL_CondSignal(c);
331 }
332
333 THREAD_SDL_DEBUGF("Removing thread: %d (%s)\n",
334 thread - threads, THREAD_SDL_GET_NAME(thread));
335
336 thread->name = NULL;
337
338 SDL_DestroyCond(c);
339
340 if (thread == current)
341 {
342 SDL_UnlockMutex(m);
343 }
344
345 SDL_KillThread(t);
346}
347
348int thread_stack_usage(const struct thread_entry *thread)
349{
350 return 50;
351 (void)thread;
352}
353
354int thread_get_status(const struct thread_entry *thread)
355{
356 return thread->statearg;
357}
358
359/* Return name if one or ID if none */
360void thread_get_name(char *buffer, int size,
361 struct thread_entry *thread)
362{
363 if (size <= 0)
364 return;
365
366 *buffer = '\0';
367
368 if (thread)
369 {
370 /* Display thread name if one or ID if none */
371 bool named = thread->name && *thread->name;
372 const char *fmt = named ? "%s" : "%08lX";
373 intptr_t name = named ?
374 (intptr_t)thread->name : (intptr_t)thread;
375 snprintf(buffer, size, fmt, name);
376 }
100} 377}