32-35 Notice the code to check for EINTR return status from the sem_wait call. The POSIX timer signal in this program will always occur while one or more threads are blocked in sem_wait. When a signal occurs for a process (such as a timer signal), the system may deliver that signal within the context of any thread within the process. Likely "victims" include threads that the kernel knows to be waiting, for example, on a semaphore. So there is a fairly good chance that the sem_wait thread will be chosen, at least sometimes. If that occurs, the call to sem_wait will return with EINTR. The thread must then retry the call. Treating an EINTR return as "success" would make it appear that two threads had been awakened by each call to sem_post: the thread that was interrupted, and the thread that was awakened by the sem_post call.
■ semaphore_signal.c
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include "errors.h"
8
9 sem_t semaphore;
10
11 /*
12 * Signal-catching function.
13 */
14 void signal_catcher (int sig)
15 {
16 if (sem_post (&semaphore) == -1)
17 errno_abort ("Post semaphore");
18 }
19
20 /*
21 * Thread start routine which waits on the semaphore.
22 */
23 void *sem_waiter (void *arg)
24 {
25 int number = (int)arg;
26 int counter;
27
28 /*
29 * Each thread waits 5 times.
30 */
31 for (counter = 1; counter <= 5; counter++) {
32 while (sem_wait (&semaphore) == -1) {
33 if (errno != EINTR)
34 errno_abort ("Wait on semaphore");
35 }
36 printf ("%d waking (%d)...\n", number, counter);
37 }
38 return NULL;
39 }
40
41 int main (int argc, char *argv[])
42 {
43 int thread_count, status;
44 struct sigevent sig_event;
45 struct sigaction sig_action;
46 sigset_t sig_mask;
47 timer_t timer_id;
48 struct itimerspec timer_val;
49 pthread_t sem_waiters[5];
50
51 #if !defined(_POSIX_SEMAPHORES) || !defined(_POSIX_TIMERS)
52 #if !defined(_POSIX_SEMAPHORES)
53 printf ("This system does not support POSIX semaphores\n");
54 # endif
55 #if !defined(_POSIX_TIMERS)
56 printf ("This system does not support POSIX timers\n");
57 #endif
58 return -1;
59 #else
60 sem_init (&semaphore, 0, 0);
61
62 /*
63 * Create 5 threads to wait on a semaphore.
64 */
65 for (thread_count = 0; thread_count < 5; thread_count++) {
66 status = pthread_create (
67 &sem_waiters[thread_count], NULL,
68 sem_waiter, (void*)thread_count);
69 if (status != 0)
70 err_abort (status, "Create thread");
71 }
72
73 /*
74 * Set up a repeating timer using signal number SIGRTMIN,
75 * set to occur every 2 seconds.
76 */
77 sig_event.sigev_value.sival_int = 0;
78 sig_event.sigev_signo = SIGRTMIN;
79 sig_event.sigev_notify = SIGEV_SIGNAL;
80 if (timer_create (CLOCK_REALTIME, &sig_event, &timer_id) == -1)
81 errno_abort ("Create timer");
82 sigemptyset (&sig_mask);
83 sigaddset (&sig_mask, SIGRTMIN);
84 sig_action.sa_handler = signal_catcher;
85 sig_action.sa_mask = sig mask;
86 sig_action.sa_flags = 0;
87 if (sigaction (SIGRTMIN, &sig_action, NULL) == -1)