=== On Unix: === when a green thread wants to do a blocking read, for(;;) { read(fd,buf,len) if(errno is EINTR) continue else if(errno is EAGAIN) { waiting_fds.add(fd,current_thread) suspend(current_thread) continue } else { /* data is now in 'buf' */ break } } then you have an IO thread that runs when no other green threads are runnable, for(;;) { select(waiting_fds) /* or poll, kqueue, epoll, etc */ foreach(fd in waiting_fds) { if(can_read(fd)) wake_up(waiting_fds.get(fd)) } yield() } === On Windows: === when a green thread wants to do a blocking read, read(fd,buf,len,&completion) waiting_completions.add(completion,current_thread) suspend(current_thread) /* data is now in buf */ then you have an IO thread that runs when no other green threads are runnable, for(;;) { completion = GetQueuedCompletionStatus(...) wake_up(waiting_completions.get(completion)) yield() }