From 5f13377b83bc5bfafaf6b150a4b507f190cee585 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Sat, 17 Mar 2012 15:02:32 -0400 Subject: multi-arfcn, trx: handle thread exiting on shutdown Previous approach was to allow stack unwinding to take care shutdown and thread ending, which was unpredictable and occasionally segfault. Attempt to shutdown more gracefully. There are thread cancellation points in the transceiver code using pthread_testcancel(), but the thread abstraction library does not allow direct access to the pthread variables. This prevents thread shutdown through pthread_cancel(). To get around this, use boolean status values in the receive socket service loops and main drive loop. The socket read calls will block indefinitly, so shutdown may cause the socket implementation to throw a SocketError exception. Use of timeout values with reads does not seem to work correctly or reliably, so catch the exception and ignore if it occurs on shutdown. The following error may appear as the socket is shutdown while the Transceiver is blocking on read(). DatagramSocket::read() failed: Bad file descriptor So be it; the API doesn't allow us to do any more. Signed-off-by: Thomas Tsou --- Transceiver52M/DriveLoop.cpp | 25 ++++++++++++-------- Transceiver52M/DriveLoop.h | 5 ++++ Transceiver52M/Transceiver.cpp | 49 ++++++++++++++++++++++++++++++--------- Transceiver52M/Transceiver.h | 10 ++++++++ Transceiver52M/multiTRX.cpp | 10 +++++++- Transceiver52M/radioInterface.cpp | 11 ++++++++- Transceiver52M/radioInterface.h | 7 ++++++ Transceiver52M/runTransceiver.cpp | 1 + 8 files changed, 95 insertions(+), 23 deletions(-) diff --git a/Transceiver52M/DriveLoop.cpp b/Transceiver52M/DriveLoop.cpp index 7e250f8..cbd2993 100644 --- a/Transceiver52M/DriveLoop.cpp +++ b/Transceiver52M/DriveLoop.cpp @@ -69,8 +69,12 @@ DriveLoop::DriveLoop(int wSamplesPerSymbol, DriveLoop::~DriveLoop() { - if (mRadioDriveLoopThread) - delete mRadioDriveLoopThread; + if (mOn) { + mOn = false; + + if (mRadioDriveLoopThread) + delete mRadioDriveLoopThread; + } delete gsmPulse; sigProcLibDestroy(); @@ -78,6 +82,9 @@ DriveLoop::~DriveLoop() void DriveLoop::start() { + if (mOn) + return; + mOn = true; mRadioDriveLoopThread = new Thread(32768); mRadioDriveLoopThread->start((void * (*)(void*))RadioDriveLoopAdapter, (void*) this); @@ -236,9 +243,6 @@ void DriveLoop::driveTransmitFIFO() { int i; - if (!mOn) - return; - RadioClock *radioClock = (mRadioInterface->getClock()); while (radioClock->get() + mTransmitLatency > mTransmitDeadlineClock) { pushRadioVector(mTransmitDeadlineClock); @@ -250,14 +254,15 @@ void DriveLoop::driveTransmitFIFO() //else radioClock->wait(); } -void *RadioDriveLoopAdapter(DriveLoop *transceiver) +void *RadioDriveLoopAdapter(DriveLoop *drive) { - transceiver->setPriority(); + drive->setPriority(); - while (1) { - transceiver->driveReceiveFIFO(); - transceiver->driveTransmitFIFO(); + while (drive->on()) { + drive->driveReceiveFIFO(); + drive->driveTransmitFIFO(); pthread_testcancel(); } + return NULL; } diff --git a/Transceiver52M/DriveLoop.h b/Transceiver52M/DriveLoop.h index 8c58296..df54ef7 100644 --- a/Transceiver52M/DriveLoop.h +++ b/Transceiver52M/DriveLoop.h @@ -172,6 +172,11 @@ protected: friend void *RadioDriveLoopAdapter(DriveLoop *); + void reset(); + + /** return drive loop status */ + bool on() { return mOn; } + /** set priority on current thread */ void setPriority() { mRadioInterface->setPriority(); } diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp index 7b60cd2..ff8c12e 100644 --- a/Transceiver52M/Transceiver.cpp +++ b/Transceiver52M/Transceiver.cpp @@ -87,6 +87,7 @@ Transceiver::Transceiver(int wBasePort, } mOn = false; + mRunning = false; mTxFreq = 0.0; mRxFreq = 0.0; mPower = -10; @@ -307,10 +308,17 @@ void Transceiver::pullFIFO() void Transceiver::start() { + mRunning = true; mControlServiceLoopThread = new Thread(32768); mControlServiceLoopThread->start((void * (*)(void*))ControlServiceLoopAdapter,(void*) this); } +void Transceiver::shutdown() +{ + mOn = false; + mRunning = false; +} + void Transceiver::reset() { mTransmitPriorityQueue->clear(); @@ -326,10 +334,19 @@ void Transceiver::driveControl() char buffer[MAX_PACKET_LENGTH]; int msgLen = -1; buffer[0] = '\0'; - - msgLen = mControlSocket.read(buffer); - if (msgLen < 1) { + try { + msgLen = mControlSocket.read(buffer); + if (msgLen < 1) { + return; + } + } catch (...) { + /* Ignore the read exception on shutdown */ + if (!mRunning) { + return; + } + + LOG(ALERT) << "Caught UHD socket exception"; return; } @@ -501,14 +518,24 @@ void Transceiver::driveControl() bool Transceiver::driveTransmitPriorityQueue() { - char buffer[gSlotLen+50]; - // check data socket - size_t msgLen = mDataSocket.read(buffer); + if (!mOn) + return true; + + try { + size_t msgLen = mDataSocket.read(buffer); + if (msgLen!=gSlotLen+1+4+1) { + LOG(ERR) << "badly formatted packet on GSM->TRX interface"; + return false; + } + } catch (...) { + if (!mOn) { + /* Shutdown condition. End the thread. */ + return true; + } - if (msgLen!=gSlotLen+1+4+1) { - LOG(ERR) << "badly formatted packet on GSM->TRX interface"; + LOG(ALERT) << "Caught UHD socket exception"; return false; } @@ -579,7 +606,7 @@ void Transceiver::writeClockInterface() void *FIFOServiceLoopAdapter(Transceiver *transceiver) { - while (1) { + while (transceiver->on()) { transceiver->pullFIFO(); pthread_testcancel(); } @@ -588,7 +615,7 @@ void *FIFOServiceLoopAdapter(Transceiver *transceiver) void *ControlServiceLoopAdapter(Transceiver *transceiver) { - while (1) { + while (transceiver->running()) { transceiver->driveControl(); pthread_testcancel(); } @@ -597,7 +624,7 @@ void *ControlServiceLoopAdapter(Transceiver *transceiver) void *TransmitPriorityQueueServiceLoopAdapter(Transceiver *transceiver) { - while (1) { + while (transceiver->on()) { bool stale = false; // Flush the UDP packets until a successful transfer. while (!transceiver->driveTransmitPriorityQueue()) { diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h index fed2df9..1b4e181 100644 --- a/Transceiver52M/Transceiver.h +++ b/Transceiver52M/Transceiver.h @@ -95,6 +95,7 @@ private: int mSamplesPerSymbol; ///< number of samples per GSM symbol bool mOn; ///< flag to indicate that transceiver is powered on + bool mRunning; ///< flag to indicate control loop is running double mTxFreq; ///< the transmit frequency double mRxFreq; ///< the receive frequency int mPower; ///< the transmit power in dB @@ -134,6 +135,9 @@ public: /** start the Transceiver */ void start(); + /** shutdown (teardown threads) the Transceiver */ + void shutdown(); + /** attach the radioInterface receive FIFO */ void receiveFIFO(VectorFIFO *wFIFO) { mReceiveFIFO = wFIFO;} @@ -165,6 +169,12 @@ protected: void reset(); + /** return transceiver on/off status */ + bool on() { return mOn; } + + /** return control loop operational status */ + bool running() { return mRunning; } + /** set priority on current thread */ void setPriority() { mRadioInterface->setPriority(); } diff --git a/Transceiver52M/multiTRX.cpp b/Transceiver52M/multiTRX.cpp index a68f234..8ce9ae0 100644 --- a/Transceiver52M/multiTRX.cpp +++ b/Transceiver52M/multiTRX.cpp @@ -105,7 +105,15 @@ int main(int argc, char *argv[]) sleep(1); } - LOG(NOTICE) << "Shutting down transceiver..."; + LOG(NOTICE) << "Shutting down transceivers..."; + trx0->shutdown(); + trx1->shutdown(); + trx2->shutdown(); + + /* + * Allow time for threads to end before we start freeing objects + */ + sleep(2); delete trx0; delete trx1; diff --git a/Transceiver52M/radioInterface.cpp b/Transceiver52M/radioInterface.cpp index 316779f..98af480 100644 --- a/Transceiver52M/radioInterface.cpp +++ b/Transceiver52M/radioInterface.cpp @@ -188,10 +188,19 @@ bool RadioInterface::start() return true; } +bool RadioInterface::stop() +{ + if (!mOn) + return false; + + mOn = false; + mRadio->stop(); +} + #ifdef USRP1 void *AlignRadioServiceLoopAdapter(RadioInterface *radioInterface) { - while (1) { + while (radioInterface->on()) { radioInterface->alignRadio(); pthread_testcancel(); } diff --git a/Transceiver52M/radioInterface.h b/Transceiver52M/radioInterface.h index 99c66b1..bc32763 100644 --- a/Transceiver52M/radioInterface.h +++ b/Transceiver52M/radioInterface.h @@ -94,6 +94,7 @@ public: /** start the interface */ bool start(); + bool stop(); bool started() { return mOn; }; @@ -160,6 +161,12 @@ protected: /** drive synchronization of Tx/Rx of USRP */ void alignRadio(); + /** reset the interface */ + void reset(); + + /** interface status */ + bool on() { return mOn; } + friend void *AlignRadioServiceLoopAdapter(RadioInterface*); #endif }; diff --git a/Transceiver52M/runTransceiver.cpp b/Transceiver52M/runTransceiver.cpp index c750f96..441edf9 100644 --- a/Transceiver52M/runTransceiver.cpp +++ b/Transceiver52M/runTransceiver.cpp @@ -160,6 +160,7 @@ int main(int argc, char *argv[]) while(!gbShutdown) { sleep(1); }//i++; if (i==60) break;} cout << "Shutting down transceiver..." << endl; + trx->shutdown(); delete trx; delete drive; -- cgit v1.2.3