summaryrefslogtreecommitdiff
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
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
-rw-r--r--apps/debug_menu.c4
-rw-r--r--apps/plugin.c4
-rw-r--r--apps/plugin.h4
-rw-r--r--apps/plugins/doom/rockmacros.h8
-rw-r--r--apps/plugins/rockboy/rockmacros.h8
-rw-r--r--firmware/export/thread.h10
-rw-r--r--firmware/include/file.h2
-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
12 files changed, 579 insertions, 119 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index f8492d34b6..d5c0b8171d 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -181,7 +181,6 @@ static bool dbg_list(struct action_callback_info *info)
181extern struct thread_entry threads[MAXTHREADS]; 181extern struct thread_entry threads[MAXTHREADS];
182 182
183 183
184#ifndef SIMULATOR
185static char thread_status_char(int status) 184static char thread_status_char(int status)
186{ 185{
187 switch (status) 186 switch (status)
@@ -256,7 +255,6 @@ static bool dbg_os(void)
256 info.dbg_getname = threads_getname; 255 info.dbg_getname = threads_getname;
257 return dbg_list(&info); 256 return dbg_list(&info);
258} 257}
259#endif /* !SIMULATOR */
260 258
261#ifdef HAVE_LCD_BITMAP 259#ifdef HAVE_LCD_BITMAP
262#if CONFIG_CODEC != SWCODEC 260#if CONFIG_CODEC != SWCODEC
@@ -2270,9 +2268,7 @@ static const struct the_menu_item menuitems[] = {
2270#if CONFIG_CPU == SH7034 || defined(CPU_COLDFIRE) 2268#if CONFIG_CPU == SH7034 || defined(CPU_COLDFIRE)
2271 { "Catch mem accesses", dbg_set_memory_guard }, 2269 { "Catch mem accesses", dbg_set_memory_guard },
2272#endif 2270#endif
2273#ifndef SIMULATOR
2274 { "View OS stacks", dbg_os }, 2271 { "View OS stacks", dbg_os },
2275#endif
2276#ifdef HAVE_LCD_BITMAP 2272#ifdef HAVE_LCD_BITMAP
2277#ifndef SIMULATOR 2273#ifndef SIMULATOR
2278 { "View battery", view_battery }, 2274 { "View battery", view_battery },
diff --git a/apps/plugin.c b/apps/plugin.c
index 9d46ea4510..bdb59e6005 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -209,10 +209,10 @@ static const struct plugin_api rockbox_api = {
209 /* file */ 209 /* file */
210 (open_func)PREFIX(open), 210 (open_func)PREFIX(open),
211 close, 211 close,
212 (read_func)read, 212 (read_func)PREFIX(read),
213 PREFIX(lseek), 213 PREFIX(lseek),
214 (creat_func)PREFIX(creat), 214 (creat_func)PREFIX(creat),
215 (write_func)write, 215 (write_func)PREFIX(write),
216 PREFIX(remove), 216 PREFIX(remove),
217 PREFIX(rename), 217 PREFIX(rename),
218 PREFIX(ftruncate), 218 PREFIX(ftruncate),
diff --git a/apps/plugin.h b/apps/plugin.h
index c3e5a5b714..2580d43eb0 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -296,10 +296,10 @@ struct plugin_api {
296 /* file */ 296 /* file */
297 int (*PREFIX(open))(const char* pathname, int flags); 297 int (*PREFIX(open))(const char* pathname, int flags);
298 int (*close)(int fd); 298 int (*close)(int fd);
299 ssize_t (*read)(int fd, void* buf, size_t count); 299 ssize_t (*PREFIX(read))(int fd, void* buf, size_t count);
300 off_t (*PREFIX(lseek))(int fd, off_t offset, int whence); 300 off_t (*PREFIX(lseek))(int fd, off_t offset, int whence);
301 int (*PREFIX(creat))(const char *pathname); 301 int (*PREFIX(creat))(const char *pathname);
302 ssize_t (*write)(int fd, const void* buf, size_t count); 302 ssize_t (*PREFIX(write))(int fd, const void* buf, size_t count);
303 int (*PREFIX(remove))(const char* pathname); 303 int (*PREFIX(remove))(const char* pathname);
304 int (*PREFIX(rename))(const char* path, const char* newname); 304 int (*PREFIX(rename))(const char* path, const char* newname);
305 int (*PREFIX(ftruncate))(int fd, off_t length); 305 int (*PREFIX(ftruncate))(int fd, off_t length);
diff --git a/apps/plugins/doom/rockmacros.h b/apps/plugins/doom/rockmacros.h
index 1541ef48fd..b73c965c92 100644
--- a/apps/plugins/doom/rockmacros.h
+++ b/apps/plugins/doom/rockmacros.h
@@ -43,20 +43,24 @@ char *my_strtok( char * s, const char * delim );
43#undef open 43#undef open
44#undef lseek 44#undef lseek
45#undef filesize 45#undef filesize
46#undef read
47#undef write
46#define open(a,b) rb->sim_open((a),(b)) 48#define open(a,b) rb->sim_open((a),(b))
47#define lseek(a,b,c) rb->sim_lseek((a),(b),(c)) 49#define lseek(a,b,c) rb->sim_lseek((a),(b),(c))
48#define filesize(a) rb->sim_filesize((a)) 50#define filesize(a) rb->sim_filesize((a))
51#define read(a,b,c) rb->sim_read((a),(b),(c))
52#define write(a,b,c) rb->sim_write((a),(b),(c))
49#else /* !SIMULATOR */ 53#else /* !SIMULATOR */
50#define open(a,b) my_open((a),(b)) 54#define open(a,b) my_open((a),(b))
51#define close(a) my_close((a)) 55#define close(a) my_close((a))
52#define lseek(a,b,c) rb->lseek((a),(b),(c)) 56#define lseek(a,b,c) rb->lseek((a),(b),(c))
53#define filesize(a) rb->filesize((a)) 57#define filesize(a) rb->filesize((a))
58#define read(a,b,c) rb->read((a),(b),(c))
59#define write(a,b,c) rb->write((a),(b),(c))
54#endif /* !SIMULATOR */ 60#endif /* !SIMULATOR */
55 61
56#define strtok(a,b) my_strtok((a),(b)) 62#define strtok(a,b) my_strtok((a),(b))
57#define strcat(a,b) rb->strcat((a),(b)) 63#define strcat(a,b) rb->strcat((a),(b))
58#define read(a,b,c) rb->read((a),(b),(c))
59#define write(a,b,c) rb->write((a),(b),(c))
60#define memset(a,b,c) rb->memset((a),(b),(c)) 64#define memset(a,b,c) rb->memset((a),(b),(c))
61#define memmove(a,b,c) rb->memmove((a),(b),(c)) 65#define memmove(a,b,c) rb->memmove((a),(b),(c))
62#define memcmp(a,b,c) rb->memcmp((a),(b),(c)) 66#define memcmp(a,b,c) rb->memcmp((a),(b),(c))
diff --git a/apps/plugins/rockboy/rockmacros.h b/apps/plugins/rockboy/rockmacros.h
index f5223b01df..83b599897e 100644
--- a/apps/plugins/rockboy/rockmacros.h
+++ b/apps/plugins/rockboy/rockmacros.h
@@ -76,15 +76,19 @@ void dynamic_recompile (struct dynarec_block *newblock);
76#define lseek(a,b,c) rb->sim_lseek((a),(b),(c)) 76#define lseek(a,b,c) rb->sim_lseek((a),(b),(c))
77#undef close 77#undef close
78#define close(a) rb->close((a)) 78#define close(a) rb->close((a))
79#undef read
80#define read(a,b,c) rb->sim_read((a),(b),(c))
81#undef write
82#define write(a,b,c) rb->sim_write((a),(b),(c))
79#else /* !SIMULATOR */ 83#else /* !SIMULATOR */
80#define open(a,b) rb->open((a),(b)) 84#define open(a,b) rb->open((a),(b))
81#define lseek(a,b,c) rb->lseek((a),(b),(c)) 85#define lseek(a,b,c) rb->lseek((a),(b),(c))
82#define close(a) rb->close((a)) 86#define close(a) rb->close((a))
87#define read(a,b,c) rb->read((a),(b),(c))
88#define write(a,b,c) rb->write((a),(b),(c))
83#endif /* !SIMULATOR */ 89#endif /* !SIMULATOR */
84 90
85#define strcat(a,b) rb->strcat((a),(b)) 91#define strcat(a,b) rb->strcat((a),(b))
86#define read(a,b,c) rb->read((a),(b),(c))
87#define write(a,b,c) rb->write((a),(b),(c))
88#define memset(a,b,c) rb->memset((a),(b),(c)) 92#define memset(a,b,c) rb->memset((a),(b),(c))
89#define strcpy(a,b) rb->strcpy((a),(b)) 93#define strcpy(a,b) rb->strcpy((a),(b))
90#define strncpy(a,b,c) rb->strncpy((a),(b),(c)) 94#define strncpy(a,b,c) rb->strncpy((a),(b),(c))
diff --git a/firmware/export/thread.h b/firmware/export/thread.h
index 2915d23207..19bf9e12fc 100644
--- a/firmware/export/thread.h
+++ b/firmware/export/thread.h
@@ -76,7 +76,13 @@ struct regs
76 void *start; /* Thread start address, or NULL when started */ 76 void *start; /* Thread start address, or NULL when started */
77}; 77};
78# endif 78# endif
79 79#else
80struct regs
81{
82 void *t; /* Simulator OS thread */
83 void *c; /* Condition for blocking and sync */
84 void (*start)(void); /* Start function */
85};
80#endif /* !SIMULATOR */ 86#endif /* !SIMULATOR */
81 87
82#define STATE_RUNNING 0x00000000 88#define STATE_RUNNING 0x00000000
@@ -97,9 +103,7 @@ struct regs
97#define SET_BOOST_STATE(var) (var |= STATE_BOOSTED) 103#define SET_BOOST_STATE(var) (var |= STATE_BOOSTED)
98 104
99struct thread_entry { 105struct thread_entry {
100#ifndef SIMULATOR
101 struct regs context; 106 struct regs context;
102#endif
103 const char *name; 107 const char *name;
104 void *stack; 108 void *stack;
105 unsigned long statearg; 109 unsigned long statearg;
diff --git a/firmware/include/file.h b/firmware/include/file.h
index 989f50a283..9a94e91263 100644
--- a/firmware/include/file.h
+++ b/firmware/include/file.h
@@ -55,6 +55,8 @@
55#define fsync(x) sim_fsync(x) 55#define fsync(x) sim_fsync(x)
56#define ftruncate(x,y) sim_ftruncate(x,y) 56#define ftruncate(x,y) sim_ftruncate(x,y)
57#define lseek(x,y,z) sim_lseek(x,y,z) 57#define lseek(x,y,z) sim_lseek(x,y,z)
58#define read(x,y,z) sim_read(x,y,z)
59#define write(x,y,z) sim_write(x,y,z)
58#endif 60#endif
59 61
60typedef int (*open_func)(const char* pathname, int flags); 62typedef int (*open_func)(const char* pathname, int flags);
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