31-42 If an alarm is found, it is removed from the list. The current time is retrieved by calling the time function, and it is compared to the requested time for the alarm. If the alarm has already expired, then alarm_thread will set sleep_time to 0. If the alarm has not expired, alarm_thread computes the difference between the current time and the alarm expiration time, and sets sleep_time to that number of seconds.
52-58 The mutex is always unlocked before sleeping or yielding. If the mutex remained locked, then main would be unable to insert a new alarm on the list. That would make the program behave synchronously—the user would have to wait until the alarm expired before doing anything else. (The user would be able to enter a single command, but would not receive another prompt until the next alarm expired.) Calling sleep blocks alarm_thread for the required period of time—it cannot run until the timer expires.
Calling sched_yield instead is slightly different. We'll describe sched_yield in detail later (in Section 5.5.2)—for now, just remember that calling sched_yield will yield the processor to a thread that is ready to run, but will return immediately if there are no
64-67 If the alarm pointer is not NULL, that is, if an alarm was processed from alarm_list, the function prints a message indicating that the alarm has expired. After printing the message, it frees the alarm structure. The thread is now ready to process another alarm.
■ alarm_mutex.c part 2 alarm_thread
1 /*
2 * The alarm thread's start routine.
3 */
4 void *alarm_thread (void *arg)
5 {
6 alarm_t *alarm;
7 int sleep_time;
8 time_t now;
9 int status; 10
11 /*
12 * Loop forever, processing commands. The alarm thread will
13 * be disintegrated when the process exits.
14 */
15 while (1) {
16 status = pthread_mutex_lock (&alarm_mutex);
17 if (status != 0)
18 err_abort (status, "Lock mutex");
19 alarm = alarm_list; 20
21 /*
22 * If the alarm list is empty, wait for one second. This
23 * allows the main thread to run, and read another
24 * command. If the list is not empty, remove the first
25 * item. Compute the number of seconds to wait — if the
26 * result is less than 0 (the time has passed), then set
27 * the sleep_time to 0.
28 */
29 if (alarm == NULL)
30 sleep_time = 1;
31 else {
32 alarm_list = alarm->link;
33 now = time (NULL);
34 if (alarm->time <= now)
35 sleep_time = 0;
36 else
37 sleep_time = alarm->time - now;
38 #ifdef DEBUG
39 printf ("[waiting: %d(%d)\"%s\"]\n", alarm->time,
40 sleep_time, alarm->message);
41 #endif
42 }
43
44 /*
45 * Unlock the mutex before waiting, so that the main
46 * thread can lock it to insert a new alarm request. If
47 * the sleep_time is 0, then call sched_yield, giving
48 * the main thread a chance to run if it has been
49 * readied by user input, without delaying the message
50 * if there's no input.
51 */
52 status = pthread_mutex_unlock (&alarm_mutex);
53 if (status != 0)
54 err_abort (status, "Unlock mutex");
55 if (sleep_time > 0)
56 sleep (sleep_time);
57 else
58 sched_yield ();
59
60 /*
61 * If a timer expired, print the message and free the
62 * structure.
63 */
64 if (alarm != NULL) {