r3231 - in trunk/libmnetutil: include/libmnetutil source

erik at minisip.org erik at minisip.org
Wed Mar 7 20:53:10 CET 2007


Author: erik
Date: 2007-03-07 20:53:09 +0100 (Wed, 07 Mar 2007)
New Revision: 3231

Modified:
   trunk/libmnetutil/include/libmnetutil/SocketServer.h
   trunk/libmnetutil/source/SocketServer.cxx
   trunk/libmnetutil/source/init.cxx
Log:

 * libmsip: Fix race condition in SocketServer

   When SocketServer::start is called it creates
   a thread that executes the "run" method. This
   method initializes internal data that is
   used in the signal method. If the stop method
   is called before the "run" has initialized the
   internal data, the thread will not stop running
   and "stop" will block indefinetly.

   Example code that often hangs:
     MRef<SipStack*> s = new SipStack( config );
     s->startTcpServer();
     s->stopRunning(); //This can block indefinetly - race

   This fix initializes the internal data in the start method.
   If the start method is not called and you instead call
   the run method directly, then the run method will initialize
   the data.


 * Minor change: I think we should use the LIBMNETUTIL_API not
   only in the header file. I don't remember if it is required
   in the .cxx file as well by the Microsoft compiler, but we
   have done it in the rest of the code.





Modified: trunk/libmnetutil/include/libmnetutil/SocketServer.h
===================================================================
--- trunk/libmnetutil/include/libmnetutil/SocketServer.h	2007-03-07 09:55:29 UTC (rev 3230)
+++ trunk/libmnetutil/include/libmnetutil/SocketServer.h	2007-03-07 19:53:09 UTC (rev 3231)
@@ -63,11 +63,16 @@
 		int buildFdSet( fd_set *set, int pipeFd );
 
 	private:
+		void createSignalPipe();
 		typedef std::map< MRef<Socket*>, MRef<InputReadyHandler*> > Sockets;
 		Mutex csMutex;
 		MRef<Thread *> thread;
 		Sockets sockets;
-		int fdSignal;
+
+		int fdSignal;		///Socket pair used to wake thread running run()
+		int fdSignalInternal;	///from its select. This is typically used to
+					///to tell the thread to stop.
+
 		bool doStop;
 };
 #endif

Modified: trunk/libmnetutil/source/SocketServer.cxx
===================================================================
--- trunk/libmnetutil/source/SocketServer.cxx	2007-03-07 09:55:29 UTC (rev 3230)
+++ trunk/libmnetutil/source/SocketServer.cxx	2007-03-07 19:53:09 UTC (rev 3231)
@@ -84,11 +84,34 @@
 	stop();
 }
 
+void SocketServer::createSignalPipe(){
+	int pipeFds[2] = {-1,-1};
+
+	if( fdSignal >= 0 ){
+		close( fdSignal );
+		fdSignal = -1;
+	}
+
+#ifdef WIN32
+	// Use TCP sockets since Windows pipes don't support select
+	if( createTcpPipe( pipeFds )) {
+#else
+	if( ::pipe( pipeFds ) ){
+#endif
+		throw Exception( "Can't create pipe" );
+	}
+
+	fdSignal = pipeFds[1];
+	fdSignalInternal = pipeFds[0];
+}
+
 void SocketServer::start()
 {
 	CriticalSection cs( csMutex );
 	if( !thread.isNull() )
 		return;
+	if (fdSignal < 0)
+		createSignalPipe();
 
 	thread = new Thread( this );
 }
@@ -154,6 +177,7 @@
 
 void SocketServer::signal()
 {
+
 	char c = 0;
 
 	if( fdSignal < 0 )
@@ -255,32 +279,14 @@
 	struct timeval timeout;
 	fd_set tmpl;
 	fd_set set;
-	int pipeFds[2] = {-1,-1};
 	int maxFd = -1;
 	Sockets::const_iterator i;
 
-	csMutex.lock();
+	if (fdSignal < 0)
+		createSignalPipe();
 
-	if( fdSignal >= 0 ){
-		close( fdSignal );
-		fdSignal = -1;
-	}
-
-#ifdef WIN32
-	// Use TCP sockets since Windows pipes don't support select
-	if( createTcpPipe( pipeFds )) {
-#else
-	if( ::pipe( pipeFds ) ){
-#endif
-		throw Exception( "Can't create pipe" );
-	}
-
-	fdSignal = pipeFds[1];
-
-	csMutex.unlock();
-
 	while (!doStop){
-		maxFd = buildFdSet( &tmpl, pipeFds[0] );
+		maxFd = buildFdSet( &tmpl, fdSignalInternal );
 
 		int avail;
 		do{
@@ -297,13 +303,13 @@
 // 			cerr<< "SipSocketServer::run(): Timeout"<< endl;
 		}
 
-		if( FD_ISSET( pipeFds[0], &set ) ){
+		if( FD_ISSET( fdSignalInternal, &set ) ){
 			char buf[255];
 
 #ifdef WIN32
-			if( recv( pipeFds[0], buf, sizeof(buf), 0 ) < 0){
+			if( recv( fdSignalInternal, buf, sizeof(buf), 0 ) < 0){
 #else
-			if( read( pipeFds[0], buf, sizeof(buf) ) < 0){
+			if( read( fdSignalInternal, buf, sizeof(buf) ) < 0){
 #endif
 				cerr << "Read failed" << endl;
 				throw NetworkException( errno );
@@ -325,9 +331,9 @@
 
 // 	csMutex.lock();
 
+	closesocket( fdSignalInternal );
+	closesocket( fdSignal );
 	fdSignal = -1;
-	closesocket( pipeFds[0] );
-	closesocket( pipeFds[1] );
 	doStop = false;
 
 // 	csMutex.unlock();

Modified: trunk/libmnetutil/source/init.cxx
===================================================================
--- trunk/libmnetutil/source/init.cxx	2007-03-07 09:55:29 UTC (rev 3230)
+++ trunk/libmnetutil/source/init.cxx	2007-03-07 19:53:09 UTC (rev 3231)
@@ -29,7 +29,7 @@
 
 static unsigned int g_initialized;
 
-void libmnetutilInit()
+LIBMNETUTIL_API void libmnetutilInit()
 {
 	if( g_initialized++ > 0 )
 		return;
@@ -40,8 +40,10 @@
 	}
 }
 
-void libmnetutilUninit()
+LIBMNETUTIL_API void libmnetutilUninit()
 {
 	if( --g_initialized )
 		return;
 }
+
+



More information about the Minisip-devel mailing list