Comm: Use the old style async i/o instead of select

Use the old style async i/o thread to read from the qmi file
descriptors because the implementation using select appears to be
buggy.  The suspend resume test frequently gets a segmentation
violation within the gobi sdk, and even when code is modified to
mitigate that problem, we have had several kernel crashes.  Moving
back to the async I/O thread until bugs with select can be addressed.

BUG=chromium-os:24474
TEST=network_3g, especially SuspendResume

Change-Id: I3abc8518c2554f08861662b27e0411d70a372320
diff --git a/Core/Comm.cpp b/Core/Comm.cpp
index db06db9..2c4fdb0 100644
--- a/Core/Comm.cpp
+++ b/Core/Comm.cpp
@@ -47,10 +47,6 @@
 //---------------------------------------------------------------------------
 // Definitions
 //---------------------------------------------------------------------------
-// Thread commands
-#define START_READ_CMD  0
-#define STOP_READ_CMD   1
-#define EXIT_CMD        2
 
 /*=========================================================================*/
 // Free Methods
@@ -58,102 +54,48 @@
 
 /*===========================================================================
 METHOD:
-   RxThread (Free Method)
+   RxCompletionRoutine (Free Method)
 
 DESCRIPTION:
-   Thread for simulating asynchronous reads
+   Completion routine for receive operation, exercises current receive 
+   callback object
 
 PARAMETERS:
-   pData      [ I ]   Asynchronous read object
+   returnSignal [ I/O ]   Asynchronus signal event 
+                          (contains pointer to cCOMM object)
 
 RETURN VALUE:
-   void * - thread exit value (always 0)
+   None
 ===========================================================================*/
-void * RxThread( void * pData )
+VOID RxCompletionRoutine( sigval returnSignal )
 {
-   cComm * pComm = (cComm*)pData;
+   cComm * pComm = (cComm *)returnSignal.sival_ptr;
+      
    if (pComm == NULL || pComm->IsValid() == false)
    {
-      return 0;
+      return;
    }
 
-   fd_set inputSet, outputSet;
-   FD_ZERO( &inputSet );
-   FD_SET( pComm->mCommandPipe[READING], &inputSet );
-   int largestFD = pComm->mCommandPipe[READING];
-
-   int status = 0;
-   while (true)
+   cIOCallback * pCallback = pComm->mpRxCallback;
+   if (pCallback == 0)
    {
-      // No FD_COPY() available
-      memcpy( &outputSet, &inputSet, sizeof( fd_set ) );
-
-      status = select( largestFD + 1, &outputSet, NULL, NULL, NULL );
-      if (status <= 0)
-      {
-         TRACE( "error %d in select, errno %d\n", status, errno );
-         break;
-      }
-
-      if (FD_ISSET( pComm->mCommandPipe[READING], &outputSet ) == true)
-      {
-         // Read from the pipe
-         BYTE cmd;
-         status = read( pComm->mCommandPipe[READING], &cmd, 1 );
-         if (status != 1)
-         {
-            TRACE( "cmd error %d\n", status );
-            break;
-         }
-
-         if (cmd == START_READ_CMD)
-         {
-            FD_SET( pComm->mPort, &inputSet );
-            largestFD = std::max( pComm->mPort, 
-                                  pComm->mCommandPipe[READING] );
-         }
-         else if (cmd == STOP_READ_CMD)
-         {
-            FD_CLR( pComm->mPort, &inputSet );
-            largestFD = pComm->mCommandPipe[READING];
-         }
-         else
-         {
-            // EXIT_CMD or anything else
-            break;
-         }
-      }
-      else if (FD_ISSET( pComm->mPort, &outputSet ) == true)
-      {
-         // Stop watching for read data
-         FD_CLR( pComm->mPort, &inputSet );
-         largestFD = pComm->mCommandPipe[READING];
-
-         // Perform a read
-         status = read( pComm->mPort,
-                        pComm->mpBuffer,
-                        pComm->mBuffSz );
-
-         cIOCallback * pCallback = pComm->mpRxCallback;
-         pComm->mpRxCallback = 0;
-
-         if (pCallback == (cIOCallback *)1)
-         {
-            // We wanted to read, but not to be notified
-         }   
-         else if (status >= 0)
-         {
-            pCallback->IOComplete( 0, status );
-         }
-         else
-         {
-            pCallback->IOComplete( status, 0 );
-         }
-      }
+      // aio_cancel is broken if file pointer is bad
+      // Notify cComm::CancelIO() manually
+      TRACE( "%s manual notification %d\n", __func__, pComm->mPort );
+      pComm->mReadCanceled.Set( 1 );
+      
+      return;
    }
 
-   return 0;
-};
+   pComm->mpRxCallback = 0;
+   if (pCallback != (cIOCallback *)1)
+   {
+      int nEC = aio_error( &pComm->mReadIO );
+      int nBytesTransfered = aio_return( &pComm->mReadIO );
+
+      pCallback->IOComplete( nEC, nBytesTransfered );
+   }
+}
 
 /*=========================================================================*/
 // cComm Methods
