summaryrefslogtreecommitdiff
path: root/uisimulator
diff options
context:
space:
mode:
Diffstat (limited to 'uisimulator')
-rw-r--r--uisimulator/common/io.c169
-rw-r--r--uisimulator/sdl/kernel.c126
-rw-r--r--uisimulator/sdl/thread-sdl.c343
-rw-r--r--uisimulator/sdl/thread-sdl.h5
-rw-r--r--uisimulator/sdl/uisdl.c15
5 files changed, 554 insertions, 104 deletions
diff --git a/uisimulator/common/io.c b/uisimulator/common/io.c
index 3f7087876a..127a1c36f1 100644
--- a/uisimulator/common/io.c
+++ b/uisimulator/common/io.c
@@ -47,7 +47,10 @@
47#define MAX_PATH 260 47#define MAX_PATH 260
48 48
49#include <fcntl.h> 49#include <fcntl.h>
50 50#include <SDL.h>
51#include <SDL_thread.h>
52#include "thread.h"
53#include "kernel.h"
51#include "debug.h" 54#include "debug.h"
52#include "config.h" 55#include "config.h"
53 56
@@ -175,6 +178,131 @@ static unsigned int rockbox2sim(int opt)
175} 178}
176#endif 179#endif
177 180
181/** Simulator I/O engine routines **/
182enum
183{
184 IO_QUIT = -1,
185 IO_OPEN,
186 IO_CLOSE,
187 IO_READ,
188 IO_WRITE,
189};
190
191struct sim_io
192{
193 SDL_mutex *m; /* Mutex for condition */
194 SDL_cond *c; /* Condition for synchronizing threads */
195 SDL_Thread *t; /* The I/O thread */
196 struct mutex sim_mutex; /* Rockbox mutex */
197 volatile int cmd; /* The command to perform */
198 volatile int ready; /* I/O ready flag - 1= ready */
199 volatile int fd; /* The file to read/write */
200 void* volatile buf; /* The buffer to read/write */
201 volatile size_t count; /* Number of bytes to read/write */
202 ssize_t result; /* Result of operation */
203};
204
205static struct sim_io io;
206
207static int io_thread(void *data)
208{
209 SDL_LockMutex(io.m);
210
211 io.ready = 1; /* Indication mutex has been locked */
212
213 for (;;)
214 {
215 SDL_CondWait(io.c, io.m); /* unlock mutex and wait */
216
217 switch (io.cmd)
218 {
219 case IO_READ:
220 io.result = read(io.fd, io.buf, io.count);
221 io.ready = 1;
222 break;
223 case IO_WRITE:
224 io.result = write(io.fd, io.buf, io.count);
225 io.ready = 1;
226 break;
227 case IO_QUIT:
228 SDL_UnlockMutex(io.m);
229 return 0;
230 }
231 }
232
233 (void)data;
234}
235
236void sim_io_init(void)
237{
238 mutex_init(&io.sim_mutex);
239
240 io.ready = 0;
241
242 io.m = SDL_CreateMutex();
243 if (io.m == NULL)
244 {
245 fprintf(stderr, "Failed to create IO mutex\n");
246 exit(-1);
247 }
248
249 io.c = SDL_CreateCond();
250 if (io.c == NULL)
251 {
252 fprintf(stderr, "Failed to create IO cond\n");
253 exit(-1);
254 }
255
256 io.t = SDL_CreateThread(io_thread, NULL);
257 if (io.t == NULL)
258 {
259 fprintf(stderr, "Failed to create IO thread\n");
260 exit(-1);
261 }
262
263 /* Wait for IO thread to lock mutex */
264 while (!io.ready);
265
266 /* Wait for it to unlock */
267 SDL_LockMutex(io.m);
268 /* Free it for another thread */
269 SDL_UnlockMutex(io.m);
270}
271
272void sim_io_shutdown(void)
273{
274 SDL_LockMutex(io.m);
275
276 io.cmd = IO_QUIT;
277
278 SDL_CondSignal(io.c);
279 SDL_UnlockMutex(io.m);
280
281 SDL_WaitThread(io.t, NULL);
282
283 SDL_DestroyMutex(io.m);
284 SDL_DestroyCond(io.c);
285}
286
287static void io_trigger_and_wait(int cmd)
288{
289 /* Lock mutex before setting up new params and signaling condition */
290 SDL_LockMutex(io.m);
291
292 io.cmd = cmd;
293 io.ready = 0;
294
295 /* Get thread started */
296 SDL_CondSignal(io.c);
297
298 /* Let it run */
299 SDL_UnlockMutex(io.m);
300
301 /* Wait for IO to complete */
302 while (!io.ready)
303 yield();
304}
305
178MYDIR *sim_opendir(const char *name) 306MYDIR *sim_opendir(const char *name)
179{ 307{
180 char buffer[MAX_PATH]; /* sufficiently big */ 308 char buffer[MAX_PATH]; /* sufficiently big */
@@ -287,6 +415,45 @@ int sim_creat(const char *name)
287#endif 415#endif
288} 416}
289 417
418ssize_t sim_read(int fd, void *buf, size_t count)
419{
420 ssize_t result;
421
422 mutex_lock(&io.sim_mutex);
423
424 /* Setup parameters */
425 io.fd = fd;
426 io.buf = buf;
427 io.count = count;
428
429 io_trigger_and_wait(IO_READ);
430
431 result = io.result;
432
433 mutex_unlock(&io.sim_mutex);
434
435 return result;
436}
437
438ssize_t sim_write(int fd, const void *buf, size_t count)
439{
440 ssize_t result;
441
442 mutex_lock(&io.sim_mutex);
443
444 io.fd = fd;
445 io.buf = (void*)buf;
446 io.count = count;
447
448 io_trigger_and_wait(IO_WRITE);
449
450 result = io.result;
451
452 mutex_unlock(&io.sim_mutex);
453
454 return result;
455}
456
290int sim_mkdir(const char *name) 457int sim_mkdir(const char *name)
291{ 458{
292#ifdef __PCTOOL__ 459#ifdef __PCTOOL__
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
28volatile long current_tick = 0;
28static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); 29static 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. */
31static struct event_queue *all_queues[32]; 32static struct event_queue *all_queues[32];
32static int num_queues = 0; 33static int num_queues = 0;
33 34
34int 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 */
43static void queue_fetch_sender(struct queue_sender_list *send, 38static 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)
88void queue_enable_queue_send(struct event_queue *q, 85void 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
146void queue_wait(struct event_queue *q, struct event *ev) 158void 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
167void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks) 179void 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
195void queue_post(struct event_queue *q, long id, intptr_t data) 205void 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
220intptr_t queue_send(struct event_queue *q, long id, intptr_t data) 229intptr_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
290void queue_remove_from_head(struct event_queue *q, long id) 291void 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
321int queue_count(const struct event_queue *q) 318int 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
338void switch_thread(bool save_context, struct thread_entry **blocked_list) 335void yield(void)
339{ 336{
340 (void)save_context; 337 switch_thread(true, NULL);
341 (void)blocked_list; 338}
342 339
343 yield (); 340void sleep(int ticks)
341{
342 sleep_thread(ticks);
344} 343}
345 344
346void sim_tick_tasks(void) 345void 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 */
396void mutex_init(struct mutex *m) 396void mutex_init(struct mutex *m)
397{ 397{
398 m->locked = false; 398 m->thread = NULL;
399 m->locked = 0;
399} 400}
400 401
401void mutex_lock(struct mutex *m) 402void 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
408void mutex_unlock(struct mutex *m) 410void 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
413void spinlock_lock(struct mutex *m) 422void 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
420void spinlock_unlock(struct mutex *m) 430void 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
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}
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
25extern SDL_Thread* threads[256]; 25extern SDL_Thread *gui_thread; /* The "main" thread */
26extern int threadCount; 26void kill_sim_threads(); /* Kill all the rockbox sim threads */
27extern 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 @@
41extern void app_main (void *); /* mod entry point */ 41extern void app_main (void *); /* mod entry point */
42extern void new_key(int key); 42extern void new_key(int key);
43extern void sim_tick_tasks(void); 43extern void sim_tick_tasks(void);
44extern void sim_io_init(void);
45extern void sim_io_shutdown(void);
44 46
45void button_event(int key, bool pressed); 47void button_event(int key, bool pressed);
46 48
@@ -167,16 +169,9 @@ bool gui_startup(void)
167 169
168bool gui_shutdown(void) 170bool 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