summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 f8492d3..d5c0b81 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -181,7 +181,6 @@ static bool dbg_list(struct action_callback_info *info)
extern struct thread_entry threads[MAXTHREADS];
-#ifndef SIMULATOR
static char thread_status_char(int status)
{
switch (status)
@@ -256,7 +255,6 @@ static bool dbg_os(void)
info.dbg_getname = threads_getname;
return dbg_list(&info);
}
-#endif /* !SIMULATOR */
#ifdef HAVE_LCD_BITMAP
#if CONFIG_CODEC != SWCODEC
@@ -2270,9 +2268,7 @@ static const struct the_menu_item menuitems[] = {
#if CONFIG_CPU == SH7034 || defined(CPU_COLDFIRE)
{ "Catch mem accesses", dbg_set_memory_guard },
#endif
-#ifndef SIMULATOR
{ "View OS stacks", dbg_os },
-#endif
#ifdef HAVE_LCD_BITMAP
#ifndef SIMULATOR
{ "View battery", view_battery },
diff --git a/apps/plugin.c b/apps/plugin.c
index 9d46ea4..bdb59e6 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -209,10 +209,10 @@ static const struct plugin_api rockbox_api = {
/* file */
(open_func)PREFIX(open),
close,
- (read_func)read,
+ (read_func)PREFIX(read),
PREFIX(lseek),
(creat_func)PREFIX(creat),
- (write_func)write,
+ (write_func)PREFIX(write),
PREFIX(remove),
PREFIX(rename),
PREFIX(ftruncate),
diff --git a/apps/plugin.h b/apps/plugin.h
index c3e5a5b..2580d43 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -296,10 +296,10 @@ struct plugin_api {
/* file */
int (*PREFIX(open))(const char* pathname, int flags);
int (*close)(int fd);
- ssize_t (*read)(int fd, void* buf, size_t count);
+ ssize_t (*PREFIX(read))(int fd, void* buf, size_t count);
off_t (*PREFIX(lseek))(int fd, off_t offset, int whence);
int (*PREFIX(creat))(const char *pathname);
- ssize_t (*write)(int fd, const void* buf, size_t count);
+ ssize_t (*PREFIX(write))(int fd, const void* buf, size_t count);
int (*PREFIX(remove))(const char* pathname);
int (*PREFIX(rename))(const char* path, const char* newname);
int (*PREFIX(ftruncate))(int fd, off_t length);
diff --git a/apps/plugins/doom/rockmacros.h b/apps/plugins/doom/rockmacros.h
index 1541ef4..b73c965 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 );
#undef open
#undef lseek
#undef filesize
+#undef read
+#undef write
#define open(a,b) rb->sim_open((a),(b))
#define lseek(a,b,c) rb->sim_lseek((a),(b),(c))
#define filesize(a) rb->sim_filesize((a))
+#define read(a,b,c) rb->sim_read((a),(b),(c))
+#define write(a,b,c) rb->sim_write((a),(b),(c))
#else /* !SIMULATOR */
#define open(a,b) my_open((a),(b))
#define close(a) my_close((a))
#define lseek(a,b,c) rb->lseek((a),(b),(c))
#define filesize(a) rb->filesize((a))
+#define read(a,b,c) rb->read((a),(b),(c))
+#define write(a,b,c) rb->write((a),(b),(c))
#endif /* !SIMULATOR */
#define strtok(a,b) my_strtok((a),(b))
#define strcat(a,b) rb->strcat((a),(b))
-#define read(a,b,c) rb->read((a),(b),(c))
-#define write(a,b,c) rb->write((a),(b),(c))
#define memset(a,b,c) rb->memset((a),(b),(c))
#define memmove(a,b,c) rb->memmove((a),(b),(c))
#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 f5223b0..83b5998 100644
--- a/apps/plugins/rockboy/rockmacros.h
+++ b/apps/plugins/rockboy/rockmacros.h
@@ -76,15 +76,19 @@ void dynamic_recompile (struct dynarec_block *newblock);
#define lseek(a,b,c) rb->sim_lseek((a),(b),(c))
#undef close
#define close(a) rb->close((a))
+#undef read
+#define read(a,b,c) rb->sim_read((a),(b),(c))
+#undef write
+#define write(a,b,c) rb->sim_write((a),(b),(c))
#else /* !SIMULATOR */
#define open(a,b) rb->open((a),(b))
#define lseek(a,b,c) rb->lseek((a),(b),(c))
#define close(a) rb->close((a))
+#define read(a,b,c) rb->read((a),(b),(c))
+#define write(a,b,c) rb->write((a),(b),(c))
#endif /* !SIMULATOR */
#define strcat(a,b) rb->strcat((a),(b))
-#define read(a,b,c) rb->read((a),(b),(c))
-#define write(a,b,c) rb->write((a),(b),(c))
#define memset(a,b,c) rb->memset((a),(b),(c))
#define strcpy(a,b) rb->strcpy((a),(b))
#define strncpy(a,b,c) rb->strncpy((a),(b),(c))
diff --git a/firmware/export/thread.h b/firmware/export/thread.h
index 2915d23..19bf9e1 100644
--- a/firmware/export/thread.h
+++ b/firmware/export/thread.h
@@ -76,7 +76,13 @@ struct regs
void *start; /* Thread start address, or NULL when started */
};
# endif
-
+#else
+struct regs
+{
+ void *t; /* Simulator OS thread */
+ void *c; /* Condition for blocking and sync */
+ void (*start)(void); /* Start function */
+};
#endif /* !SIMULATOR */
#define STATE_RUNNING 0x00000000
@@ -97,9 +103,7 @@ struct regs
#define SET_BOOST_STATE(var) (var |= STATE_BOOSTED)
struct thread_entry {
-#ifndef SIMULATOR
struct regs context;
-#endif
const char *name;
void *stack;
unsigned long statearg;
diff --git a/firmware/include/file.h b/firmware/include/file.h
index 989f50a..9a94e91 100644
--- a/firmware/include/file.h
+++ b/firmware/include/file.h
@@ -55,6 +55,8 @@
#define fsync(x) sim_fsync(x)
#define ftruncate(x,y) sim_ftruncate(x,y)
#define lseek(x,y,z) sim_lseek(x,y,z)
+#define read(x,y,z) sim_read(x,y,z)
+#define write(x,y,z) sim_write(x,y,z)
#endif
typedef int (*open_func)(const char* pathname, int flags);
diff --git a/uisimulator/common/io.c b/uisimulator/common/io.c
index 3f70878..127a1c3 100644
--- a/uisimulator/common/io.c
+++ b/uisimulator/common/io.c
@@ -47,7 +47,10 @@
#define MAX_PATH 260
#include <fcntl.h>
-
+#include <SDL.h>
+#include <SDL_thread.h>
+#include "thread.h"
+#include "kernel.h"
#include "debug.h"
#include "config.h"
@@ -175,6 +178,131 @@ static unsigned int rockbox2sim(int opt)
}
#endif
+/** Simulator I/O engine routines **/
+enum
+{
+ IO_QUIT = -1,
+ IO_OPEN,
+ IO_CLOSE,
+ IO_READ,
+ IO_WRITE,
+};
+
+struct sim_io
+{
+ SDL_mutex *m; /* Mutex for condition */
+ SDL_cond *c; /* Condition for synchronizing threads */
+ SDL_Thread *t; /* The I/O thread */
+ struct mutex sim_mutex; /* Rockbox mutex */
+ volatile int cmd; /* The command to perform */
+ volatile int ready; /* I/O ready flag - 1= ready */
+ volatile int fd; /* The file to read/write */
+ void* volatile buf; /* The buffer to read/write */
+ volatile size_t count; /* Number of bytes to read/write */
+ ssize_t result; /* Result of operation */
+};
+
+static struct sim_io io;
+
+static int io_thread(void *data)
+{
+ SDL_LockMutex(io.m);
+
+ io.ready = 1; /* Indication mutex has been locked */
+
+ for (;;)
+ {
+ SDL_CondWait(io.c, io.m); /* unlock mutex and wait */
+
+ switch (io.cmd)
+ {
+ case IO_READ:
+ io.result = read(io.fd, io.buf, io.count);
+ io.ready = 1;
+ break;
+ case IO_WRITE:
+ io.result = write(io.fd, io.buf, io.count);
+ io.ready = 1;
+ break;
+ case IO_QUIT:
+ SDL_UnlockMutex(io.m);
+ return 0;
+ }
+ }
+
+ (void)data;
+}
+
+void sim_io_init(void)
+{
+ mutex_init(&io.sim_mutex);
+
+ io.ready = 0;
+
+ io.m = SDL_CreateMutex();
+ if (io.m == NULL)
+ {
+ fprintf(stderr, "Failed to create IO mutex\n");
+ exit(-1);
+ }
+
+ io.c = SDL_CreateCond();
+ if (io.c == NULL)
+ {
+ fprintf(stderr, "Failed to create IO cond\n");
+ exit(-1);
+ }
+
+ io.t = SDL_CreateThread(io_thread, NULL);
+ if (io.t == NULL)
+ {
+ fprintf(stderr, "Failed to create IO thread\n");
+ exit(-1);
+ }
+
+ /* Wait for IO thread to lock mutex */
+ while (!io.ready);
+
+ /* Wait for it to unlock */
+ SDL_LockMutex(io.m);
+ /* Free it for another thread */
+ SDL_UnlockMutex(io.m);
+}
+
+void sim_io_shutdown(void)
+{
+ SDL_LockMutex(io.m);
+
+ io.cmd = IO_QUIT;
+
+ SDL_CondSignal(io.c);
+ SDL_UnlockMutex(io.m);
+
+ SDL_WaitThread(io.t, NULL);
+
+ SDL_DestroyMutex(io.m);
+ SDL_DestroyCond(io.c);
+}
+
+static void io_trigger_and_wait(int cmd)
+{
+ /* Lock mutex before setting up new params and signaling condition */
+ SDL_LockMutex(io.m);
+
+ io.cmd = cmd;
+ io.ready = 0;
+
+ /* Get thread started */
+ SDL_CondSignal(io.c);
+
+ /* Let it run */
+ SDL_UnlockMutex(io.m);
+
+ /* Wait for IO to complete */
+ while (!io.ready)
+ yield();
+}
+
MYDIR *sim_opendir(const char *name)
{
char buffer[MAX_PATH]; /* sufficiently big */
@@ -287,6 +415,45 @@ int sim_creat(const char *name)
#endif
}
+ssize_t sim_read(int fd, void *buf, size_t count)
+{
+ ssize_t result;
+
+ mutex_lock(&io.sim_mutex);
+
+ /* Setup parameters */
+ io.fd = fd;
+ io.buf = buf;
+ io.count = count;
+
+ io_trigger_and_wait(IO_READ);
+
+ result = io.result;
+
+ mutex_unlock(&io.sim_mutex);
+
+ return result;
+}
+
+ssize_t sim_write(int fd, const void *buf, size_t count)
+{
+ ssize_t result;
+
+ mutex_lock(&io.sim_mutex);
+
+ io.fd = fd;
+ io.buf = (void*)buf;
+ io.count = count;
+
+ io_trigger_and_wait(IO_WRITE);
+
+ result = io.result;
+
+ mutex_unlock(&io.sim_mutex);
+
+ return result;
+}
+
int sim_mkdir(const char *name)
{
#ifdef __PCTOOL__
diff --git a/uisimulator/sdl/kernel.c b/uisimulator/sdl/kernel.c
index 2b194a2..91d1afa 100644
--- a/uisimulator/sdl/kernel.c
+++ b/uisimulator/sdl/kernel.c
@@ -25,25 +25,19 @@
#include "thread.h"
#include "debug.h"
+volatile long current_tick = 0;
static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
/* This array holds all queues that are initiated. It is used for broadcast. */
static struct event_queue *all_queues[32];
static int num_queues = 0;
-int set_irq_level (int level)
-{
- static int _lv = 0;
- return (_lv = level);
-}
-
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
/* Moves waiting thread's descriptor to the current sender when a
message is dequeued */
static void queue_fetch_sender(struct queue_sender_list *send,
unsigned int i)
{
- int old_level = set_irq_level(15<<4);
struct thread_entry **spp = &send->senders[i];
if(*spp)
@@ -51,8 +45,6 @@ static void queue_fetch_sender(struct queue_sender_list *send,
send->curr_sender = *spp;
*spp = NULL;
}
-
- set_irq_level(old_level);
}
/* 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,
intptr_t retval)
{
(*sender)->retval = retval;
- *sender = NULL;
+ wakeup_thread(sender);
+ if(*sender != NULL)
+ {
+ fprintf(stderr, "queue->send slot ovf: %08X\n", (int)*sender);
+ exit(-1);
+ }
}
/* Releases any waiting threads that are queued with queue_send -
@@ -88,8 +85,12 @@ static void queue_release_all_senders(struct event_queue *q)
void queue_enable_queue_send(struct event_queue *q,
struct queue_sender_list *send)
{
- q->send = send;
- memset(send, 0, sizeof(*send));
+ q->send = NULL;
+ if(send)
+ {
+ q->send = send;
+ memset(send, 0, sizeof(*send));
+ }
}
#endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */
@@ -104,6 +105,11 @@ void queue_init(struct event_queue *q, bool register_queue)
if(register_queue)
{
+ if(num_queues >= 32)
+ {
+ fprintf(stderr, "queue_init->out of queues");
+ exit(-1);
+ }
/* Add it to the all_queues array */
all_queues[num_queues++] = q;
}
@@ -114,13 +120,6 @@ void queue_delete(struct event_queue *q)
int i;
bool found = false;
-#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
- /* Release waiting threads and reply to any dequeued message
- waiting for one. */
- queue_release_all_senders(q);
- queue_reply(q, 0);
-#endif
-
/* Find the queue to be deleted */
for(i = 0;i < num_queues;i++)
{
@@ -141,15 +140,28 @@ void queue_delete(struct event_queue *q)
num_queues--;
}
+
+ /* Release threads waiting on queue head */
+ wakeup_thread(&q->thread);
+
+#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
+ /* Release waiting threads and reply to any dequeued message
+ waiting for one. */
+ queue_release_all_senders(q);
+ queue_reply(q, 0);
+#endif
+
+ q->read = 0;
+ q->write = 0;
}
void queue_wait(struct event_queue *q, struct event *ev)
{
unsigned int rd;
- while(q->read == q->write)
+ if (q->read == q->write)
{
- switch_thread(true, NULL);
+ block_thread(&q->thread);
}
rd = q->read++ & QUEUE_LENGTH_MASK;
@@ -166,11 +178,9 @@ void queue_wait(struct event_queue *q, struct event *ev)
void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks)
{
- unsigned int timeout = current_tick + ticks;
-
- while(q->read == q->write && TIME_BEFORE( current_tick, timeout ))
+ if (q->read == q->write && ticks > 0)
{
- sim_sleep(1);
+ block_thread_w_tmo(&q->thread, ticks);
}
if(q->read != q->write)
@@ -194,7 +204,6 @@ void queue_wait_w_tmo(struct event_queue *q, struct event *ev, int ticks)
void queue_post(struct event_queue *q, long id, intptr_t data)
{
- int oldlevel = set_irq_level(15<<4);
unsigned int wr = q->write++ & QUEUE_LENGTH_MASK;
q->events[wr].id = id;
@@ -213,13 +222,12 @@ void queue_post(struct event_queue *q, long id, intptr_t data)
}
#endif
- set_irq_level(oldlevel);
+ wakeup_thread(&q->thread);
}
#ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
intptr_t queue_send(struct event_queue *q, long id, intptr_t data)
{
- int oldlevel = set_irq_level(15<<4);
unsigned int wr = q->write++ & QUEUE_LENGTH_MASK;
q->events[wr].id = id;
@@ -228,7 +236,6 @@ intptr_t queue_send(struct event_queue *q, long id, intptr_t data)
if(q->send)
{
struct thread_entry **spp = &q->send->senders[wr];
- static struct thread_entry sender;
if(*spp)
{
@@ -236,19 +243,13 @@ intptr_t queue_send(struct event_queue *q, long id, intptr_t data)
queue_release_sender(spp, 0);
}
- *spp = &sender;
-
- set_irq_level(oldlevel);
- while (*spp != NULL)
- {
- switch_thread(true, NULL);
- }
+ wakeup_thread(&q->thread);
- return sender.retval;
+ block_thread(spp);
+ return thread_get_current()->retval;
}
/* Function as queue_post if sending is not enabled */
- set_irq_level(oldlevel);
return 0;
}
@@ -289,8 +290,6 @@ void queue_clear(struct event_queue* q)
void queue_remove_from_head(struct event_queue *q, long id)
{
- int oldlevel = set_irq_level(15<<4);
-
while(q->read != q->write)
{
unsigned int rd = q->read & QUEUE_LENGTH_MASK;
@@ -314,8 +313,6 @@ void queue_remove_from_head(struct event_queue *q, long id)
#endif
q->read++;
}
-
- set_irq_level(oldlevel);
}
int queue_count(const struct event_queue *q)
@@ -335,12 +332,14 @@ int queue_broadcast(long id, intptr_t data)
return num_queues;
}
-void switch_thread(bool save_context, struct thread_entry **blocked_list)
+void yield(void)
{
- (void)save_context;
- (void)blocked_list;
-
- yield ();
+ switch_thread(true, NULL);
+}
+
+void sleep(int ticks)
+{
+ sleep_thread(ticks);
}
void sim_tick_tasks(void)
@@ -370,7 +369,8 @@ int tick_add_task(void (*f)(void))
return 0;
}
}
- DEBUGF("Error! tick_add_task(): out of tasks");
+ fprintf(stderr, "Error! tick_add_task(): out of tasks");
+ exit(-1);
return -1;
}
@@ -395,29 +395,39 @@ int tick_remove_task(void (*f)(void))
multitasking, but is better than nothing at all */
void mutex_init(struct mutex *m)
{
- m->locked = false;
+ m->thread = NULL;
+ m->locked = 0;
}
void mutex_lock(struct mutex *m)
{
- while(m->locked)
- switch_thread(true, NULL);
- m->locked = true;
+ if (test_and_set(&m->locked, 1))
+ {
+ block_thread(&m->thread);
+ }
}
void mutex_unlock(struct mutex *m)
{
- m->locked = false;
+ if (m->thread != NULL)
+ {
+ wakeup_thread(&m->thread);
+ }
+ else
+ {
+ m->locked = 0;
+ }
}
-void spinlock_lock(struct mutex *m)
+void spinlock_lock(struct mutex *l)
{
- while(m->locked)
+ while(test_and_set(&l->locked, 1))
+ {
switch_thread(true, NULL);
- m->locked = true;
+ }
}
-void spinlock_unlock(struct mutex *m)
+void spinlock_unlock(struct mutex *l)
{
- m->locked = false;
+ l->locked = 0;
}
diff --git a/uisimulator/sdl/thread-sdl.c b/uisimulator/sdl/thread-sdl.c
index 90a4ecf..5d2fe0b 100644
--- a/uisimulator/sdl/thread-sdl.c
+++ b/uisimulator/sdl/thread-sdl.c
@@ -21,41 +21,157 @@
#include <SDL.h>
#include <SDL_thread.h>
#include <stdlib.h>
+#include <memory.h>
#include "thread-sdl.h"
#include "kernel.h"
#include "thread.h"
#include "debug.h"
-SDL_Thread *threads[256];
-int threadCount = 0;
-volatile long current_tick = 0;
-SDL_mutex *m;
+/* Define this as 1 to show informational messages that are not errors. */
+#define THREAD_SDL_DEBUGF_ENABLED 0
-void yield(void)
+#if THREAD_SDL_DEBUGF_ENABLED
+#define THREAD_SDL_DEBUGF(...) DEBUGF(__VA_ARGS__)
+static char __name[32];
+#define THREAD_SDL_GET_NAME(thread) \
+ ({ thread_get_name(__name, sizeof(__name)/sizeof(__name[0]), thread); __name; })
+#else
+#define THREAD_SDL_DEBUGF(...)
+#define THREAD_SDL_GET_NAME(thread)
+#endif
+
+#define THREAD_PANICF(str...) \
+ ({ fprintf(stderr, str); exit(-1); })
+
+struct thread_entry threads[MAXTHREADS]; /* Thread entries as in core */
+static SDL_mutex *m;
+static SDL_sem *s;
+static struct thread_entry *running;
+
+void kill_sim_threads(void)
+{
+ int i;
+ SDL_LockMutex(m);
+ for (i = 0; i < MAXTHREADS; i++)
+ {
+ struct thread_entry *thread = &threads[i];
+ if (thread->context.t != NULL)
+ {
+ SDL_LockMutex(m);
+ if (thread->statearg == STATE_RUNNING)
+ SDL_SemPost(s);
+ else
+ SDL_CondSignal(thread->context.c);
+ SDL_KillThread(thread->context.t);
+ SDL_DestroyCond(thread->context.c);
+ }
+ }
+ SDL_DestroyMutex(m);
+ SDL_DestroySemaphore(s);
+}
+
+static int find_empty_thread_slot(void)
+{
+ int n;
+
+ for (n = 0; n < MAXTHREADS; n++)
+ {
+ if (threads[n].name == NULL)
+ break;
+ }
+
+ return n;
+}
+
+static void add_to_list(struct thread_entry **list,
+ struct thread_entry *thread)
+{
+ if (*list == NULL)
+ {
+ /* Insert into unoccupied list */
+ thread->next = thread;
+ thread->prev = thread;
+ *list = thread;
+ }
+ else
+ {
+ /* Insert last */
+ thread->next = *list;
+ thread->prev = (*list)->prev;
+ thread->prev->next = thread;
+ (*list)->prev = thread;
+ }
+}
+
+static void remove_from_list(struct thread_entry **list,
+ struct thread_entry *thread)
{
- static int counter = 0;
+ if (thread == thread->next)
+ {
+ /* The only item */
+ *list = NULL;
+ return;
+ }
- SDL_mutexV(m);
- if (counter++ >= 50)
+ if (thread == *list)
{
- SDL_Delay(1);
- counter = 0;
+ /* List becomes next item */
+ *list = thread->next;
}
- SDL_mutexP(m);
+
+ /* Fix links to jump over the removed entry. */
+ thread->prev->next = thread->next;
+ thread->next->prev = thread->prev;
}
-void sim_sleep(int ticks)
+struct thread_entry *thread_get_current(void)
{
- SDL_mutexV(m);
- SDL_Delay((1000/HZ) * ticks);
- SDL_mutexP(m);
+ return running;
+}
+
+void switch_thread(bool save_context, struct thread_entry **blocked_list)
+{
+ struct thread_entry *current = running;
+
+ SDL_UnlockMutex(m);
+
+ SDL_SemWait(s);
+
+ SDL_LockMutex(m);
+ running = current;
+
+ SDL_SemPost(s);
+
+ (void)save_context; (void)blocked_list;
+}
+
+void sleep_thread(int ticks)
+{
+ struct thread_entry *current;
+
+ current = running;
+ current->statearg = STATE_SLEEPING;
+
+ SDL_CondWaitTimeout(current->context.c, m, (1000/HZ) * ticks);
+ running = current;
+
+ current->statearg = STATE_RUNNING;
}
int runthread(void *data)
{
- SDL_mutexP(m);
- ((void(*)())data) ();
- SDL_mutexV(m);
+ struct thread_entry *current;
+
+ /* Cannot access thread variables before locking the mutex as the
+ data structures may not be filled-in yet. */
+ SDL_LockMutex(m);
+ running = (struct thread_entry *)data;
+ current = running;
+ current->context.start();
+
+ THREAD_SDL_DEBUGF("Thread Done: %d (%s)\n",
+ current - threads, THREAD_SDL_GET_NAME(current));
+ remove_thread(NULL);
return 0;
}
@@ -64,37 +180,198 @@ struct thread_entry*
const char *name)
{
/** Avoid compiler warnings */
- (void)stack;
- (void)stack_size;
- (void)name;
SDL_Thread* t;
+ SDL_cond *cond;
+ int slot;
+
+ THREAD_SDL_DEBUGF("Creating thread: (%s)\n", name ? name : "");
- if (threadCount == 256) {
+ slot = find_empty_thread_slot();
+ if (slot >= MAXTHREADS)
+ {
+ DEBUGF("Failed to find thread slot\n");
return NULL;
}
- t = SDL_CreateThread(runthread, function);
- threads[threadCount++] = t;
+ cond = SDL_CreateCond();
+ if (cond == NULL)
+ {
+ DEBUGF("Failed to create condition variable\n");
+ return NULL;
+ }
+
+ t = SDL_CreateThread(runthread, &threads[slot]);
+ if (t == NULL)
+ {
+ DEBUGF("Failed to create SDL thread\n");
+ SDL_DestroyCond(cond);
+ return NULL;
+ }
+
+ threads[slot].stack = stack;
+ threads[slot].stack_size = stack_size;
+ threads[slot].name = name;
+ threads[slot].statearg = STATE_RUNNING;
+ threads[slot].context.start = function;
+ threads[slot].context.t = t;
+ threads[slot].context.c = cond;
+
+ THREAD_SDL_DEBUGF("New Thread: %d (%s)\n",
+ slot, THREAD_SDL_GET_NAME(&threads[slot]));
+
+ return &threads[slot];
+}
+
+void block_thread(struct thread_entry **list)
+{
+ struct thread_entry *thread = running;
+
+ thread->statearg = STATE_BLOCKED;
+ add_to_list(list, thread);
+
+ SDL_CondWait(thread->context.c, m);
+ running = thread;
+}
+
+void block_thread_w_tmo(struct thread_entry **list, int ticks)
+{
+ struct thread_entry *thread = running;
+
+ thread->statearg = STATE_BLOCKED_W_TMO;
+ add_to_list(list, thread);
+
+ SDL_CondWaitTimeout(thread->context.c, m, (1000/HZ) * ticks);
+ running = thread;
+
+ if (thread->statearg == STATE_BLOCKED_W_TMO)
+ {
+ /* Timed out */
+ remove_from_list(list, thread);
+ thread->statearg = STATE_RUNNING;
+ }
+}
+
+void wakeup_thread(struct thread_entry **list)
+{
+ struct thread_entry *thread = *list;
- yield();
+ if (thread == NULL)
+ {
+ return;
+ }
- /* The return value is never de-referenced outside thread.c so this
- nastiness should be fine. However, a better solution would be nice.
- */
- return (struct thread_entry*)t;
+ switch (thread->statearg)
+ {
+ case STATE_BLOCKED:
+ case STATE_BLOCKED_W_TMO:
+ remove_from_list(list, thread);
+ thread->statearg = STATE_RUNNING;
+ SDL_CondSignal(thread->context.c);
+ break;
+ }
}
void init_threads(void)
{
+ int slot;
+
m = SDL_CreateMutex();
+ s = SDL_CreateSemaphore(0);
+
+ memset(threads, 0, sizeof(threads));
+
+ slot = find_empty_thread_slot();
+ if (slot >= MAXTHREADS)
+ {
+ THREAD_PANICF("Couldn't find slot for main thread.\n");
+ }
+
+ threads[slot].stack = " ";
+ threads[slot].stack_size = 8;
+ threads[slot].name = "main";
+ threads[slot].statearg = STATE_RUNNING;
+ threads[slot].context.t = gui_thread;
+ threads[slot].context.c = SDL_CreateCond();
+
+ running = &threads[slot];
+
+ THREAD_SDL_DEBUGF("First Thread: %d (%s)\n",
+ slot, THREAD_SDL_GET_NAME(&threads[slot]));
+
+ if (SDL_LockMutex(m) == -1) {
+ THREAD_PANICF("Couldn't lock mutex\n");
+ }
- if (SDL_mutexP(m) == -1) {
- fprintf(stderr, "Couldn't lock mutex\n");
- exit(-1);
+ if (SDL_SemPost(s) == -1) {
+ THREAD_PANICF("Couldn't post to semaphore\n");
}
}
void remove_thread(struct thread_entry *thread)
{
- SDL_KillThread((SDL_Thread*) thread);
+ struct thread_entry *current = running;
+ SDL_Thread *t;
+ SDL_cond *c;
+
+ if (thread == NULL)
+ {
+ thread = current;
+ }
+
+ t = thread->context.t;
+ c = thread->context.c;
+ thread->context.t = NULL;
+
+ if (thread != current)
+ {
+ if (thread->statearg == STATE_RUNNING)
+ SDL_SemPost(s);
+ else
+ SDL_CondSignal(c);
+ }
+
+ THREAD_SDL_DEBUGF("Removing thread: %d (%s)\n",
+ thread - threads, THREAD_SDL_GET_NAME(thread));
+
+ thread->name = NULL;
+
+ SDL_DestroyCond(c);
+
+ if (thread == current)
+ {
+ SDL_UnlockMutex(m);
+ }
+
+ SDL_KillThread(t);
+}
+
+int thread_stack_usage(const struct thread_entry *thread)
+{
+ return 50;
+ (void)thread;
+}
+
+int thread_get_status(const struct thread_entry *thread)
+{
+ return thread->statearg;
+}
+
+/* Return name if one or ID if none */
+void thread_get_name(char *buffer, int size,
+ struct thread_entry *thread)
+{
+ if (size <= 0)
+ return;
+
+ *buffer = '\0';
+
+ if (thread)
+ {
+ /* Display thread name if one or ID if none */
+ bool named = thread->name && *thread->name;
+ const char *fmt = named ? "%s" : "%08lX";
+ intptr_t name = named ?
+ (intptr_t)thread->name : (intptr_t)thread;
+ snprintf(buffer, size, fmt, name);
+ }
}
diff --git a/uisimulator/sdl/thread-sdl.h b/uisimulator/sdl/thread-sdl.h
index 0bb6ded..20641fb 100644
--- a/uisimulator/sdl/thread-sdl.h
+++ b/uisimulator/sdl/thread-sdl.h
@@ -22,9 +22,8 @@
#include "SDL_thread.h"
-extern SDL_Thread* threads[256];
-extern int threadCount;
-extern SDL_mutex* mutex;
+extern SDL_Thread *gui_thread; /* The "main" thread */
+void kill_sim_threads(); /* Kill all the rockbox sim threads */
#endif /* #ifndef __THREADSDL_H__ */
diff --git a/uisimulator/sdl/uisdl.c b/uisimulator/sdl/uisdl.c
index 052fd4a..37a0e6f 100644
--- a/uisimulator/sdl/uisdl.c
+++ b/uisimulator/sdl/uisdl.c
@@ -41,6 +41,8 @@
extern void app_main (void *); /* mod entry point */
extern void new_key(int key);
extern void sim_tick_tasks(void);
+extern void sim_io_init(void);
+extern void sim_io_shutdown(void);
void button_event(int key, bool pressed);
@@ -167,16 +169,9 @@ bool gui_startup(void)
bool gui_shutdown(void)
{
- int i;
-
- SDL_KillThread(gui_thread);
SDL_RemoveTimer(tick_timer_id);
-
- for (i = 0; i < threadCount; i++)
- {
- SDL_KillThread(threads[i]);
- }
-
+ kill_sim_threads();
+ sim_io_shutdown();
return true;
}
@@ -236,6 +231,8 @@ int main(int argc, char *argv[])
background = false;
}
+ sim_io_init();
+
if (!gui_startup())
return -1;