dotgnu-pnet-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[dotgnu-pnet-commits] pnetlib ChangeLog System/Net/Sockets/Socket.cs ...


From: Radek Polak
Subject: [dotgnu-pnet-commits] pnetlib ChangeLog System/Net/Sockets/Socket.cs ...
Date: Fri, 12 Oct 2007 15:10:55 +0000

CVSROOT:        /sources/dotgnu-pnet
Module name:    pnetlib
Changes by:     Radek Polak <radekp>    07/10/12 15:10:55

Modified files:
        .              : ChangeLog 
        System/Net/Sockets: Socket.cs 
Added files:
        DotGNU.Misc    : BlockingOperation.cs 
        System/Private : BlockingOperation.cs BlockingOperations.cs 

Log message:
        fix closing socket by canceling operations that are blocked in system 
calls (bug bug #20885)

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/pnetlib/ChangeLog?cvsroot=dotgnu-pnet&r1=1.2515&r2=1.2516
http://cvs.savannah.gnu.org/viewcvs/pnetlib/DotGNU.Misc/BlockingOperation.cs?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/pnetlib/System/Net/Sockets/Socket.cs?cvsroot=dotgnu-pnet&r1=1.24&r2=1.25
http://cvs.savannah.gnu.org/viewcvs/pnetlib/System/Private/BlockingOperation.cs?cvsroot=dotgnu-pnet&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/pnetlib/System/Private/BlockingOperations.cs?cvsroot=dotgnu-pnet&rev=1.1

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/dotgnu-pnet/pnetlib/ChangeLog,v
retrieving revision 1.2515
retrieving revision 1.2516
diff -u -b -r1.2515 -r1.2516
--- ChangeLog   9 Oct 2007 12:19:43 -0000       1.2515
+++ ChangeLog   12 Oct 2007 15:10:54 -0000      1.2516
@@ -1,3 +1,17 @@
+2007-10-12  Radek Polak  <address@hidden>
+
+       * DotGNU.Misc/BlockingOperation.cs: Class for aborting operations
+       blocked in kernel calls. This can be useful when user is pinvoking
+       kernel calls.
+
+       * System/Private/BlockingOperation.cs,
+       System/Private/BlockingOperations.cs: Helper classes. They are used to
+       abort operations that are blocking in kernel when socket is closed.
+
+       * System/Net/Sockets/Socket.cs: Handle closing correctly by aborting
+       all blocked operations on this socket. This fixes bug #20885. 
+
+
 2007-10-09  Radek Polak  <address@hidden>
 
        * System/IO/Ports/SerialPort.cs: Check return value from write to port

Index: System/Net/Sockets/Socket.cs
===================================================================
RCS file: /sources/dotgnu-pnet/pnetlib/System/Net/Sockets/Socket.cs,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -b -r1.24 -r1.25
--- System/Net/Sockets/Socket.cs        23 Nov 2006 11:05:35 -0000      1.24
+++ System/Net/Sockets/Socket.cs        12 Oct 2007 15:10:55 -0000      1.25
@@ -23,6 +23,7 @@
 
 using Platform;
 using System;
+using System.Private;
 using System.Collections;
 using System.Security;
 using System.Threading;
@@ -39,6 +40,7 @@
        private EndPoint localEP;
        private EndPoint remoteEP;
        private Object readLock;
+       private BlockingOperations blockingOps;
 
        // Invalid socket handle.
        private static readonly IntPtr InvalidHandle =
@@ -120,6 +122,7 @@
                                this.localEP = null;
                                this.remoteEP = null;
                                this.readLock = new Object();
+                               this.blockingOps = new BlockingOperations();
 
                                // Attempt to create the socket.  This may bail 
out for
                                // some address families, even if 
"AddressFamilySupported"
@@ -147,6 +150,7 @@
                                this.localEP = null;
                                this.remoteEP = remoteEP;
                                this.readLock = new Object();
+                               this.blockingOps = new BlockingOperations();
                        }
 
        // Destructor.
@@ -213,11 +217,14 @@
                                // Accept a new connection on the socket.  We 
do this outside
                                // of the lock's protection so that multiple 
threads can
                                // wait for incoming connections on the same 
socket.
+                               using(BlockingOperation op = 
blockingOps.NewOp())
+                               {
                                if(!SocketMethods.Accept
                                          (currentHandle, addrReturn, out 
newHandle))
                                {
                                        throw new 
SocketException(this.GetErrno());
                                }
+                               }
 
                                // Create the end-point object for the remote 
