38 return;
39 }
9-40 The thd_suspend
function suspends a thread, and returns when that thread has ceased to execute user code. It first ensures that the suspend/resume package is initialized by calling pthread_once
. Under protection of a mutex, it searches for the target thread's identifier in the array of suspended thread identifiers. If the thread is already suspended, thd_suspend
returns successfully.
47-60 Determine whether there is an empty entry in the array of suspended threads and, if not, realloc
the array with an extra entry.
65-78 The sentinel variable is initialized to 0, to detect when the target thread suspension occurs. The thread is sent a SIGUSR1 signal by calling pthread_kill
, and thd_suspend
loops, calling sched_yield
to avoid monopolizing a processor, until the target thread responds by setting sentinel. Finally, the suspended thread's identifier is stored in the array.
¦ susp.c part 3 thd_suspend
1 /*
2 * Suspend a thread by sending it a signal (SIGUSR1), which will
3 * block the thread until another signal (SIGUSR2) arrives.
4 *
5 * Multiple calls to thd_suspend for a single thread have no
6 * additional effect on the thread — a single thd_continue
7 * call will cause it to resume execution.
8 */
9 int
10 thd_suspend (pthread_t target_thread)
11 {
12 int status;
13 int i = 0;
14
15 /*
16 * The first call to thd_suspend will initialize the
17 * package.
18 */
19 status = pthread_once (&once, suspend_init_routine);
20 if (status != 0)
21 return status;
22
23 /*
24 * Serialize access to suspend, makes life easier.
25 */
26 status = pthread_mutex_lock (&mut);
27 if (status != 0)
28 return status;
29
30 /*
31 * Threads that are suspended are added to the target_array;
32 * a request to suspend a thread already listed in the array
33 * is ignored. Sending a second SIGUSR1 would cause the
34 * thread to resuspend itself as soon as it is resumed.
35 */
36 while (i < bottom)
37 if (array[i++] == target_thread) {
38 status = pthread_mutex_unlock (&mut);
39 return status;
40 }
41
42 /*
43 * Ok, we really need to suspend this thread. So, let's find
44 * the location in the array that we'll use. If we run off
45 * the end, realloc the array for more space.
46 */
47 i = 0;
48 while (array[i] != 0)
49 i++;
50
51 if (i == bottom) {
52 array = (pthread_t*) realloc (
53 array, (++bottom * sizeof (pthread_t)));
54 if (array == NULL) {
55 pthread_mutex_unlock (&mut);
56 return errno;
57 }
58
59 array[bottom] = null_pthread; /* Clear new entry */
60 }
61
62 /*
63 * Clear the sentinel and signal the thread to suspend.
64 */
65 sentinel = 0;
66 status = pthread_kill (target_thread, SIGUSR1);
67 if (status != 0) {
68 pthread_mutex_unlock (&mut);
69 return status;
70 }
71
72 /*
73 * Wait for the sentinel to change.
74 */
75 while (sentinel == 0)
76 sched_yield ();
77
78 array[i] = target_thread;
79
80 status = pthread_mutex_unlock (&mut);
81 return status;
82 }
23-26 The thd_continue
function first checks whether the suspend/resume package has been initialized (inited
is not 0). If it has not been initialized, then no threads are suspended, and thd_continue
returns with success.