diff --git a/firmware/target/hosted/sdl/button-sdl.c b/firmware/target/hosted/sdl/button-sdl.c
index 8375151..29c697f 100644
--- a/firmware/target/hosted/sdl/button-sdl.c
+++ b/firmware/target/hosted/sdl/button-sdl.c
@@ -284,6 +284,9 @@ static bool event_handler(SDL_Event *event)
case SDL_USEREVENT:
return true;
break;
+ case SDL_USEREVENT+1:
+ sim_io_thread_fn((SDL_UserEvent*)event);
+ break;
#ifdef HAVE_DYNAMIC_LCD_SIZE
case SDL_VIDEORESIZE:
/* NOTE: SDL 1.2.15 has a bug where this event is not always received */
@@ -295,25 +298,58 @@ static bool event_handler(SDL_Event *event)
return false;
}

+/* SDL_WaitEvent is not suitable for very fast event handling, as it
+ * internally calls SDL_Delay(10) internally
+ * http://gameprogrammer.com/fastevents/fastevents1.html
+ *
+ * We replace it with an equivalent SDL_PollEvent mechanism which can
+ * be interrupted with gui_message_force_timeout() to not wait the full 10ms */
+static SDL_cond *ev_cond, *ev_wait;
+void gui_message_push_event(SDL_Event *ev)
+{
+ while (!ev_cond || !ev_wait) SDL_Delay(10);
+
+ SDL_mutex *m = SDL_CreateMutex();
+ while(SDL_PushEvent(ev) == -1)
+ SDL_CondWait(ev_cond, m);
+ SDL_CondSignal(ev_cond);
+}
+
void gui_message_loop(void)
{
SDL_Event event;
bool quit;
+ int result;
+
+ SDL_mutex *m = SDL_CreateMutex();
+ ev_cond = SDL_CreateCond();
+ ev_wait = SDL_CreateCond();
+
+ SDL_LockMutex(m);

do {
/* wait for the next event */
- if(SDL_WaitEvent(&event) == 0) {
- printf("SDL_WaitEvent() error\n");
+ SDL_CondWaitTimeout(ev_cond, m, 10);
+ result = SDL_PollEvent(&event);
+ if (result == 0) {
+ continue;
+ }
+ else if (result < 0) {
+ printf("SDL_PollEvent() error\n");
return; /* error, out of here */
}
+ else
+ SDL_CondSignal(ev_wait);

sim_enter_irq_handler();
quit = event_handler(&event);
sim_exit_irq_handler();
-
} while(!quit);
+
+ SDL_UnlockMutex(m);
}

+
static void button_event(int key, bool pressed)
{
int new_btn = 0;
diff --git a/uisimulator/common/io.c b/uisimulator/common/io.c
index 6f9f4b2..1dc7959 100644
--- a/uisimulator/common/io.c
+++ b/uisimulator/common/io.c
@@ -46,13 +46,8 @@
#include "dir-win32.h"
#endif

+#include <SDL.h>
#include <fcntl.h>
-#ifdef HAVE_SDL_THREADS
-#include "thread-sdl.h"
-#else
-#define sim_thread_unlock() NULL
-#define sim_thread_lock(a)
-#endif
#include "thread.h"
#include "kernel.h"
#include "debug.h"
@@ -220,22 +215,18 @@ enum io_dir

struct sim_io
{
- struct mutex sim_mutex; /* Rockbox mutex */
+ struct semaphore sem; /* Rockbox semaphore */
int cmd; /* The command to perform */
int ready; /* I/O ready flag - 1= ready */
int fd; /* The file to read/write */
- void *buf; /* The buffer to read/write */
+ const void *buf; /* The buffer to read/write */
size_t count; /* Number of bytes to read/write */
- size_t accum; /* Acculated bytes transferred */
+ size_t result; /* Bytes transferred */
};

-static struct sim_io io;
-
int ata_init(void)
{
/* Initialize the rockbox kernel objects on a rockbox thread */
- mutex_init(&io.sim_mutex);
- io.accum = 0;
return 1;
}

@@ -244,39 +235,60 @@ int ata_spinup_time(void)
return HZ;
}

-static ssize_t io_trigger_and_wait(enum io_dir cmd)
+
+int sim_io_thread_fn(SDL_UserEvent *ev)
{
- void *mythread = NULL;
+ struct sim_io *io = ev->data1;
ssize_t result;

- if (io.count > IO_YIELD_THRESHOLD ||
- (io.accum += io.count) >= IO_YIELD_THRESHOLD)
- {
- /* Allow other rockbox threads to run */
- io.accum = 0;
- mythread = sim_thread_unlock();
- }
+ //~ printf("%s() enter\n", __func__);

- switch (cmd)
+ switch (io->cmd)
{
case IO_READ:
- result = read(io.fd, io.buf, io.count);
+ result = read(io->fd, (void*)io->buf, io->count);
break;
case IO_WRITE:
- result = write(io.fd, io.buf, io.count);
+ result = write(io->fd, io->buf, io->count);
break;
/* shut up gcc */
default:
result = -1;
}

- /* Regain our status as current */
- if (mythread != NULL)
- {
- sim_thread_lock(mythread);
- }
+ io->result = result;
+ semaphore_release(&io->sem);
+
+ //~ printf("%s() exit\n", __func__);

- return result;
+ return 0;
+}
+
+ssize_t io_trigger_and_wait(enum io_dir dir, int fd, const void *buf, size_t count)
+{
+ struct sim_io io;
+ SDL_UserEvent ev;
+
+ io.cmd = dir;
+ io.fd = fd;
+ io.buf = buf;
+ io.count = count;
+
+ semaphore_init(&io.sem, 1, 0);
+
+ //~ printf("createThread()\n");
+
+ memset(&ev, 0, sizeof(ev));
+ ev.type = SDL_USEREVENT+1;
+ ev.data1 = &io;
+ gui_message_push_event((SDL_Event*)&ev);
+
+ //~ printf("wait()\n");
+
+ semaphore_wait(&io.sem, TIMEOUT_BLOCK);
+
+ //~ printf("wait() ret\n");
+ return io.result;
}

#if !defined(__PCTOOL__) && !defined(APPLICATION)
@@ -445,37 +457,18 @@ int sim_creat(const char *name, mode_t mode)

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;
-
- result = io_trigger_and_wait(IO_READ);
-
- mutex_unlock(&io.sim_mutex);
-
- return result;
+ /* direct call for small amounts */
+ if (count < IO_YIELD_THRESHOLD)
+ return read(fd, buf, count);
+ return io_trigger_and_wait(IO_READ, fd, buf, count);
}

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;
-
- result = io_trigger_and_wait(IO_WRITE);
-
- mutex_unlock(&io.sim_mutex);
-
- return result;
+ /* direct call for small amounts */
+ if (count < IO_YIELD_THRESHOLD)
+ return write(fd, buf, count);
+ return io_trigger_and_wait(IO_WRITE, fd, buf, count);
}

int sim_mkdir(const char *name)