I have a TcpListener and a thread that blocks in AcceptSocket(),
corresponding to Socket.Accept().

Another thread now calls Stop() on the listener, which causes the
socket to be disposed. I believe the intention is that the thread
blocking on Accept() should now get a SocketException with errorcode =
interrupted. This is based on reading the code, and this does happen
sometimes. However, sometimes, quite often, I get this
ThreadAbortException instead:

System.Threading.ThreadAbortException: Thread was being aborted
  at System.Net.Sockets.SocketException..ctor (Int32 error) [0x00007]
in 
/home/oskar/mono24/mono-2.4.2.3/mono-2.4.2.3/mcs/class/System/System.Net.Sockets/SocketException.cs:54
  at System.Net.Sockets.Socket.Accept () [0x000b8] in
/home/oskar/mono24/mono-2.4.2.3/mono-2.4.2.3/mcs/class/System/System.Net.Sockets/Socket.cs:1434
  at System.Net.Sockets.TcpListener.AcceptSocket () [0x00016] in
/home/oskar/mono24/mono-2.4.2.3/mono-2.4.2.3/mcs/class/System/System.Net.Sockets/TcpListener.cs:193
  at XXXX.TriggerServer.Run_impl () [0x0003b] in MYCODE

BTW, Socket.cs:1434 above seems bogus... There is no call to
SocketException..ctor on that line. Closest one, and only one in
Accept(), is on line 1426.

Looking at the code in Socket.Accept() it is built to handle a
ThreadAbortException by preventing the abort and generating a
SocketException instead. But this does not seem to work reliably!

Is it possible there is a race condition here? That is: Can
Close_internal() in fact cause Accept_internal() to return (with an
error code) before Dispose() calls Abort() on blocking_thread?


This is an excerpt from public Socket Accept():

                        blocking_thread = Thread.CurrentThread;
                        try {
                                sock = Accept_internal(socket, out error, 
blocking);
                        } catch (ThreadAbortException) {
                                if (disposed) {
#if !NET_2_1
                                        Thread.ResetAbort ();
#endif
                                        error = (int) SocketError.Interrupted;
                                }
                        } finally {
                                blocking_thread = null;
                        }

                        if (error != 0)
                                throw new SocketException (error);


And this is the Dispose():
                protected virtual void Dispose (bool explicitDisposing)
                {
                        if (disposed)
                                return;

                        disposed = true;
                        connected = false;
                        if ((int) socket != -1) {
                                int error;
                                closed = true;
                                IntPtr x = socket;
                                socket = (IntPtr) (-1);
                                Close_internal (x, out error);
                                if (blocking_thread != null) {
                                        blocking_thread.Abort ();
                                        blocking_thread = null;
                                }

                                if (error != 0)
                                        throw new SocketException (error);
                        }
                }



/Oskar
_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to