@@ -174,12 +116,11 @@
       mPort( INVALID_HANDLE_VALUE ),
       mpRxCallback( 0 ),
       mbCancelWrite( false ),
-      mpBuffer( 0 ),
-      mBuffSz( 0 ),
-      mRxThreadID( 0 )
+      mReadCanceled()
 {
-   mCommandPipe[READING] = INVALID_HANDLE_VALUE;
-   mCommandPipe[WRITING] = INVALID_HANDLE_VALUE;
+   memset( &mReadIO, 0, sizeof( aiocb) );
+
+   mReadIO.aio_sigevent.sigev_value.sival_ptr = this;
 }
 
 /*===========================================================================
@@ -197,8 +138,7 @@
    // Disconnect from current port
    Disconnect();
 
-   mCommandPipe[READING] = INVALID_HANDLE_VALUE;
-   mCommandPipe[WRITING] = INVALID_HANDLE_VALUE;
+   mReadIO.aio_sigevent.sigev_value.sival_ptr = NULL;
 }
 
 /*===========================================================================
@@ -213,8 +153,7 @@
 ===========================================================================*/
 bool cComm::IsValid()
 {
-   // Nothing to do, dependant on extended class functionality
-   return true;
+   return (mReadIO.aio_sigevent.sigev_value.sival_ptr == this);
 }
 
 /*===========================================================================
@@ -242,35 +181,18 @@
       Disconnect();
    }
 
-   // Initialize command pipe for read thread
-   int nRet = pipe( mCommandPipe );
-   if (nRet != 0)
-   {
-      TRACE( "cComm:Connect() pipe creation failed %d\n", nRet );
-      return false;
-   }
-
-   // Start the read thread
-   nRet = pthread_create( &mRxThreadID,
-                          0,
-                          RxThread,
-                          this );
-   if (nRet != 0)
-   {
-      TRACE( "cComm::Connect() pthread_create = %d\n",  nRet );
-
-      Disconnect();
-      return false;
-   }
-
    // Opening the com port
    mPort = open( pPort, O_RDWR );
    if (mPort == INVALID_HANDLE_VALUE) 
    {
-      Disconnect();
       return false;
    }
 
+   // Clear any contents
+   tcdrain( mPort );
+
+   mReadCanceled.Clear();
+ 
    // Save port name
    mPortName = pPort;
 
@@ -320,35 +242,14 @@
    // Assume success
    bool bRC = true;
 
-   if (mCommandPipe[WRITING] != INVALID_HANDLE_VALUE)
-   {
-      if (mRxThreadID != 0)
-      {
-         // Notify the thread to exit
-         BYTE byte = EXIT_CMD;
-         write( mCommandPipe[WRITING], &byte, 1 );
-
-         // And wait for it
-         TRACE( "cComm::Disconnnect() joining thread\n" );
-         int nRC = pthread_join( mRxThreadID, 0 );
-         if (nRC != 0)
-         {
-            TRACE( "failed to join thread %d\n", nRC );
-            bRC = false;
-         }
-
-         mRxThreadID = 0;
-      }
-
-      close( mCommandPipe[WRITING] );
-      close( mCommandPipe[READING] );
-      mCommandPipe[READING] = INVALID_HANDLE_VALUE;
-      mCommandPipe[WRITING] = INVALID_HANDLE_VALUE;
-   }
-
    if (mPort != INVALID_HANDLE_VALUE)
    {
-      close( mPort );
+      int nClose = close( mPort );
+      if (nClose == -1)
+      {
+         bRC = false;
+      }
+
       mPort = INVALID_HANDLE_VALUE;
    }
 
@@ -455,28 +356,31 @@
 ===========================================================================*/
 bool cComm::CancelRx()
 {
-   if (mPort == INVALID_HANDLE_VALUE
-   ||  mCommandPipe[WRITING] == INVALID_HANDLE_VALUE
-   ||  mpRxCallback == 0
-   ||  mRxThreadID == 0)
+   if (mPort == INVALID_HANDLE_VALUE || mpRxCallback == 0)
    {
-      TRACE( "cannot cancel, thread not active\n" );
       return false;
    }
 
-   // Notify the thread to stop reading
-   BYTE byte = STOP_READ_CMD;
-   int nRC = write( mCommandPipe[WRITING], &byte, 1 );
-   if (nRC != 1)
-   {
-      TRACE( "error %d canceling read\n", nRC );
-      return false;
-   }
-   
-   // Remove the old callback
+   int nReadRC = aio_cancel( mPort, &mReadIO );
    mpRxCallback = 0;
 
-   return true;
+   if (nReadRC == -1 && (errno == EBADF || errno == ENXIO))
+   {
+      // aio_cancel is broken if file pointer is bad
+      // wait for completion
+      TRACE( "cComm::CancelRx manual wait %d\n", mPort );
+
+      DWORD nTemp; 
+      if (mReadCanceled.Wait( INFINITE, nTemp ) == 0)
+      {
+         return true;
+      }
+
+      // Timeout or some other failure
+      return false;
+   }
+
+   return (nReadRC == AIO_CANCELED);
 }
 
 /*===========================================================================
@@ -526,7 +430,7 @@
    {
       return false;
    }
-
+      
    if (pCallback == 0)
    {
       // Not interested in being notified, but we still need a value
@@ -539,15 +443,19 @@
       mpRxCallback = pCallback;
    }
 
-   mpBuffer = pBuf;
-   mBuffSz = bufSz;
+   mReadIO.aio_fildes = mPort;
+   mReadIO.aio_buf = pBuf;
+   mReadIO.aio_nbytes = bufSz;
+   mReadIO.aio_sigevent.sigev_notify = SIGEV_THREAD;
+   mReadIO.aio_sigevent.sigev_notify_function = RxCompletionRoutine;
+   mReadIO.aio_sigevent.sigev_value.sival_ptr = this;
+   mReadIO.aio_offset = 0;
 
-   // Notify the thread to stop reading
-   BYTE byte = START_READ_CMD;
-   int nRC = write( mCommandPipe[WRITING], &byte, 1 );
-   if (nRC != 1)
+   int nRet = aio_read( &mReadIO );
+   if (nRet != 0)
    {
-      TRACE( "error %d starting read\n", nRC );
+      TRACE( "cComm::RxData() = %d, %s\n", nRet, strerror( errno ) );
+      errno = 0;
       return false;
    }
 
diff --git a/Core/Comm.h b/Core/Comm.h
index 3f56413..86bd01f 100644
--- a/Core/Comm.h
+++ b/Core/Comm.h
@@ -41,6 +41,7 @@
 // Include Files
 //---------------------------------------------------------------------------
 #include "Event.h"
+#include <aio.h>
 
 //---------------------------------------------------------------------------
 // Pragmas
@@ -136,24 +137,18 @@
       /* Handle to COM port */
       int mPort;
 
+      // Read IO settings
+      aiocb mReadIO;
+
       /* Read callbacks */
       cIOCallback * mpRxCallback;
       
       // Cancel the write request?
       bool mbCancelWrite;
 
-      /* Buffer */
-      BYTE * mpBuffer;
+      // Read callback cancelation notification
+      cEvent mReadCanceled;
 
-      /* Buffer size */
-      ULONG mBuffSz;
-
-      /* Pipe for comunication with thread */
-      int mCommandPipe[2];
-
-      /* Thread ID of Rx Thread. */
-      pthread_t mRxThreadID;
-
-      // Rx thread is allowed complete access
-      friend void * RxThread( void * pData );
+      // Rx completion routine is allowed complete access
+      friend VOID RxCompletionRoutine( sigval returnSignal );
 };