side.
                                remoteEP = LocalEndPoint.Create(new 
SocketAddress(addrReturn));
@@ -743,10 +750,13 @@
                                        }
 
                                        // Connect to the foreign location.
+                                       using(BlockingOperation op = 
blockingOps.NewOp())
+                                       {
                                        if(!SocketMethods.Connect(handle, addr))
                                        {
                                                throw new 
SocketException(this.GetErrno());
                                        }
+                                       }
                                        connected = true;
                                        this.remoteEP = remoteEP;
                                }
@@ -761,6 +771,7 @@
                                        {
                                                SocketMethods.Close(handle);
                                                handle = InvalidHandle;
+                                               blockingOps.Abort();
                                        }
                                }
                        }
@@ -939,11 +950,15 @@
                                                        throw new 
SocketException(Errno.EINVAL);
                                                }
                                                byte[] data = new byte 
[optionLength];
-                                               
if(!SocketMethods.DiscoverIrDADevices(handle, data))
+                                               using(BlockingOperation op = 
blockingOps.NewOp())
+                                               {
+                                                       
if(!SocketMethods.DiscoverIrDADevices
+                                                                       
(handle, data))
                                                {
                                                        throw new 
SocketException
                                                                
(this.GetErrno());
                                                }
+                                               }
                                                return data;
                                        }
                                }
@@ -995,6 +1010,8 @@
                                array[0] = GetHandle(this);
 
                                // Perform the select.
+                               using(BlockingOperation op = 
blockingOps.NewOp())
+                               {
                                switch(mode)
                                {
                                        case SelectMode.SelectRead:
@@ -1025,6 +1042,7 @@
                                        }
                                        // Not reached.
                                }
+                               }
 
                                // Decode the result and return.
                                if(result == 0)
@@ -1058,8 +1076,11 @@
                                                throw new 
ObjectDisposedException
                                                        
(S._("Exception_Disposed"));
                                        }
+                                       using(BlockingOperation op = 
blockingOps.NewOp())
+                                       {
                                        result = SocketMethods.Receive
                                                (handle, buffer, offset, size, 
(int)socketFlags);
+                                       }
                                        if(result < 0)
                                        {
                                                throw new 
SocketException(this.GetErrno());
@@ -1121,9 +1142,12 @@
                                                throw new 
ObjectDisposedException
                                                        
(S._("Exception_Disposed"));
                                        }
+                                       using(BlockingOperation op = 
blockingOps.NewOp())
+                                       {
                                        result = SocketMethods.ReceiveFrom
                                                (handle, buffer, offset, size,
                                                 (int)socketFlags, addrReturn);
+                                       }
                                        if(result < 0)
                                        {
                                                throw new 
SocketException(this.GetErrno());
@@ -1380,8 +1404,11 @@
                                                throw new 
ObjectDisposedException
                                                        
(S._("Exception_Disposed"));
                                        }
+                                       using(BlockingOperation op = 
blockingOps.NewOp())
+                                       {
                                        result = SocketMethods.Send
                                                (handle, buffer, offset, size, 
(int)socketFlags);
+                                       }
                                        if(result < 0)
                                        {
                                                throw new 
SocketException(this.GetErrno());
@@ -1442,8 +1469,12 @@
                                                throw new 
ObjectDisposedException
                                                        
(S._("Exception_Disposed"));
                                        }
