]> git.corax.cc Git - corax/commitdiff
klibc/sem: Make sem_wait() return -EINTR if interrupted due to a signal
authorMatthias Kruk <m@m10k.eu>
Sat, 4 Apr 2020 15:57:03 +0000 (00:57 +0900)
committerMatthias Kruk <m@m10k.eu>
Sat, 4 Apr 2020 15:57:03 +0000 (00:57 +0900)
kernel/include/sem.h
kernel/klibc/sem.c

index 169f13e185b3140f56938be6481a92bc5dc928e4..10a475373415b1d21d575b92a0bcfdf9d732ad72 100644 (file)
@@ -29,9 +29,17 @@ typedef struct {
  *  keep trying until it succeeds, meaning that the calling task may
  *  be suspended indefinitely if no other task invokes sem_post() on
  *  the same semaphore.
+ *  A task that is waiting on a semaphore may, however, be interrupted
+ *  by the scheduler due to the advent of a signal. In this case, the
+ *  function call will return early and the semaphore will not have
+ *  been modified. In such a case, it is not safe for the caller to
+ *  proceed - i.e. the intended synchronisation has not taken place.
+ *  Therefore, a check of the return value of this function must not
+ *  be omitted.
  *
  * RETURN VALUE
- *  0 the value of the semaphore has been successfully decreased
+ *       0 the value of the semaphore has been successfully decreased
+ *  -EINTR The task was woken up by the scheduler due to a signal
  */
 int sem_wait(sem_t*);
 
index 955e64d694af8623612d92b54990271bd0f24a92..281bc4db0a3dbf04bec11ecb4a52f73a034070e0 100644 (file)
@@ -72,7 +72,19 @@ int sem_wait(sem_t *sem)
                         * If we have a valid slot, go to bed and wait for
                         * someone to wake us up.
                         */
-                       sched_sleep(NULL);
+                       if(sched_sleep(NULL) == -EINTR) {
+                               /*
+                                * A signal has interrupted the sleep. Free the slot that
+                                * we've been using and return to the caller immediately.
+                                */
+
+                               spinlock_lock(&(sem->sem_lock));
+                               sem->sem_waitq[slot] = NULL;
+                               spinlock_unlock(&(sem->sem_lock));
+
+                               ret_val = -EINTR;
+                               break;
+                       }
                }
 
        } while(ret_val < 0);