title: FTDI D2XX C# .NET Wrapper running on Linux / Mono - SetEventNotification being triggered seems to crash program
body: <p>I'm working on porting an existing, functional C# application we have that uses the  <a href="http://www.ftdichip.com/Support/SoftwareExamples/CodeExamples/CSharp/FTD2XX_NETclass.zip" rel="nofollow">FTDI D2XX C# .NET wrapper</a> on Windows, over to Linux and Mono.
  I have followed directions given on installing the <a href="http://www.ftdichip.com/Drivers/D2XX.htm" rel="nofollow">Linux D2XX driver</a>. When it's detected that we're running on Linux we look for and load the Linux driver in the C# .NET wrapper, instead of the Windows driver.</p>
  
  <p>After doing that work, much of our application code is still fine, but it appears that when the event set with the SetEventNotification function is triggered on an FT_EVENT_RXCHAR event, the application crashes.</p>
  
  <p>The flow of the C# application is to:</p>
  
  <ol>
  <li>Set up communication with the FTDI device</li>
  <li>SetEventNotification to be notified when new data is available from the FTDI device</li>
  <li>Ping the FTDI device, letting it know we're ready and we'd like some data</li>
  <li>When notified of new data (from using the SetEventNotification), do some things with it</li>
  </ol>
  
  <p>A bit more detail:</p>
  
  <ul>
  <li>Read'ing and Write'ing with the C# wrapper seem to work fine on Linux / Mono
  
  <ul>
  <li>The device is first pinged using a Write, then the following Reads are successful</li>
  </ul></li>
  <li>Using example code provided in the D2XX Programmer's Guide, C code written on Linux doesn't crash when using SetEventNotification</li>
  <li>The (apparent) alternative, using the C# wrapper's Read on a desired number of bytes appears to be working appropriately on Linux / Mono</li>
  </ul>
  
  <p>A couple of questions:</p>
  
  <ol>
  <li>Has anyone worked with the C# .NET Wrapper for the D2XX drivers on Linux / Mono and had this issue?</li>
  <li>C# Wrapper's SetEventNotification expects an EventWaitHandle, which then retrieves the native operating system handle by using SafeWaitHandle. Is it possible that the issue is here?</li>
  </ol>
  
  <p>Any insight offered is much appreciated.</p>
  
  <p><strong>Edit:</strong></p>
  
  <p>The stack trace is now attached below.</p>
  
  <p>I tried to move to a polling approach, but it appears that it's possible to have a "frame" of data not fully written when we perform an FTDI Read and we'll have a gap in the data.</p>
  
  <p>I have reached out to FTDI for some guidance on the issue. Will update if I hear back something actionable.</p>
  
  <pre><code># mono --debug ./CT4USB.exe
  
  Native stacktrace:
  
      mono() [0x49d5fc]
      mono() [0x424a0e]
      /lib/x86_64-linux-gnu/libpthread.so.0(+0x10330) [0x7f3253539330]
      /lib/x86_64-linux-gnu/libpthread.so.0(pthread_mutex_lock+0x4) [0x7f3253533404]
      /usr/local/lib/libftd2xx.so(+0x12f52) [0x7f324b9d1f52]
      /usr/local/lib/libftd2xx.so(+0x134f1) [0x7f324b9d24f1]
      /usr/local/lib/libftd2xx.so(processor_thread+0x21b) [0x7f324b9d29bd]
      /lib/x86_64-linux-gnu/libpthread.so.0(+0x8184) [0x7f3253531184]
      /lib/x86_64-linux-gnu/libc.so.6(clone+0x6d) [0x7f325325e37d]
  
  Debug info from gdb:
  
  [New LWP 5654]
  [New LWP 5653]
  [New LWP 5652]
  [New LWP 5645]
  [New LWP 5644]
  [New LWP 5643]
  [New LWP 5642]
  [New LWP 5641]
  [New LWP 5640]
  [New LWP 5639]
  [Thread debugging using libthread_db enabled]
  Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
  0x00007f3253538b9d in nanosleep () at ../sysdeps/unix/syscall-template.S:81
  81  ../sysdeps/unix/syscall-template.S: No such file or directory.
    Id   Target Id         Frame 
    11   Thread 0x7f32523ff700 (LWP 5639) "mono" pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
    10   Thread 0x7f3252a81700 (LWP 5640) "Finalizer" sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:85
    9    Thread 0x7f3253efa700 (LWP 5641) "mono" __clock_nanosleep (clock_id=1, flags=1, req=0x7f3253ef9d80, rem=0x7f325326c974 &lt;__clock_nanosleep+132&gt;) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:49
    8    Thread 0x7f324bfff700 (LWP 5642) "Threadpool work" pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
    7    Thread 0x7f324bdfe700 (LWP 5643) "Threadpool work" pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
    6    Thread 0x7f324b9be700 (LWP 5644) "Threadpool work" 0x00007f3253250fdd in poll () at ../sysdeps/unix/syscall-template.S:81
    5    Thread 0x7f324b1bd700 (LWP 5645) "Threadpool work" 0x00007f3253250fdd in poll () at ../sysdeps/unix/syscall-template.S:81
    4    Thread 0x7f324a7ff700 (LWP 5652) "Threadpool work" pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
    3    Thread 0x7f3249ffe700 (LWP 5653) "Threadpool work" 0x00007f3253538ed9 in __libc_waitpid (pid=5655, stat_loc=0x7f3249ffce4c, options=0) at ../sysdeps/unix/sysv/linux/waitpid.c:40
    2    Thread 0x7f32497fd700 (LWP 5654) "Threadpool work" pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
  * 1    Thread 0x7f325405d7c0 (LWP 5638) "mono" 0x00007f3253538b9d in nanosleep () at ../sysdeps/unix/syscall-template.S:81
  
  Thread 11 (Thread 0x7f32523ff700 (LWP 5639)):
  #0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
  #1  0x00000000005f9aec in ?? ()
  #2  0x00007f3253531184 in start_thread (arg=0x7f32523ff700) at pthread_create.c:312
  #3  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
  
  Thread 10 (Thread 0x7f3252a81700 (LWP 5640)):
  #0  sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:85
  #1  0x000000000061de28 in mono_sem_wait ()
  #2  0x00000000005a2076 in ?? ()
  #3  0x00000000005843d3 in ?? ()
  #4  0x0000000000624666 in ?? ()
  #5  0x00007f3253531184 in start_thread (arg=0x7f3252a81700) at pthread_create.c:312
  #6  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
  
  Thread 9 (Thread 0x7f3253efa700 (LWP 5641)):
  #0  __clock_nanosleep (clock_id=1, flags=1, req=0x7f3253ef9d80, rem=0x7f325326c974 &lt;__clock_nanosleep+132&gt;) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:49
  #1  0x00000000006122c8 in ?? ()
  #2  0x0000000000588244 in ?? ()
  #3  0x00000000005843d3 in ?? ()
  #4  0x0000000000624666 in ?? ()
  #5  0x00007f3253531184 in start_thread (arg=0x7f3253efa700) at pthread_create.c:312
  #6  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
  
  Thread 8 (Thread 0x7f324bfff700 (LWP 5642)):
  #0  pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
  #1  0x00000000005fef90 in ?? ()
  #2  0x00000000006117a2 in ?? ()
  #3  0x00000000005840fd in ?? ()
  #4  0x00000000005853e6 in ?? ()
  #5  0x00000000418b9b0e in ?? ()
  #6  0x0000000000000000 in ?? ()
  
  Thread 7 (Thread 0x7f324bdfe700 (LWP 5643)):
  #0  pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
  #1  0x000000000061b982 in ?? ()
  #2  0x0000000000586b58 in ?? ()
  #3  0x00000000005843d3 in ?? ()
  #4  0x0000000000624666 in ?? ()
  #5  0x00007f3253531184 in start_thread (arg=0x7f324bdfe700) at pthread_create.c:312
  #6  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
  
  Thread 6 (Thread 0x7f324b9be700 (LWP 5644)):
  #0  0x00007f3253250fdd in poll () at ../sysdeps/unix/syscall-template.S:81
  #1  0x00007f324b9f2a52 in linux_netlink_event_thread_main () from /usr/local/lib/libftd2xx.so
  #2  0x00007f3253531184 in start_thread (arg=0x7f324b9be700) at pthread_create.c:312
  #3  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
  
  Thread 5 (Thread 0x7f324b1bd700 (LWP 5645)):
  #0  0x00007f3253250fdd in poll () at ../sysdeps/unix/syscall-template.S:81
  #1  0x00007f324b9eb14e in handle_events () from /usr/local/lib/libftd2xx.so
  #2  0x00007f324b9eb569 in libusb_handle_events_timeout_completed () from /usr/local/lib/libftd2xx.so
  #3  0x00007f324b9eb674 in libusb_handle_events_timeout () from /usr/local/lib/libftd2xx.so
  #4  0x00007f324b9c924f in poll_async_libusb () from /usr/local/lib/libftd2xx.so
  #5  0x00007f3253531184 in start_thread (arg=0x7f324b1bd700) at pthread_create.c:312
  #6  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
  
  Thread 4 (Thread 0x7f324a7ff700 (LWP 5652)):
  #0  pthread_cond_timedwait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S:238
  #1  0x00007f324b9cf9fe in EventWait () from /usr/local/lib/libftd2xx.so
  #2  0x00007f324b9d2651 in reader_thread () from /usr/local/lib/libftd2xx.so
  #3  0x00007f3253531184 in start_thread (arg=0x7f324a7ff700) at pthread_create.c:312
  #4  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
  
  Thread 3 (Thread 0x7f3249ffe700 (LWP 5653)):
  #0  0x00007f3253538ed9 in __libc_waitpid (pid=5655, stat_loc=0x7f3249ffce4c, options=0) at ../sysdeps/unix/sysv/linux/waitpid.c:40
  #1  0x000000000049d689 in ?? ()
  #2  0x0000000000424a0e in ?? ()
  #3  &lt;signal handler called&gt;
  #4  __GI___pthread_mutex_lock (mutex=0x0) at ../nptl/pthread_mutex_lock.c:66
  #5  0x00007f324b9d1f52 in signalSomeEvents () from /usr/local/lib/libftd2xx.so
  #6  0x00007f324b9d24f1 in ProcessBulkInData () from /usr/local/lib/libftd2xx.so
  #7  0x00007f324b9d29bd in processor_thread () from /usr/local/lib/libftd2xx.so
  #8  0x00007f3253531184 in start_thread (arg=0x7f3249ffe700) at pthread_create.c:312
  #9  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
  
  Thread 2 (Thread 0x7f32497fd700 (LWP 5654)):
  #0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
  #1  0x00007f324b9cf904 in EventWait () from /usr/local/lib/libftd2xx.so
  #2  0x00007f324b9cbfd1 in write_thread () from /usr/local/lib/libftd2xx.so
  #3  0x00007f3253531184 in start_thread (arg=0x7f32497fd700) at pthread_create.c:312
  #4  0x00007f325325e37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
  
  Thread 1 (Thread 0x7f325405d7c0 (LWP 5638)):
  #0  0x00007f3253538b9d in nanosleep () at ../sysdeps/unix/syscall-template.S:81
  #1  0x00000000005fedfa in ?? ()
  #2  0x000000000061101b in ?? ()
  #3  0x000000000058415e in ?? ()
  #4  0x0000000000585309 in ?? ()
  #5  0x00000000418b3e8d in ?? ()
  #6  0x00000000015de450 in ?? ()
  #7  0x00007ffc9ba9b960 in ?? ()
  #8  0x00007f3253fb8130 in ?? ()
  #9  0x00007f3252400578 in ?? ()
  #10 0x00007f3252400528 in ?? ()
  #11 0x00000000015a41e0 in ?? ()
  #12 0x00000000418b3e07 in ?? ()
  #13 0x00007ffc9ba9b4d0 in ?? ()
  #14 0x00007ffc9ba9b450 in ?? ()
  /build/buildd/gdb-7.7.1/gdb/dwarf2-frame.c:692: internal-error: Unknown CFI encountered.
  A problem internal to GDB has been detected,
  further debugging may prove unreliable.
  Quit this debugging session? (y or n) [answered Y; input not from terminal]
  /build/buildd/gdb-7.7.1/gdb/dwarf2-frame.c:692: internal-error: Unknown CFI encountered.
  A problem internal to GDB has been detected,
  further debugging may prove unreliable.
  Create a core file of GDB? (y or n) [answered Y; input not from terminal]
  
  =================================================================
  Got a SIGSEGV while executing native code. This usually indicates
  a fatal error in the mono runtime or one of the native libraries 
  used by your application.
  =================================================================
  
  Aborted (core dumped)
  </code></pre>
  
  <p><strong>Edit the 2nd:</strong></p>
  
  <p>The representations of Mono's SafeWaitHandle and the expected parameter to SetEventNotification are completely different. Because the FTDI D2XX library is trying to treat the SafeWaitHandle as an EVENT_HANDLE (defined in the ftd2xx.h header; basically a pthread_cond_t and pthread_mutex_t), I think that's why we get a crash.</p>
  
  <p>I think I can proceed by using P/Invoke with libpthread in the FTDI D2XX C# .NET wrapper to perform the necessary conversions between pthread conditions and mutexes and Mono SafeWaitHandle's. At this point, I need working C code which will loop and block on pthread_cond_wait for FTDI D2XX. I haven't gotten that code working yet. It's listed below if anyone has advice:</p>
  
  <pre><code>/*/*
  
  gcc -o SetEventNotification_separate_thread SetEventNotification_separate_thread.c -lpthread -lftd2xx -Wl,-rpath /usr/local/lib
  
  */
  
  #include &lt;stdlib.h&gt;
  #include &lt;pthread.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdint.h&gt;
  #include "../ftd2xx.h"
  
  static FT_HANDLE ft_handle;
  
  
  // Seems like this sort of stuff should have been provided by FTDI
  static const char *ft_errors[] =
  {
      [FT_OK] = "Success",
      [FT_INVALID_HANDLE] = "Invalid device handle",
      [FT_DEVICE_NOT_FOUND] = "Device not found",
      [FT_DEVICE_NOT_OPENED] = "Device not opened",
      [FT_IO_ERROR] = "Input/output error",
      [FT_INSUFFICIENT_RESOURCES] = "Insufficient resources",
      [FT_INVALID_PARAMETER] = "Invalid parameter",
      [FT_INVALID_BAUD_RATE] = "Invalid baud rate",
      [FT_DEVICE_NOT_OPENED_FOR_ERASE] = "Device not opened for erase",
      [FT_DEVICE_NOT_OPENED_FOR_WRITE] = "Device not opened for write",
      [FT_FAILED_TO_WRITE_DEVICE] = "Failed to write device",
      [FT_EEPROM_READ_FAILED] = "EEPROM read failed",
      [FT_EEPROM_WRITE_FAILED] = "EEPROM write failed",
      [FT_EEPROM_ERASE_FAILED] = "EEPROM erase failed",
      [FT_EEPROM_NOT_PRESENT] = "EEPROM not present",
      [FT_EEPROM_NOT_PROGRAMMED] = "EEPROM not programmed",
      [FT_INVALID_ARGS] = "Invalid argument",
      [FT_NOT_SUPPORTED] = "Not supported",
      [FT_OTHER_ERROR] = "Other error"
  };
  
  static const int num_ft_errors = sizeof(ft_errors) / sizeof(ft_errors[FT_OK]);
  static const char *ft_strerror(FT_STATUS ft_status)
  {
      if (ft_status &lt; 0        // Should be impossible because it is unsigned
      || ft_status &gt;= num_ft_errors
      || !ft_errors[ft_status])
      {
      return "Unknown error";
      }
      return ft_errors[ft_status];
  }
  
  static void ft_error_exit(const char *str, FT_STATUS ft_status)
  {
      if (str &amp;&amp; *str)
      fprintf(stderr, "%s: %sn", str, ft_strerror(ft_status));
      else
      fprintf(stderr, "%sn", ft_strerror(ft_status));
      exit(1);
  }
  
  static void pthread_error_exit(const char *str, int err)
  {
      if (str &amp;&amp; *str)
      fprintf(stderr, "%s: %sn", str, strerror(err));
      else
      fprintf(stderr, "%sn", strerror(err));
      exit(1);
  }
  
  static void std_error_exit(const char *str)
  {
      perror(str);
      exit(1);
  }
  
  // Reader thread function
  static void *reader_func(void *arg)
  {
    FT_STATUS ft_status;
    EVENT_HANDLE eh;
    DWORD chars_in_q;
    char buf[8192];
    int pterr;
  
  
  
    if ((pterr = pthread_mutex_init(&amp;eh.eMutex, NULL)))
      pthread_error_exit("pthread_mutex_init", pterr);
    if ((pterr = pthread_cond_init(&amp;eh.eCondVar, NULL)))
      pthread_error_exit("pthread_cond_init", pterr);
  
    if ((ft_status = FT_SetEventNotification(ft_handle, FT_EVENT_RXCHAR,
                         (PVOID)&amp;eh)) != FT_OK)
    ft_error_exit("FT_SetEventNotification", ft_status);
  
    for (;;)
    {
      printf("at for: chars_in_q: %d\n", chars_in_q);
  
      if ((pterr = pthread_mutex_lock(&amp;eh.eMutex))){
        pthread_error_exit("pthread_mutex_lock", pterr);
        printf("pthread_mutex_lock failed...\n");
      }
      printf("pthread_mutex_lock\n");
      if ((ft_status = FT_GetQueueStatus(ft_handle, &amp;chars_in_q)) != FT_OK)
        ft_error_exit("FT_GetQueueStatus", ft_status);
      printf("before if (chars_in_q == 0): chars_in_q: %d\n", chars_in_q);
  //    while (chars_in_q == 0)
  //    {
        printf("&lt;&lt;----------- SetEventNotification pthread_cond_wait ---------------&gt;&gt;\n");
        if ((pterr = pthread_cond_wait(&amp;eh.eCondVar, &amp;eh.eMutex)))
          pthread_error_exit("pthread_cond_wait", pterr);
        printf("pthread_cond_wait\n");
        if ((ft_status = FT_GetQueueStatus(ft_handle,
                           &amp;chars_in_q)) != FT_OK)
          ft_error_exit("FT_GetQueueStatus", ft_status);
        printf("before if (chars_in_q == 0): chars_in_q: %d\n", chars_in_q);
  //    }
      if ((pterr = pthread_mutex_unlock(&amp;eh.eMutex)))
        pthread_error_exit("pthread_mutex_unlock", pterr);
  
      printf("pthread_mutex_unlock\n");
  
      while (chars_in_q)
      {
        printf("at while (chars_in_q): chars_in_q: %d\n", chars_in_q);
  
        DWORD len_to_read, len_read;
        ssize_t len_written;
  
        len_to_read = (chars_in_q &gt; sizeof(buf)) ? sizeof(buf) : chars_in_q;
  
        if ((ft_status = FT_Read(ft_handle, (LPVOID)buf,
                     len_to_read, &amp;len_read)) != FT_OK)
          ft_error_exit("FT_Read", ft_status);
        if (!len_read)
        {
          fprintf(stderr, "FT_Read returned no data.n");
          exit(1);
        }
  
        len_written = printf("%s\n", buf);
        printf("len_to_read: %d\n", len_to_read);
        printf("len_read: %d\n", len_read);
  
        chars_in_q -= len_read;
      }
    }
  }
  
  int main(int argc, char *argv[])
  {
    FT_STATUS ft_status;
    DWORD devCount;
    DWORD devIndex = 0; // first device
    DWORD numDevices = 1;
    char serialNumber[64]; // more than enough room!
  
    const unsigned int baudrate = 8000000;
  
    FT_DEVICE_LIST_INFO_NODE * devInfo;
    devInfo = malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevices);
  
    ft_status = FT_CreateDeviceInfoList(&amp;devCount);
  
    if(  ft_status != FT_OK)
    {
      printf("No devices connected!\n");
      exit(-1);
    }
  
    printf("Devices found: %d\n", devCount);
  
    ft_status = FT_ListDevices((PVOID)devIndex, serialNumber, FT_LIST_BY_INDEX|FT_OPEN_BY_SERIAL_NUMBER);
    if (  ft_status == FT_OK)
    {
      // FT_ListDevices OK, serial number is in serialNumber
      printf("Device Serial Number: %s\n", serialNumber);
    }
    else
    {
      // FT_ListDevices failed
    }
  
    ft_status = FT_OpenEx(serialNumber, FT_OPEN_BY_SERIAL_NUMBER, &amp;ft_handle);
  
    printf("after calling FT_OpenEx\n");
  
    if (  ft_status == FT_OK)
    {
      // FT_OpenEx OK, ft_handle not null
      printf("FT_OpenEx succeeded\n");
    }
    else
    {
      printf("FT_OpenEx failed\n");
    }
  
      ft_status = FT_SetBaudRate(ft_handle, baudrate);
  
    if (  ft_status == FT_OK)
    {
      // FT_SetBaudRate OK
      printf("FT_SetBaudRate succeeded\n");
    }
    else
    {
      printf("FT_SetBaudRate failed\n");
    }
  
    ft_status = FT_SetFlowControl(ft_handle, FT_FLOW_RTS_CTS, 0, 0);
  
    if (  ft_status == FT_OK)
    {
      // FT_SetFlowControl OK
      printf("FT_SetFlowControl succeeded\n");
    }
    else
    {
      printf("FT_SetFlowControl failed\n");
    }
  
    // Flush the FTDI's buffers
    if ((ft_status = FT_Purge(ft_handle, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK)
    ft_error_exit("FT_Purge", ft_status);
  
    // Create reader and writer threads.
    int pterr;
    sigset_t sig_set;
    (void)sigfillset(&amp;sig_set);
    pthread_attr_t ptattr;
    if ((pterr = pthread_attr_init(&amp;ptattr)))
      pthread_error_exit("pthread_attr_init", pterr);
    if ((pterr = pthread_attr_setdetachstate(&amp;ptattr,
                         PTHREAD_CREATE_DETACHED)))
      pthread_error_exit("pthread_attr_setdetachstate", pterr);
    pthread_t reader_id, writer_id;
    if ((pterr = pthread_create(&amp;reader_id, &amp;ptattr, reader_func, NULL)))
    pthread_error_exit("pthread_create reader", pterr);
  
    // Now wait for a signal to terminate us
    int caught_sig;
    if (sigwait(&amp;sig_set, &amp;caught_sig))
    std_error_exit("sigwait");
  
    exit(0);
  }
  
  gcc -o SetEventNotification_separate_thread SetEventNotification_separate_thread.c -lpthread -lftd2xx -Wl,-rpath /usr/local/lib
  
  */
  
  #include &lt;stdlib.h&gt;
  #include &lt;pthread.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdint.h&gt;
  #include "../ftd2xx.h"
  
  static FT_HANDLE ft_handle;
  
  
  // Seems like this sort of stuff should have been provided by FTDI
  static const char *ft_errors[] =
  {
      [FT_OK] = "Success",
      [FT_INVALID_HANDLE] = "Invalid device handle",
      [FT_DEVICE_NOT_FOUND] = "Device not found",
      [FT_DEVICE_NOT_OPENED] = "Device not opened",
      [FT_IO_ERROR] = "Input/output error",
      [FT_INSUFFICIENT_RESOURCES] = "Insufficient resources",
      [FT_INVALID_PARAMETER] = "Invalid parameter",
      [FT_INVALID_BAUD_RATE] = "Invalid baud rate",
      [FT_DEVICE_NOT_OPENED_FOR_ERASE] = "Device not opened for erase",
      [FT_DEVICE_NOT_OPENED_FOR_WRITE] = "Device not opened for write",
      [FT_FAILED_TO_WRITE_DEVICE] = "Failed to write device",
      [FT_EEPROM_READ_FAILED] = "EEPROM read failed",
      [FT_EEPROM_WRITE_FAILED] = "EEPROM write failed",
      [FT_EEPROM_ERASE_FAILED] = "EEPROM erase failed",
      [FT_EEPROM_NOT_PRESENT] = "EEPROM not present",
      [FT_EEPROM_NOT_PROGRAMMED] = "EEPROM not programmed",
      [FT_INVALID_ARGS] = "Invalid argument",
      [FT_NOT_SUPPORTED] = "Not supported",
      [FT_OTHER_ERROR] = "Other error"
  };
  
  static const int num_ft_errors = sizeof(ft_errors) / sizeof(ft_errors[FT_OK]);
  static const char *ft_strerror(FT_STATUS ft_status)
  {
      if (ft_status &lt; 0        // Should be impossible because it is unsigned
      || ft_status &gt;= num_ft_errors
      || !ft_errors[ft_status])
      {
      return "Unknown error";
      }
      return ft_errors[ft_status];
  }
  
  static void ft_error_exit(const char *str, FT_STATUS ft_status)
  {
      if (str &amp;&amp; *str)
      fprintf(stderr, "%s: %sn", str, ft_strerror(ft_status));
      else
      fprintf(stderr, "%sn", ft_strerror(ft_status));
      exit(1);
  }
  
  static void pthread_error_exit(const char *str, int err)
  {
      if (str &amp;&amp; *str)
      fprintf(stderr, "%s: %sn", str, strerror(err));
      else
      fprintf(stderr, "%sn", strerror(err));
      exit(1);
  }
  
  static void std_error_exit(const char *str)
  {
      perror(str);
      exit(1);
  }
  
  // Reader thread function
  static void *reader_func(void *arg)
  {
    FT_STATUS ft_status;
    EVENT_HANDLE eh;
    DWORD chars_in_q;
    char buf[8192];
    int pterr;
  
  
  
    if ((pterr = pthread_mutex_init(&amp;eh.eMutex, NULL)))
      pthread_error_exit("pthread_mutex_init", pterr);
    if ((pterr = pthread_cond_init(&amp;eh.eCondVar, NULL)))
      pthread_error_exit("pthread_cond_init", pterr);
  
    if ((ft_status = FT_SetEventNotification(ft_handle, FT_EVENT_RXCHAR,
                         (PVOID)&amp;eh)) != FT_OK)
    ft_error_exit("FT_SetEventNotification", ft_status);
  
    for (;;)
    {
      printf("at for: chars_in_q: %d\n", chars_in_q);
  
      if ((pterr = pthread_mutex_lock(&amp;eh.eMutex))){
        pthread_error_exit("pthread_mutex_lock", pterr);
        printf("pthread_mutex_lock failed...\n");
      }
      printf("pthread_mutex_lock\n");
      if ((ft_status = FT_GetQueueStatus(ft_handle, &amp;chars_in_q)) != FT_OK)
        ft_error_exit("FT_GetQueueStatus", ft_status);
      printf("before if (chars_in_q == 0): chars_in_q: %d\n", chars_in_q);
  //    while (chars_in_q == 0)
  //    {
        printf("&lt;&lt;----------- SetEventNotification pthread_cond_wait ---------------&gt;&gt;\n");
        if ((pterr = pthread_cond_wait(&amp;eh.eCondVar, &amp;eh.eMutex)))
          pthread_error_exit("pthread_cond_wait", pterr);
        printf("pthread_cond_wait\n");
        if ((ft_status = FT_GetQueueStatus(ft_handle,
                           &amp;chars_in_q)) != FT_OK)
          ft_error_exit("FT_GetQueueStatus", ft_status);
        printf("before if (chars_in_q == 0): chars_in_q: %d\n", chars_in_q);
  //    }
      if ((pterr = pthread_mutex_unlock(&amp;eh.eMutex)))
        pthread_error_exit("pthread_mutex_unlock", pterr);
  
      printf("pthread_mutex_unlock\n");
  
      while (chars_in_q)
      {
        printf("at while (chars_in_q): chars_in_q: %d\n", chars_in_q);
  
        DWORD len_to_read, len_read;
        ssize_t len_written;
  
        len_to_read = (chars_in_q &gt; sizeof(buf)) ? sizeof(buf) : chars_in_q;
  
        if ((ft_status = FT_Read(ft_handle, (LPVOID)buf,
                     len_to_read, &amp;len_read)) != FT_OK)
          ft_error_exit("FT_Read", ft_status);
        if (!len_read)
        {
          fprintf(stderr, "FT_Read returned no data.n");
          exit(1);
        }
  
        len_written = printf("%s\n", buf);
        printf("len_to_read: %d\n", len_to_read);
        printf("len_read: %d\n", len_read);
  
        chars_in_q -= len_read;
      }
    }
  }
  
  int main(int argc, char *argv[])
  {
    FT_STATUS ft_status;
    DWORD devCount;
    DWORD devIndex = 0; // first device
    DWORD numDevices = 1;
    char serialNumber[64]; // more than enough room!
  
    const unsigned int baudrate = 8000000;
  
    FT_DEVICE_LIST_INFO_NODE * devInfo;
    devInfo = malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevices);
  
    ft_status = FT_CreateDeviceInfoList(&amp;devCount);
  
    if(  ft_status != FT_OK)
    {
      printf("No devices connected!\n");
      exit(-1);
    }
  
    printf("Devices found: %d\n", devCount);
  
    ft_status = FT_ListDevices((PVOID)devIndex, serialNumber, FT_LIST_BY_INDEX|FT_OPEN_BY_SERIAL_NUMBER);
    if (  ft_status == FT_OK)
    {
      // FT_ListDevices OK, serial number is in serialNumber
      printf("Device Serial Number: %s\n", serialNumber);
    }
    else
    {
      // FT_ListDevices failed
    }
  
    ft_status = FT_OpenEx(serialNumber, FT_OPEN_BY_SERIAL_NUMBER, &amp;ft_handle);
  
    printf("after calling FT_OpenEx\n");
  
    if (  ft_status == FT_OK)
    {
      // FT_OpenEx OK, ft_handle not null
      printf("FT_OpenEx succeeded\n");
    }
    else
    {
      printf("FT_OpenEx failed\n");
    }
  
      ft_status = FT_SetBaudRate(ft_handle, baudrate);
  
    if (  ft_status == FT_OK)
    {
      // FT_SetBaudRate OK
      printf("FT_SetBaudRate succeeded\n");
    }
    else
    {
      printf("FT_SetBaudRate failed\n");
    }
  
    ft_status = FT_SetFlowControl(ft_handle, FT_FLOW_RTS_CTS, 0, 0);
  
    if (  ft_status == FT_OK)
    {
      // FT_SetFlowControl OK
      printf("FT_SetFlowControl succeeded\n");
    }
    else
    {
      printf("FT_SetFlowControl failed\n");
    }
  
    // Flush the FTDI's buffers
    if ((ft_status = FT_Purge(ft_handle, FT_PURGE_RX | FT_PURGE_TX)) != FT_OK)
    ft_error_exit("FT_Purge", ft_status);
  
    // Create reader and writer threads.
    int pterr;
    sigset_t sig_set;
    (void)sigfillset(&amp;sig_set);
    pthread_attr_t ptattr;
    if ((pterr = pthread_attr_init(&amp;ptattr)))
      pthread_error_exit("pthread_attr_init", pterr);
    if ((pterr = pthread_attr_setdetachstate(&amp;ptattr,
                         PTHREAD_CREATE_DETACHED)))
      pthread_error_exit("pthread_attr_setdetachstate", pterr);
    pthread_t reader_id, writer_id;
    if ((pterr = pthread_create(&amp;reader_id, &amp;ptattr, reader_func, NULL)))
    pthread_error_exit("pthread_create reader", pterr);
  
    // Now wait for a signal to terminate us
    int caught_sig;
    if (sigwait(&amp;sig_set, &amp;caught_sig))
    std_error_exit("sigwait");
  
    exit(0);
  }
  </code></pre>
  
  <p>It always gets stuck on the pthread_cond_wait. Any thoughts would be appreciated.</p>