[108029] trunk/base/src/pextlib1.0/tracelib.c

cal at macports.org cal at macports.org
Wed Jul 10 16:34:44 PDT 2013


Revision: 108029
          https://trac.macports.org/changeset/108029
Author:   cal at macports.org
Date:     2013-07-10 16:34:44 -0700 (Wed, 10 Jul 2013)
Log Message:
-----------
tracelib: support systems < 10.6 by using djb's self-pipe trick instead of EVFILT_USER

See http://cr.yp.to/docs/selfpipe.html

Modified Paths:
--------------
    trunk/base/src/pextlib1.0/tracelib.c

Modified: trunk/base/src/pextlib1.0/tracelib.c
===================================================================
--- trunk/base/src/pextlib1.0/tracelib.c	2013-07-10 23:27:44 UTC (rev 108028)
+++ trunk/base/src/pextlib1.0/tracelib.c	2013-07-10 23:34:44 UTC (rev 108029)
@@ -81,6 +81,11 @@
 static char *depends;
 static int sock = -1;
 static int kq = -1;
+#ifndef EVFILT_USER
+/* if EVFILT_USER isn't available (< 10.6), use the self-pipe trick to return
+ * from the blocking kqueue(2) call by writing a byte to the pipe */
+static int selfpipe[2];
+#endif
 static int enable_fence = 0;
 static Tcl_Interp *interp;
 static pthread_mutex_t sock_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -472,6 +477,7 @@
     struct kevent kev;
     int flags;
     int oldsock;
+    int opensockcount = 0;
 
     if (-1 == (kq = kqueue())) {
         Tcl_SetErrno(errno);
@@ -516,8 +522,50 @@
             return TCL_ERROR;
         }
 
+
+#       ifndef EVFILT_USER
+        /* on systems that don't have EVFILT_USER, use the self-pipe trick to
+         * trigger returning from kevent(2) when tracelib closesocket is
+         * called. */
+        if (-1 == pipe(selfpipe)) {
+            Tcl_SetErrno(errno);
+            Tcl_ResetResult(in);
+            Tcl_AppendResult(in, "pipe: ", (char *) Tcl_PosixError(in), NULL);
+            return TCL_ERROR;
+        }
+
+        /* mark the write side of the pipe non-blocking */
+        flags = fcntl(selfpipe[1], F_GETFL, 0);
+        if (-1 == fcntl(selfpipe[1], F_SETFL, flags | O_NONBLOCK)) {
+            Tcl_SetErrno(errno);
+            Tcl_ResetResult(in);
+            Tcl_AppendResult(in, "fcntl(F_SETFL, += O_NONBLOCK): ", (char *) Tcl_PosixError(in), NULL);
+            return TCL_ERROR;
+        }
+
         /* wait for the user event on the listen socket, as sent by CloseCmd as
          * deathpill */
+        EV_SET(&kev, selfpipe[0], EVFILT_READ, EV_ADD | EV_RECEIPT, 0, 0, NULL);
+        if (1 != kevent(kq, &kev, 1, &kev, 1, NULL)) {
+            Tcl_SetErrno(errno);
+            Tcl_ResetResult(in);
+            Tcl_AppendResult(in, "kevent: ", (char *) Tcl_PosixError(in), NULL);
+            close(kq);
+            return TCL_ERROR;
+        }
+        /* kevent(2) on EV_RECEIPT: When passed as input, it forces EV_ERROR to
+         * always be returned. When a filter is successfully added, the data field
+         * will be zero. */
+        if ((kev.flags & EV_ERROR) == 0 || ((kev.flags & EV_ERROR) > 0 && kev.data != 0)) {
+            Tcl_SetErrno(kev.data);
+            Tcl_ResetResult(in);
+            Tcl_AppendResult(in, "kevent: ", (char *) Tcl_PosixError(in), NULL);
+            close(kq);
+            return TCL_ERROR;
+        }
+#       else /* ifndef EVFILT_USER */
+        /* wait for the user event on the listen socket, as sent by CloseCmd as
+         * deathpill */
         EV_SET(&kev, oldsock, EVFILT_USER, EV_ADD | EV_RECEIPT, 0, 0, NULL);
         if (1 != kevent(kq, &kev, 1, &kev, 1, NULL)) {
             Tcl_SetErrno(errno);
@@ -536,6 +584,7 @@
             close(kq);
             return TCL_ERROR;
         }
+#       endif /* ifndef EVFILT_USER */
     }
     pthread_mutex_unlock(&sock_mutex);
 
@@ -555,6 +604,18 @@
         } while (keventstatus == 0);
 
         for (i = 0; i < keventstatus; ++i) {
+#           ifndef EVFILT_USER
+            /* handle traffic on the selfpipe */
+            if ((int) res_kevents[i].ident == selfpipe[0]) {
+                pthread_mutex_lock(&sock_mutex);
+                close(selfpipe[0]);
+                close(selfpipe[1]);
+                selfpipe[0] = -1;
+                selfpipe[1] = -1;
+                pthread_mutex_unlock(&sock_mutex);
+                break;
+            }
+#           endif
             /* the control socket has activity – we might have a new
              * connection. We use a copy of sock here, because sock might have
              * been set to -1 by the close command */
@@ -610,6 +671,8 @@
                         close(s);
                         continue;
                     }
+
+                    opensockcount++;
                 }
 
                 if (cleanuping) {
@@ -626,12 +689,16 @@
                     close(res_kevents[i].ident);
                     /* closing the socket will automatically remove it from the
                      * kqueue :) */
+                    opensockcount--;
                 }
             }
         }
     }
 
     /* NOTE: We aren't necessarily closing all client sockets here! */
+    if (opensockcount > 0) {
+        fprintf(stderr, "tracelib: %d open sockets will leak at end of runcmd\n", opensockcount);
+    }
     pthread_mutex_lock(&sock_mutex);
     close(kq);
     kq = -1;
@@ -665,16 +732,18 @@
     return TCL_OK;
 }
 
-static int TracelibCloseSocketCmd(Tcl_Interp *interp) {
+static int TracelibCloseSocketCmd(Tcl_Interp *interp UNUSED) {
+    /* interp might be UNUSED on systems without EVFILT_USER */
     cleanuping = 1;
     pthread_mutex_lock(&sock_mutex);
     if (sock != -1) {
         int oldsock = sock;
         /*shutdown(sock, SHUT_RDWR);*/
-        close(sock);
+        close(oldsock);
         sock = -1;
 
         if (kq != -1) {
+#           ifdef EVFILT_USER
             int ret;
             struct kevent kev;
             EV_SET(&kev, oldsock, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
@@ -685,6 +754,13 @@
                 pthread_mutex_unlock(&sock_mutex);
                 return TCL_ERROR;
             }
+#           else /* ifdef EVFILT_USER */
+            /* We know the pipes have been created because kq != -1 and we have
+             * the lock. We don't have to check for errors, because none should
+             * occur but when the pipe is full, which we wouldn't care about.
+             * */
+            write(selfpipe[1], "!", 1);
+#           endif /* ifdef EVFILT_USER */
         }
     }
     pthread_mutex_unlock(&sock_mutex);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macports-changes/attachments/20130710/e3040c50/attachment.html>


More information about the macports-changes mailing list