title: Opening a serial port on OS X hangs forever without O_NONBLOCK flag
body: <p>I have a serial to USB converter (FTDI, drivers installed from <a href="http://www.ftdichip.com/Drivers/VCP.htm" rel="nofollow">http://www.ftdichip.com/Drivers/VCP.htm</a>) connecting a serial device to a MacBook Air. It shows up on the MacBook as both <code>/dev/cu.usbserial-A4017CQY</code> and <code>/dev/tty.usbserial-A4017CQY</code>. <s>All behaviour I describe is identical regardless of which of these two I use.</s></p>
  
  <p><strong>Edit: Using <code>/dev/cu.*</code> did solve the problem. I'm not sure why it seemed not to work when I first posted this question. Thanks to duskwuff for pointing me in the right direction, though he has his TTY names backwards: <code>/dev/tty.*</code> will wait for flow control, while <code>/dev/cu.*</code> will not.</strong></p>
  
  <p>The first problem I encountered was that the syscall to <code>open()</code> would block forever if I did not use the <code>O_NONBLOCK</code> flag. Using the flag, I get a good file descriptor, but <code>write()</code> does not seem to actually write (though it returns just fine claiming to have written the bytes), and <code>read()</code> fails with the error "Resource temporarily unavailable".</p>
  
  <p><code>stty -af /dev/cu.usbserial-A4017CQY</code> shows the settings just fine, but if I try to change them with a command like <code>stty -f /dev/cu.usbserial-A4017CQY -clocal</code>, they do appear to be changed when displayed with a successive call to <code>stty</code>.</p>
  
  <p>If I use <code>select()</code> to wait for the device to become ready before reading/writing, it reports after a short time that it is ready to write, but never to read. This gels with how <code>write()</code> completes without complaint, while <code>read()</code> fails. Note that the data written never does actually make it to the device.</p>
  
  <p>The entire test program I wrote to debug this is below:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;fcntl.h&gt;
  #include &lt;termios.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;sys/select.h&gt;
  
  #define SYSCALL(A) do { ret = A; if (ret == -1) { perror(#A); return -1; } else printf("%s returned %d\n", #A, ret); } while (0)
  int ret; /* necessary for SYSCALL */
  
  int main()
  {
      struct termios tio;
      char buf[256];
      int fd = open("/dev/cu.usbserial-A4017CQY", 
              O_RDWR | O_NOCTTY | O_NONBLOCK);
      fd_set rfds, wfds, xfds;
      struct timeval to;
      to.tv_sec = 5;
      to.tv_usec = 0;
  
      SYSCALL(tcgetattr(fd, &amp;tio));
  
      cfmakeraw(&amp;tio);
  
      tio.c_cflag = CS8|CREAD|CLOCAL;
      tio.c_cc[VMIN] = 1;
      tio.c_cc[VTIME] = 1;
  
      cfsetispeed(&amp;tio, B115200);
      cfsetospeed(&amp;tio, B115200);
  
      SYSCALL(tcsetattr(fd, TCSANOW, &amp;tio));
  
      FD_ZERO(&amp;rfds);
      FD_ZERO(&amp;wfds);
      FD_ZERO(&amp;xfds);
      FD_SET(fd, &amp;rfds);
      FD_SET(fd, &amp;wfds);
      FD_SET(fd, &amp;xfds);
  
      int ret = select(fd+1, &amp;rfds, NULL, &amp;xfds, &amp;to);
      if (ret == -1) perror("select");
      else if (ret &gt; 0)
      {
          if(FD_ISSET(fd, &amp;rfds))
              puts("Ready to read");
          if(FD_ISSET(fd, &amp;wfds))
              puts("Ready to write");
          if(FD_ISSET(fd, &amp;xfds))
              puts("Exception!");
      }
      else puts("Timed out!");
  
      SYSCALL(write(fd, "/home\n", 5));
      SYSCALL(read(fd, buf, 256));
  
      return 0;
  }
  </code></pre>