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)