handle EINTR for kevent calls
authorDaniel Becker <razzfazz@gmail.com>
Sat, 9 Jan 2016 19:46:25 +0000 (11:46 -0800)
committerDaniel Becker <razzfazz@gmail.com>
Sat, 9 Jan 2016 20:17:52 +0000 (12:17 -0800)
A kevent() syscall may "fail" with EINTR if the process receives
a signal before the timeout expires and before an event is placed
in the kqueue; in this case, rather than erroring out, the
syscall should simply be retried.

mcs/class/System/System.IO/KeventWatcher.cs

index 996e0e9b61fafdaf6fa845d870a1e19b7a372ff5..5d476a724b39e87962b03ce8bd0659271b3dcfa8 100644 (file)
@@ -317,10 +317,17 @@ namespace System.IO {
                        var eventBuffer = new kevent[0]; // we don't want to take any events from the queue at this point
                        var changes = CreateChangeList (ref initialFds);
 
-                       int numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref immediate_timeout);
+                       int numEvents;
+                       int errno = 0;
+                       do {
+                               numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref immediate_timeout);
+                               if (numEvents == -1) {
+                                       errno = Marshal.GetLastWin32Error ();
+                               }
+                       } while (numEvents == -1 && errno == EINTR);
 
                        if (numEvents == -1) {
-                               var errMsg = String.Format ("kevent() error at initial event registration, error code = '{0}'", Marshal.GetLastWin32Error ());
+                               var errMsg = String.Format ("kevent() error at initial event registration, error code = '{0}'", errno);
                                throw new IOException (errMsg);
                        }
                }
@@ -384,9 +391,10 @@ namespace System.IO {
                                        // Stop () signals us to stop by closing the connection
                                        if (requestStop)
                                                break;
-                                       if (++retries == 3)
+                                       int errno = Marshal.GetLastWin32Error ();
+                                       if (errno != EINTR && ++retries == 3)
                                                throw new IOException (String.Format (
-                                                       "persistent kevent() error, error code = '{0}'", Marshal.GetLastWin32Error ()));
+                                                       "persistent kevent() error, error code = '{0}'", errno));
 
                                        continue;
                                }
@@ -646,6 +654,7 @@ namespace System.IO {
                const int O_EVTONLY = 0x8000;
                const int F_GETPATH = 50;
                const int __DARWIN_MAXPATHLEN = 1024;
+               const int EINTR = 4;
                static readonly kevent[] emptyEventList = new System.IO.kevent[0];
                int maxFds = Int32.MaxValue;