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) 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 9d46ea4510..bdb59e6005 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 c3e5a5b714..2580d43eb0 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 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 ); #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 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); #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 2915d23207..19bf9e12fc 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 989f50a283..9a94e91263 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 3f7087876a..127a1c36f1 100644 --- a/uisimulator/common/io.c +++ b/uisimulator/common/io.c @@ -47,7 +47,10 @@ #define MAX_PATH 260 #include - +#include +#include +#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 2b194a24ae..91d1afa1b9 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; + wakeup_thread(&q->thread); - set_irq_level(oldlevel); - while (*spp != NULL) - { - switch_thread(true, NULL); - } - - 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 90a4ecf4a7..5d2fe0b522 100644 --- a/uisimulator/sdl/thread-sdl.c +++ b/uisimulator/sdl/thread-sdl.c @@ -21,41 +21,157 @@ #include #include #include +#include #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) { - static int counter = 0; - - SDL_mutexV(m); - if (counter++ >= 50) + int i; + SDL_LockMutex(m); + for (i = 0; i < MAXTHREADS; i++) { - SDL_Delay(1); - counter = 0; + 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_mutexP(m); + SDL_DestroyMutex(m); + SDL_DestroySemaphore(s); } -void sim_sleep(int ticks) +static int find_empty_thread_slot(void) { - SDL_mutexV(m); - SDL_Delay((1000/HZ) * ticks); - SDL_mutexP(m); + 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) +{ + if (thread == thread->next) + { + /* The only item */ + *list = NULL; + return; + } + + if (thread == *list) + { + /* List becomes next item */ + *list = thread->next; + } + + /* Fix links to jump over the removed entry. */ + thread->prev->next = thread->next; + thread->next->prev = thread->prev; +} + +struct thread_entry *thread_get_current(void) +{ + 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; - if (threadCount == 256) { + THREAD_SDL_DEBUGF("Creating thread: (%s)\n", name ? name : ""); + + 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; + } - yield(); + t = SDL_CreateThread(runthread, &threads[slot]); + if (t == NULL) + { + DEBUGF("Failed to create SDL thread\n"); + SDL_DestroyCond(cond); + return NULL; + } - /* 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; + 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; + + if (thread == NULL) + { + return; + } + + 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) { - m = SDL_CreateMutex(); + int slot; - if (SDL_mutexP(m) == -1) { - fprintf(stderr, "Couldn't lock mutex\n"); - exit(-1); + 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_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 0bb6ded0d5..20641fb673 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 052fd4af83..37a0e6fe7a 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;