[Mono-bugs] [Bug 74423][Maj] New - Deadlock with BeginReceive*/AsyncWaitHandle

bugzilla-daemon@bugzilla.ximian.com bugzilla-daemon@bugzilla.ximian.com
Tue, 5 Apr 2005 17:01:07 -0400 (EDT)

Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.

Changed by jlarimer@gmail.com.


--- shadow/74423	2005-04-05 17:01:07.000000000 -0400
+++ shadow/74423.tmp.11566	2005-04-05 17:01:07.000000000 -0400
@@ -0,0 +1,88 @@
+Bug#: 74423
+Product: Mono: Class Libraries
+Version: 1.1
+OS: Red Hat 9.0
+OS Details: Fedora Core 2
+Status: NEW   
+Priority: Major
+Component: System
+AssignedTo: mono-bugs@ximian.com                            
+ReportedBy: jlarimer@gmail.com               
+QAContact: mono-bugs@ximian.com
+TargetMilestone: ---
+Summary: Deadlock with BeginReceive*/AsyncWaitHandle
+There is a deadlock that occurs in
+/mcs/class/System/System.Net.Sockets/Socket.cs when using the IAsyncResult
+returned by a call such as Socket.BeginReceiveFrom().
+The problem is that Worker.ReceiveFrom() locks the IAsyncResult object for
+the socket while receving. If you then attempt to use the AsyncWaitHandle
+after calling BeginReceiveFrom(), the code in Socket.cs contains a
+lock(this) block of code that attempts to get a lock on the IAsyncResult
+object that has already been locked by the Worker. This will result in a
+deadlock on a blocking call that may not ever return. 
+To reproduce:
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+class SockTest {
+        public static void Main(string[] args) {
+                byte[] replyBuffer = new byte[1024];
+                using(Socket socket = new
+Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) {
+                        socket.Bind(new IPEndPoint(IPAddress.Any, 0));
+                        EndPoint endPoint = new IPEndPoint(IPAddress.Any, 999);
+                        IAsyncResult ar =
+socket.BeginReceiveFrom(replyBuffer, 0, replyBuffer.GetLength(0),
+SocketFlags.None, ref endPoint, null, null);
+                        Console.WriteLine("Getting wait handle...");
+                        WaitHandle wh = ar.AsyncWaitHandle;
+                        Console.WriteLine("Got wait handle, waiting...");
+                        wh.WaitOne(5000, false);
+                        Console.WriteLine("Done waiting, IsCompeted is
+{0}", ar.IsCompleted);
+                }
+        }
+Expected results:
+[jlarimer@debacle socktest]$ mono ./socktest.exe
+Getting wait handle...
+Got wait handle, waiting...
+Done waiting, IsCompeted is False
+Real result:
+[jlarimer@debacle socktest]$ mono ./socktest.exe
+Getting wait handle...
+(Note that the WaitHandle is never obtailed, the AsyncWaitHandle propery
+can't enter the lock(this) block)
+I fixed this by using a non-this object to lock on, a waithandle_lock that
+is created by the constructor. Another way to fix would be to create the
+WaitHandle itself in the constructor, to avoid lazy creation, although the
+MSDN docs say lazy creation is allowed. Patch is attached for my fix, a
+more elegant solution may be possible.