[pypy-commit] pypy default: Issue #2623

arigo pypy.commits at gmail.com
Sat Aug 5 02:58:59 EDT 2017


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r92085:2d3c081aa72d
Date: 2017-08-05 08:58 +0200
http://bitbucket.org/pypy/pypy/changeset/2d3c081aa72d/

Log:	Issue #2623

	Tweak the signals logic to avoid the possibly-harmful optimization
	of pypysig_occurred.

diff --git a/rpython/translator/c/src/signals.c b/rpython/translator/c/src/signals.c
--- a/rpython/translator/c/src/signals.c
+++ b/rpython/translator/c/src/signals.c
@@ -31,11 +31,11 @@
 # endif
 #endif
 
+#define N_LONGBITS  (8 * sizeof(long))
+#define N_LONGSIG   ((NSIG - 1) / N_LONGBITS + 1)
+
 struct pypysig_long_struct pypysig_counter = {0};
-static char volatile pypysig_flags[NSIG] = {0};
-static int volatile pypysig_occurred = 0;
-/* pypysig_occurred is only an optimization: it tells if any
-   pypysig_flags could be set. */
+static long volatile pypysig_flags_bits[N_LONGSIG];
 static int wakeup_fd = -1;
 static int wakeup_with_nul_byte = 1;
 
@@ -73,12 +73,28 @@
 #endif
 }
 
+#ifdef _WIN32
+#define atomic_cas(ptr, oldv, newv)   (InterlockedCompareExchange(ptr, \
+                                            newv, oldv) == (oldv))
+#else
+#define atomic_cas(ptr, oldv, newv)    __sync_bool_compare_and_swap(ptr, \
+                                            oldv, newv)
+#endif
+
 void pypysig_pushback(int signum)
 {
     if (0 <= signum && signum < NSIG)
       {
-        pypysig_flags[signum] = 1;
-        pypysig_occurred = 1;
+        int ok, index = signum / N_LONGBITS;
+        unsigned long bitmask = 1UL << (signum % N_LONGBITS);
+        do
+        {
+            long value = pypysig_flags_bits[index];
+            if (value & bitmask)
+                break;   /* already set */
+            ok = atomic_cas(&pypysig_flags_bits[index], value, value | bitmask);
+        } while (!ok);
+
         pypysig_counter.value = -1;
       }
 }
@@ -161,19 +177,22 @@
 
 int pypysig_poll(void)
 {
-  if (pypysig_occurred)
-    {
-      int i;
-      pypysig_occurred = 0;
-      for (i=0; i<NSIG; i++)
-        if (pypysig_flags[i])
-          {
-            pypysig_flags[i] = 0;
-            pypysig_occurred = 1;   /* maybe another signal is pending */
-            return i;
-          }
+    int index;
+    for (index = 0; index < N_LONGSIG; index++) {
+        long value;
+      retry:
+        value = pypysig_flags_bits[index];
+        if (value != 0L) {
+            int j = 0;
+            while ((value & (1UL << j)) == 0)
+                j++;
+            if (!atomic_cas(&pypysig_flags_bits[index], value,
+                            value & ~(1UL << j)))
+                goto retry;
+            return index * N_LONGBITS + j;
+        }
     }
-  return -1;  /* no pending signal */
+    return -1;  /* no pending signal */
 }
 
 int pypysig_set_wakeup_fd(int fd, int with_nul_byte)


More information about the pypy-commit mailing list