]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc_r/uthread/uthread_cancel.c
add pthread_cancel, obtained from OpenBSD.
[FreeBSD/FreeBSD.git] / lib / libc_r / uthread / uthread_cancel.c
1 /*
2  * David Leonard <d@openbsd.org>, 1999. Public domain.
3  * $FreeBSD$
4  */
5
6 #include <sys/errno.h>
7 #include <pthread.h>
8 #include "pthread_private.h"
9
10 int
11 pthread_cancel(pthread_t pthread)
12 {
13         int ret;
14
15         if ((ret = _find_thread(pthread)) != 0) {
16                 /* NOTHING */
17         } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK) {
18                 ret = 0;
19         } else {
20                 /* Protect the scheduling queues: */
21                 _thread_kern_sig_defer();
22
23                 /* Check if we need to kick it back into the run queue: */
24                 if ((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0)
25                         switch (pthread->state) {
26                         case PS_RUNNING:
27                                 /* No need to resume: */
28                                 pthread->cancelflags |= PTHREAD_CANCELLING;
29                                 break;
30
31                         case PS_SPINBLOCK:
32                         case PS_FDR_WAIT:
33                         case PS_FDW_WAIT:
34                         case PS_POLL_WAIT:
35                         case PS_SELECT_WAIT:
36                         /* Remove these threads from the work queue: */
37                                 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
38                                     != 0)
39                                         PTHREAD_WORKQ_REMOVE(pthread);
40                                 /* Fall through: */
41                         case PS_SIGTHREAD:
42                         case PS_SLEEP_WAIT:
43                         case PS_WAIT_WAIT:
44                         case PS_SIGSUSPEND:
45                         case PS_SIGWAIT:
46                         case PS_SUSPENDED:
47                                 /* Interrupt and resume: */
48                                 pthread->interrupted = 1;
49                                 pthread->cancelflags |= PTHREAD_CANCELLING;
50                                 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
51                                 break;
52
53                         case PS_MUTEX_WAIT:
54                         case PS_COND_WAIT:
55                         case PS_FDLR_WAIT:
56                         case PS_FDLW_WAIT:
57                         case PS_FILE_WAIT:
58                         case PS_JOIN:
59                                 /*
60                                  * Threads in these states may be in queues.
61                                  * In order to preserve queue integrity, the
62                                  * cancelled thread must remove itself from the
63                                  * queue.  Mark the thread as interrupted and
64                                  * needing cancellation, and set the state to
65                                  * running.  When the thread resumes, it will
66                                  * exit after removing itself from the queue.
67                                  */
68                                 pthread->interrupted = 1;
69                                 pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
70                                 PTHREAD_NEW_STATE(pthread,PS_RUNNING);
71                                 break;
72
73                         case PS_DEAD:
74                         case PS_DEADLOCK:
75                         case PS_STATE_MAX:
76                                 /* Ignore - only here to silence -Wall: */
77                                 break;
78                 }
79                 /* Unprotect the scheduling queues: */
80                 _thread_kern_sig_undefer();
81
82                 ret = 0;
83         }
84         return (ret);
85 }
86
87 int
88 pthread_setcancelstate(int state, int *oldstate)
89 {
90         int ostate;
91         int ret;
92
93         ostate = _thread_run->cancelflags & PTHREAD_CANCEL_DISABLE;
94
95         switch (state) {
96         case PTHREAD_CANCEL_ENABLE:
97                 if (oldstate != NULL)
98                         *oldstate = ostate;
99                 _thread_run->cancelflags &= PTHREAD_CANCEL_ENABLE;
100                 if ((_thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)
101                         pthread_testcancel();
102                 ret = 0;
103                 break;
104         case PTHREAD_CANCEL_DISABLE:
105                 if (oldstate != NULL)
106                         *oldstate = ostate;
107                 _thread_run->cancelflags |= PTHREAD_CANCEL_DISABLE;
108                 ret = 0;
109                 break;
110         default:
111                 ret = EINVAL;
112         }
113
114         return (ret);
115 }
116
117 int
118 pthread_setcanceltype(int type, int *oldtype)
119 {
120         int otype;
121         int ret;
122
123         otype = _thread_run->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS;
124         switch (type) {
125         case PTHREAD_CANCEL_ASYNCHRONOUS:
126                 if (oldtype != NULL)
127                         *oldtype = otype;
128                 _thread_run->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS;
129                 pthread_testcancel();
130                 ret = 0;
131                 break;
132         case PTHREAD_CANCEL_DEFERRED:
133                 if (oldtype != NULL)
134                         *oldtype = otype;
135                 _thread_run->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS;
136                 ret = 0;
137                 break;
138         default:
139                 ret = EINVAL;
140         }
141
142         return (ret);
143 }
144
145 void
146 pthread_testcancel(void)
147 {
148
149         if (((_thread_run->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) &&
150             ((_thread_run->cancelflags & PTHREAD_CANCELLING) != 0)) {
151                 /*
152                  * It is possible for this thread to be swapped out
153                  * while performing cancellation; do not allow it
154                  * to be cancelled again.
155                  */
156                 _thread_run->cancelflags &= ~PTHREAD_CANCELLING;
157                 _thread_exit_cleanup();
158                 pthread_exit(PTHREAD_CANCELED);
159                 PANIC("cancel");
160         }
161 }
162
163 void
164 _thread_enter_cancellation_point(void)
165 {
166
167         /* Look for a cancellation before we block: */
168         pthread_testcancel();
169         _thread_run->cancelflags |= PTHREAD_AT_CANCEL_POINT;
170 }
171
172 void
173 _thread_leave_cancellation_point(void)
174 {
175
176         _thread_run->cancelflags &= ~PTHREAD_AT_CANCEL_POINT;
177         /* Look for a cancellation after we unblock: */
178         pthread_testcancel();
179 }