+                                       using(BlockingOperation op = 
blockingOps.NewOp())
+                                       {
                                        result = SocketMethods.SendTo
-                                               (handle, buffer, offset, size, 
(int)socketFlags, addr);
+                                                       (handle, buffer, 
offset, size,
+                                                        (int)socketFlags, 
addr);
+                                       }
                                        if(result < 0)
                                        {
                                                throw new 
SocketException(this.GetErrno());

Index: DotGNU.Misc/BlockingOperation.cs
===================================================================
RCS file: DotGNU.Misc/BlockingOperation.cs
diff -N DotGNU.Misc/BlockingOperation.cs
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ DotGNU.Misc/BlockingOperation.cs    12 Oct 2007 15:10:55 -0000      1.1
@@ -0,0 +1,37 @@
+/*
+ * BlockingOperation.cs - Class for aborting blocking operation.
+ *
+ * Copyright (C) 2007  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+namespace DotGNU.Misc
+{
+
+using System;
+using System.Threading;
+using System.Runtime.CompilerServices;
+
+public sealed class BlockingOperation
+{
+       // Send IL_SIG_ABORT to given thread to cancel operation that is 
blocking
+       // in system call.
+       [MethodImpl(MethodImplOptions.InternalCall)]
+       extern public static void ThreadSigAbort(Thread thread);
+
+}; // class BlockingOperation
+
+}; // namespace DotGNU.Misc

Index: System/Private/BlockingOperation.cs
===================================================================
RCS file: System/Private/BlockingOperation.cs
diff -N System/Private/BlockingOperation.cs
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ System/Private/BlockingOperation.cs 12 Oct 2007 15:10:55 -0000      1.1
@@ -0,0 +1,84 @@
+/*
+ * BlockingOperation.cs - Helper class for aborting blocking operation.
+ *
+ * Copyright (C) 2007  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+namespace System.Private
+{
+
+using System;
+using System.Threading;
+using System.Runtime.CompilerServices;
+
+// Helper that must be disposed after blocking operation ends.
+internal sealed class BlockingOperation : IDisposable
+{
+       // Internal state.
+       private Thread thread;
+       private BlockingOperation next;
+
+       // Constructor.
+       public BlockingOperation(Thread thread)
+                       {
+                               this.thread = thread;
+                       }
+
+       public Thread Thread
+                       {
+                               get
+                               {
+                                       return thread;
+                               }
+                               set
+                               {
+                                       thread = value;
+                               }
+                       }
+
+       public BlockingOperation Next
+                       {
+                               get
+                               {
+                                       return next;
+                               }
+                               set
+                               {
+                                       next = value;
+                               }
+                       }
+
+       // Send IL_SIG_ABORT to given thread to cancel operation that is 
blocking
+       // in system call.
+       [MethodImpl(MethodImplOptions.InternalCall)]
+       extern public static void ThreadSigAbort(Thread thread);
+
+       // Handle leave from blocking operation.
+       public void Dispose()
+                       {
+                               thread = null;
+                       }
+
+       public void Abort()
+                       {
+                               ThreadSigAbort(thread);
+                               thread = null;
+                       }
+
+}; // class BlockingOperation
+
+}; // namespace System.Private

Index: System/Private/BlockingOperations.cs
===================================================================
RCS file: System/Private/BlockingOperations.cs
diff -N System/Private/BlockingOperations.cs
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ System/Private/BlockingOperations.cs        12 Oct 2007 15:10:55 -0000      
1.1
@@ -0,0 +1,104 @@
+/*
+ * BlockingOperations.cs - Class used to abort blocking operations on unixes.
+ *
+ * Copyright (C) 2007  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+namespace System.Private
+{
+
+using System;
+using System.Threading;
+using Platform;
+
+// On unix when thread enters blocking system call (e.g. socket accept), it
+// cant be regulary aborted from managed code. On windows you can unblock the
+// thread by closing socket's handle.
+//
+// This class is used to emulate the windows behavior by sending abort signal
+// when socket is closed.
+//
+// This class holds references to threads that are blocked in kernel calls.
+// Call NewOp() before you start blocking operation and dispose returned result
+// when blocking operation ends. For example:
+//
+// using(BlockingOperation op = blockingOps.NewOp())
+// {
+//             some_blocking_operation_e_g_socket.accept();
+// }
+//
+// After you close resource of blocking operation (socket), you can call
+// Abort() to unblock all registered operations that are blocking.
+internal sealed class BlockingOperations
+{
+       // Internal state.
+       private BlockingOperation operations;
+
+       // Constructor.
+       public BlockingOperations()
+                       {
+                       }
+
+       // Call this method before starting blocking operation.
+       // Dispose result after operation is done.
+       public BlockingOperation NewOp()
+                       {
+                               lock(this)
+                               {
+                                       // Try to find free handler
+                                       BlockingOperation o = operations;
+                                       while(o != null)
+                                       {
+                                               if(o.Thread == null)
+                                               {
+                                                       o.Thread = 
Thread.CurrentThread;
+                                                       return o;
+                                               }
+                                               else
+                                               {
+                                                       o = o.Next;
+                                               }
+                                       }
+
+                                       // Create new handler and append other 
handlers
+                                       o = operations;
+                                       operations = new 
BlockingOperation(Thread.CurrentThread);
+                                       operations.Next = o;
+                                       return operations;
+                               }
+                       }
+
+       // Abort all blocking operations.
+       public void Abort()
+                       {
+                               lock(this)
+                               {
+                                       BlockingOperation o = operations;
+                                       while(o != null)
+                                       {
+                                               if(o.Thread != null)
+                                               {
+                                                       o.Abort();
+                                               }
+                                               o = o.Next;
+                                       }
+                               }
+                       }
+
+}; // class BlockingOperations
+
+}; // namespace System.Private




reply via email to

[Prev in Thread] Current Thread [Next in Thread]