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 );
};