title: tidy code for asynchronous IO
body: <p>Whilst asynchronous IO (non-blocking descriptors with select/poll/epoll/kqueue etc) is not the most documented thing on the web, there are a handful of good examples.</p>
  
  <p>However, all these examples, having determined the handles that are returned by the call, just have a '<code>do_some_io(fd)</code>' stub.  They don't really explain how to best approach the actual asynchronous IO in such a method.</p>
  
  <p>Blocking IO is very tidy and straightforward to read code.  Non-blocking, async IO is, on the other hand, hairy and messy.</p>
  
  <p>What approaches are there?  What are robust and readable?</p>
  
  <pre><code>void do_some_io(int fd) {
    switch(state) {
      case STEP1:
         ... async calls
         if(io_would_block)
            return;
         state = STEP2;
      case STEP2:
         ... more async calls
         if(io_would_block)
            return;
         state = STEP3;
      case STEP3:
         ...
    }
  }
  </code></pre>
  
  <p>or perhaps (ab)using GCC's computed gotos:</p>
  
  <pre><code>#define concatentate(x,y) x##y
  #define async_read_xx(var,bytes,line)       \
     concatentate(jmp,line):                  \
     if(!do_async_read(bytes,&amp;var)) {         \
         schedule(EPOLLIN);                   \
         jmp_read = &amp;&amp;concatentate(jmp,line); \
         return;                              \
  }
  
  // macros for making async code read like sync code
  #define async_read(var,bytes) \
      async_read_xx(var,bytes,__LINE__)
  
  #define async_resume()            \
       if(jmp_read) {               \
           void* target = jmp_read; \
           jmp_read = NULL;         \
           goto *target;            \
       }
  
  void do_some_io() {
     async_resume();
     async_read(something,sizeof(something));
     async_read(something_else,sizeof(something_else));
  }
  </code></pre>
  
  <p>Or perhaps C++ exceptions and a state machine, so worker functions can trigger the abort/resume bit, or perhaps a table-driven state-machine?</p>
  
  <p>Its not how to make it work, its how to make it maintainable that I'm chasing!</p>