Fix: handle sys_futex() FUTEX_WAIT interrupted by signal
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 6 Jul 2015 21:28:34 +0000 (17:28 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 9 Jul 2015 22:11:37 +0000 (18:11 -0400)
We need to handle EINTR returned by sys_futex() FUTEX_WAIT, otherwise a
signal interrupting this system call could make sys_futex return too
early, and therefore cause a synchronization issue.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/common/futex.c

index 7f07b1118178c1795a197aba98007e74b196dfee..078186743bfa468b9c5745d46438cfeb03fa8a17 100644 (file)
@@ -55,8 +55,11 @@ void futex_wait_update(int32_t *futex, int active)
 {
        if (active) {
                uatomic_set(futex, 1);
 {
        if (active) {
                uatomic_set(futex, 1);
-               futex_async(futex, FUTEX_WAKE,
-                               INT_MAX, NULL, NULL, 0);
+               if (futex_async(futex, FUTEX_WAKE,
+                               INT_MAX, NULL, NULL, 0) < 0) {
+                       PERROR("futex_async");
+                       abort();
+               }
        } else {
                uatomic_set(futex, 0);
        }
        } else {
                uatomic_set(futex, 0);
        }
@@ -84,10 +87,23 @@ void futex_nto1_wait(int32_t *futex)
 {
        cmm_smp_mb();
 
 {
        cmm_smp_mb();
 
-       if (uatomic_read(futex) == -1) {
-               futex_async(futex, FUTEX_WAIT, -1, NULL, NULL, 0);
+       if (uatomic_read(futex) != -1)
+               goto end;
+       while (futex_async(futex, FUTEX_WAIT, -1, NULL, NULL, 0)) {
+               switch (errno) {
+               case EWOULDBLOCK:
+                       /* Value already changed. */
+                       goto end;
+               case EINTR:
+                       /* Retry if interrupted by signal. */
+                       break;  /* Get out of switch. */
+               default:
+                       /* Unexpected error. */
+                       PERROR("futex_async");
+                       abort();
+               }
        }
        }
-
+end:
        DBG("Futex n to 1 wait done");
 }
 
        DBG("Futex n to 1 wait done");
 }
 
@@ -97,10 +113,13 @@ void futex_nto1_wait(int32_t *futex)
 LTTNG_HIDDEN
 void futex_nto1_wake(int32_t *futex)
 {
 LTTNG_HIDDEN
 void futex_nto1_wake(int32_t *futex)
 {
-       if (caa_unlikely(uatomic_read(futex) == -1)) {
-               uatomic_set(futex, 0);
-               futex_async(futex, FUTEX_WAKE, 1, NULL, NULL, 0);
+       if (caa_unlikely(uatomic_read(futex) != -1))
+               goto end;
+       uatomic_set(futex, 0);
+       if (futex_async(futex, FUTEX_WAKE, 1, NULL, NULL, 0) < 0) {
+               PERROR("futex_async");
+               abort();
        }
        }
-
+end:
        DBG("Futex n to 1 wake done");
 }
        DBG("Futex n to 1 wake done");
 }
This page took 0.025969 seconds and 4 git commands to generate.