diff options
Diffstat (limited to 'uisimulator/sdl')
-rw-r--r-- | uisimulator/sdl/kernel.c | 126 | ||||
-rw-r--r-- | uisimulator/sdl/thread-sdl.c | 343 | ||||
-rw-r--r-- | uisimulator/sdl/thread-sdl.h | 5 | ||||
-rw-r--r-- | uisimulator/sdl/uisdl.c | 15 |
4 files changed, 386 insertions, 103 deletions
diff --git a/uisimulator/sdl/kernel.c b/uisimulator/sdl/kernel.c index 2b194a24ae..91d1afa1b9 100644 --- a/uisimulator/sdl/kernel.c +++ b/uisimulator/sdl/kernel.c | |||
@@ -25,25 +25,19 @@ | |||
25 | #include "thread.h" | 25 | #include "thread.h" |
26 | #include "debug.h" | 26 | #include "debug.h" |
27 | 27 | ||
28 | volatile long current_tick = 0; | ||
28 | static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); | 29 | static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); |
29 | 30 | ||
30 | /* This array holds all queues that are initiated. It is used for broadcast. */ | 31 | /* This array holds all queues that are initiated. It is used for broadcast. */ |
31 | static struct event_queue *all_queues[32]; | 32 | static struct event_queue *all_queues[32]; |
32 | static int num_queues = 0; | 33 | static int num_queues = 0; |
33 | 34 | ||
34 | int set_irq_level (int level) | ||
35 | { | ||
36 | static int _lv = 0; | ||
37 | return (_lv = level); | ||
38 | } | ||
39 | |||
40 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME | 35 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME |
41 | /* Moves waiting thread's descriptor to the current sender when a | 36 | /* Moves waiting thread's descriptor to the current sender when a |
42 | message is dequeued */ | 37 | message is dequeued */ |
43 | static void queue_fetch_sender(struct queue_sender_list *send, | 38 | static void queue_fetch_sender(struct queue_sender_list *send, |
44 | unsigned int i) | 39 | unsigned int i) |
45 | { | 40 | { |
46 | int old_level = set_irq_level(15<<4); | ||
47 | struct thread_entry **spp = &send->senders[i]; | 41 | struct thread_entry **spp = &send->senders[i]; |
48 | 42 | ||
49 | if(*spp) | 43 | if(*spp) |
@@ -51,8 +45,6 @@ static void queue_fetch_sender(struct queue_sender_list *send, | |||
51 | send->curr_sender = *spp; | 45 | send->curr_sender = *spp; |
52 | *spp = NULL; | 46 | *spp = NULL; |
53 | } | 47 | } |
54 | |||
55 | set_irq_level(old_level); | ||
56 | } | 48 | } |
57 | 49 | ||
58 | /* Puts the specified return value in the waiting thread's return value | 50 | /* Puts the specified return value in the waiting thread's return value |
@@ -61,7 +53,12 @@ static void queue_release_sender(struct thread_entry **sender, | |||
61 | intptr_t retval) | 53 | intptr_t retval) |
62 | { | 54 | { |
63 | (*sender)->retval = retval; | 55 | (*sender)->retval = retval; |
64 | *sender = NULL; | 56 | wakeup_thread(sender); |
57 | if(*sender != NULL) | ||
58 | { | ||
59 | fprintf(stderr, "queue->send slot ovf: %08X\n", (int)*sender); | ||
60 | exit(-1); | ||
61 | } | ||
65 | } | 62 | } |
66 | 63 | ||
67 | /* Releases any waiting threads that are queued with queue_send - | 64 | /* Releases any waiting threads that are queued with queue_send - |
@@ -88,8 +85,12 @@ static void queue_release_all_senders(struct event_queue *q) | |||
88 | void queue_enable_queue_send(struct event_queue *q, | 85 | void queue_enable_queue_send(struct event_queue *q, |
89 | struct queue_sender_list *send) | 86 | struct queue_sender_list *send) |
90 | { | 87 | { |
91 | q->send = send; | 88 | q->send = NULL; |
92 | memset(send, 0, sizeof(*send)); | 89 | if(send) |
90 | { | ||
91 | q->send = send; | ||
92 | memset(send, 0, sizeof(*send)); | ||
93 | } | ||
93 | } | 94 | } |
94 | #endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ | 95 | #endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */ |
95 | 96 | ||
@@ -104,6 +105,11 @@ void queue_init(struct event_queue *q, bool register_queue) | |||
104 | 105 | ||
105 | if(register_queue) | 106 | if(register_queue) |
106 | { | 107 | { |
108 | if(num_queues >= 32) | ||
109 | { | ||
110 | fprintf(stderr, "queue_init->out of queues"); | ||
111 | exit(-1); | ||
112 | } | ||
107 | /* Add it to the all_queues array */ | 113 | /* Add it to the all_queues array */ |
108 | all_queues[num_queues++] = q; | 114 | all_queues[num_queues++] = q; |
109 | } | 115 | } |
@@ -114,13 +120,6 @@ void queue_delete(struct event_queue *q) | |||
114 | int i; | 120 | int i; |
115 | bool found = false; | 121 | bool found = false; |
116 | 122 | ||
117 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME | ||
118 | /* Release waiting threads and reply to any dequeued message | ||
119 | waiting for one. */ | ||
120 | queue_release_all_senders(q); | ||
121 | queue_reply(q, 0); | ||
122 | #endif | ||
123 | |||
124 | /* Find the queue to be deleted */ | 123 | /* Find the queue to be deleted */ |
125 | for(i = 0;i < num_queues;i++) | 124 | for(i = 0;i < num_queues;i++) |
126 | { | 125 | { |
@@ -141,15 +140,28 @@ void queue_delete(struct event_queue *q) | |||
141 | 140 | ||
142 | num_queues--; | 141 | num_queues--; |
143 | } | 142 | } |
143 | |||
144 | /* Release threads waiting on queue head */ | ||
145 | wakeup_thread(&q->thread); | ||
146 | |||
147 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME | ||
148 | /* Release waiting threads and reply to any dequeued message | ||
149 | waiting for one. */ | ||
150 | queue_release_all_senders(q); | ||
151 | queue_reply(q, 0); | ||
152 | #endif | ||
153 | |||
154 | q->read = 0; | ||
155 | q->write = 0; | ||
144 | } | 156 | } |
145 | 157 | ||
146 | void queue_wait(struct event_queue *q, struct event *ev) | 158 | void queue_wait(struct event_queue *q, struct event *ev) |
147 | { | 159 | { |
148 | unsigned int rd; | 160 | unsigned int rd; |
149 | 161 | ||
150 | while(q->read == q->write) | 162 | if (q->read == q->write) |
151 | { | 163 | { |
152 | switch_thread(true, NULL); | 164 | block_thread(&q->thread); |
153 | } | 165 | } |
154 | 166 | ||
155 | rd = q->read++ & QUEUE_LENGTH_MASK; | 167 | rd = q->read++ & QUEUE_LENGTH_MASK; |
@@ -166,11 +178,9 @@ void queue_wait(struct event_queue *q, struct event *ev) | |||
166 | 178 | ||
167 | void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) | 179 | void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) |
168 | { | 180 | { |
169 | unsigned int timeout = current_tick + ticks; | 181 | if (q->read == q->write && ticks > 0) |
170 | |||
171 | while(q->read == q->write && TIME_BEFORE( current_tick, timeout )) | ||
172 | { | 182 | { |
173 | sim_sleep(1); | 183 | block_thread_w_tmo(&q->thread, ticks); |
174 | } | 184 | } |
175 | 185 | ||
176 | if(q->read != q->write) | 186 | if(q->read != q->write) |
@@ -194,7 +204,6 @@ void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) | |||
194 | 204 | ||
195 | void queue_post(struct event_queue *q, long id, intptr_t data) | 205 | void queue_post(struct event_queue *q, long id, intptr_t data) |
196 | { | 206 | { |
197 | int oldlevel = set_irq_level(15<<4); | ||
198 | unsigned int wr = q->write++ & QUEUE_LENGTH_MASK; | 207 | unsigned int wr = q->write++ & QUEUE_LENGTH_MASK; |
199 | 208 | ||
200 | q->events[wr].id = id; | 209 | q->events[wr].id = id; |
@@ -213,13 +222,12 @@ void queue_post(struct event_queue *q, long id, intptr_t data) | |||
213 | } | 222 | } |
214 | #endif | 223 | #endif |
215 | 224 | ||
216 | set_irq_level(oldlevel); | 225 | wakeup_thread(&q->thread); |
217 | } | 226 | } |
218 | 227 | ||
219 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME | 228 | #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME |
220 | intptr_t queue_send(struct event_queue *q, long id, intptr_t data) | 229 | intptr_t queue_send(struct event_queue *q, long id, intptr_t data) |
221 | { | 230 | { |
222 | int oldlevel = set_irq_level(15<<4); | ||
223 | unsigned int wr = q->write++ & QUEUE_LENGTH_MASK; | 231 | unsigned int wr = q->write++ & QUEUE_LENGTH_MASK; |
224 | 232 | ||
225 | q->events[wr].id = id; | 233 | q->events[wr].id = id; |
@@ -228,7 +236,6 @@ intptr_t queue_send(struct event_queue *q, long id, intptr_t data) | |||
228 | if(q->send) | 236 | if(q->send) |
229 | { | 237 | { |
230 | struct thread_entry **spp = &q->send->senders[wr]; | 238 | struct thread_entry **spp = &q->send->senders[wr]; |
231 | static struct thread_entry sender; | ||
232 | 239 | ||
233 | if(*spp) | 240 | if(*spp) |
234 | { | 241 | { |
@@ -236,19 +243,13 @@ intptr_t queue_send(struct event_queue *q, long id, intptr_t data) | |||
236 | queue_release_sender(spp, 0); | 243 | queue_release_sender(spp, 0); |
237 | } | 244 | } |
238 | 245 | ||
239 | *spp = &sender; | 246 | wakeup_thread(&q->thread); |
240 | |||
241 | set_irq_level(oldlevel); | ||
242 | while (*spp != NULL) | ||
243 | { | ||
244 | switch_thread(true, NULL); | ||
245 | } | ||
246 | 247 | ||
247 | return sender.retval; | 248 | block_thread(spp); |
249 | return thread_get_current()->retval; | ||
248 | } | 250 | } |
249 | 251 | ||
250 | /* Function as queue_post if sending is not enabled */ | 252 | /* Function as queue_post if sending is not enabled */ |
251 | set_irq_level(oldlevel); | ||
252 | return 0; | 253 | return 0; |
253 | } | 254 | } |
254 | 255 | ||
@@ -289,8 +290,6 @@ void queue_clear(struct event_queue* q) | |||
289 | 290 | ||
290 | void queue_remove_from_head(struct event_queue *q, long id) | 291 | void queue_remove_from_head(struct event_queue *q, long id) |
291 | { | 292 | { |
292 | int oldlevel = set_irq_level(15<<4); | ||
293 | |||
294 | while(q->read != q->write) | 293 | while(q->read != q->write) |
295 | { | 294 | { |
296 | unsigned int rd = q->read & QUEUE_LENGTH_MASK; | 295 | unsigned int rd = q->read & QUEUE_LENGTH_MASK; |
@@ -314,8 +313,6 @@ void queue_remove_from_head(struct event_queue *q, long id) | |||
314 | #endif | 313 | #endif |
315 | q->read++; | 314 | q->read++; |
316 | } | 315 | } |
317 | |||
318 | set_irq_level(oldlevel); | ||
319 | } | 316 | } |
320 | 317 | ||
321 | int queue_count(const struct event_queue *q) | 318 | int queue_count(const struct event_queue *q) |
@@ -335,12 +332,14 @@ int queue_broadcast(long id, intptr_t data) | |||
335 | return num_queues; | 332 | return num_queues; |
336 | } | 333 | } |
337 | 334 | ||
338 | void switch_thread(bool save_context, struct thread_entry **blocked_list) | 335 | void yield(void) |
339 | { | 336 | { |
340 | (void)save_context; | 337 | switch_thread(true, NULL); |
341 | (void)blocked_list; | 338 | } |
342 | 339 | ||
343 | yield (); | 340 | void sleep(int ticks) |
341 | { | ||
342 | sleep_thread(ticks); | ||
344 | } | 343 | } |
345 | 344 | ||
346 | void sim_tick_tasks(void) | 345 | void sim_tick_tasks(void) |
@@ -370,7 +369,8 @@ int tick_add_task(void (*f)(void)) | |||
370 | return 0; | 369 | return 0; |
371 | } | 370 | } |
372 | } | 371 | } |
373 | DEBUGF("Error! tick_add_task(): out of tasks"); | 372 | fprintf(stderr, "Error! tick_add_task(): out of tasks"); |
373 | exit(-1); | ||
374 | return -1; | 374 | return -1; |
375 | } | 375 | } |
376 | 376 | ||
@@ -395,29 +395,39 @@ int tick_remove_task(void (*f)(void)) | |||
395 | multitasking, but is better than nothing at all */ | 395 | multitasking, but is better than nothing at all */ |
396 | void mutex_init(struct mutex *m) | 396 | void mutex_init(struct mutex *m) |
397 | { | 397 | { |
398 | m->locked = false; | 398 | m->thread = NULL; |
399 | m->locked = 0; | ||
399 | } | 400 | } |
400 | 401 | ||
401 | void mutex_lock(struct mutex *m) | 402 | void mutex_lock(struct mutex *m) |
402 | { | 403 | { |
403 | while(m->locked) | 404 | if (test_and_set(&m->locked, 1)) |
404 | switch_thread(true, NULL); | 405 | { |
405 | m->locked = true; | 406 | block_thread(&m->thread); |
407 | } | ||
406 | } | 408 | } |
407 | 409 | ||
408 | void mutex_unlock(struct mutex *m) | 410 | void mutex_unlock(struct mutex *m) |
409 | { | 411 | { |
410 | m->locked = false; | 412 | if (m->thread != NULL) |
413 | { | ||
414 | wakeup_thread(&m->thread); | ||
415 | } | ||
416 | else | ||
417 | { | ||
418 | m->locked = 0; | ||
419 | } | ||
411 | } | 420 | } |
412 | 421 | ||
413 | void spinlock_lock(struct mutex *m) | 422 | void spinlock_lock(struct mutex *l) |
414 | { | 423 | { |
415 | while(m->locked) | 424 | while(test_and_set(&l->locked, 1)) |
425 | { | ||
416 | switch_thread(true, NULL); | 426 | switch_thread(true, NULL); |
417 | m->locked = true; | 427 | } |
418 | } | 428 | } |
419 | 429 | ||
420 | void spinlock_unlock(struct mutex *m) | 430 | void spinlock_unlock(struct mutex *l) |
421 | { | 431 | { |
422 | m->locked = false; | 432 | l->locked = 0; |
423 | } | 433 | } |
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 | ||
29 | SDL_Thread *threads[256]; | 30 | /* Define this as 1 to show informational messages that are not errors. */ |
30 | int threadCount = 0; | 31 | #define THREAD_SDL_DEBUGF_ENABLED 0 |
31 | volatile long current_tick = 0; | ||
32 | SDL_mutex *m; | ||
33 | 32 | ||
34 | void yield(void) | 33 | #if THREAD_SDL_DEBUGF_ENABLED |
34 | #define THREAD_SDL_DEBUGF(...) DEBUGF(__VA_ARGS__) | ||
35 | static 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 | |||
46 | struct thread_entry threads[MAXTHREADS]; /* Thread entries as in core */ | ||
47 | static SDL_mutex *m; | ||
48 | static SDL_sem *s; | ||
49 | static struct thread_entry *running; | ||
50 | |||
51 | void 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 | |||
73 | static 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 | |||
86 | static 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 | |||
106 | static 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 | ||
47 | void sim_sleep(int ticks) | 127 | struct 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 | |
132 | void 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 | |||
148 | void 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 | ||
54 | int runthread(void *data) | 161 | int 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 | |||
225 | void 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 | |||
236 | void 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 | |||
254 | void 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 | ||
87 | void init_threads(void) | 274 | void 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 | ||
97 | void remove_thread(struct thread_entry *thread) | 310 | void 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 | |||
348 | int thread_stack_usage(const struct thread_entry *thread) | ||
349 | { | ||
350 | return 50; | ||
351 | (void)thread; | ||
352 | } | ||
353 | |||
354 | int thread_get_status(const struct thread_entry *thread) | ||
355 | { | ||
356 | return thread->statearg; | ||
357 | } | ||
358 | |||
359 | /* Return name if one or ID if none */ | ||
360 | void 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 | } |
diff --git a/uisimulator/sdl/thread-sdl.h b/uisimulator/sdl/thread-sdl.h index 0bb6ded0d5..20641fb673 100644 --- a/uisimulator/sdl/thread-sdl.h +++ b/uisimulator/sdl/thread-sdl.h | |||
@@ -22,9 +22,8 @@ | |||
22 | 22 | ||
23 | #include "SDL_thread.h" | 23 | #include "SDL_thread.h" |
24 | 24 | ||
25 | extern SDL_Thread* threads[256]; | 25 | extern SDL_Thread *gui_thread; /* The "main" thread */ |
26 | extern int threadCount; | 26 | void kill_sim_threads(); /* Kill all the rockbox sim threads */ |
27 | extern SDL_mutex* mutex; | ||
28 | 27 | ||
29 | #endif /* #ifndef __THREADSDL_H__ */ | 28 | #endif /* #ifndef __THREADSDL_H__ */ |
30 | 29 | ||
diff --git a/uisimulator/sdl/uisdl.c b/uisimulator/sdl/uisdl.c index 052fd4af83..37a0e6fe7a 100644 --- a/uisimulator/sdl/uisdl.c +++ b/uisimulator/sdl/uisdl.c | |||
@@ -41,6 +41,8 @@ | |||
41 | extern void app_main (void *); /* mod entry point */ | 41 | extern void app_main (void *); /* mod entry point */ |
42 | extern void new_key(int key); | 42 | extern void new_key(int key); |
43 | extern void sim_tick_tasks(void); | 43 | extern void sim_tick_tasks(void); |
44 | extern void sim_io_init(void); | ||
45 | extern void sim_io_shutdown(void); | ||
44 | 46 | ||
45 | void button_event(int key, bool pressed); | 47 | void button_event(int key, bool pressed); |
46 | 48 | ||
@@ -167,16 +169,9 @@ bool gui_startup(void) | |||
167 | 169 | ||
168 | bool gui_shutdown(void) | 170 | bool gui_shutdown(void) |
169 | { | 171 | { |
170 | int i; | ||
171 | |||
172 | SDL_KillThread(gui_thread); | ||
173 | SDL_RemoveTimer(tick_timer_id); | 172 | SDL_RemoveTimer(tick_timer_id); |
174 | 173 | kill_sim_threads(); | |
175 | for (i = 0; i < threadCount; i++) | 174 | sim_io_shutdown(); |
176 | { | ||
177 | SDL_KillThread(threads[i]); | ||
178 | } | ||
179 | |||
180 | return true; | 175 | return true; |
181 | } | 176 | } |
182 | 177 | ||
@@ -236,6 +231,8 @@ int main(int argc, char *argv[]) | |||
236 | background = false; | 231 | background = false; |
237 | } | 232 | } |
238 | 233 | ||
234 | sim_io_init(); | ||
235 | |||
239 | if (!gui_startup()) | 236 | if (!gui_startup()) |
240 | return -1; | 237 | return -1; |
241 | 238 | ||