1/* 2 * Copyright (c) 2005 David Xu <davidxu@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 *
| 1/* 2 * Copyright (c) 2005 David Xu <davidxu@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 *
|
88static __inline void 89attr2sna(pthread_attr_t *attr, struct sigev_thread_attr *sna) 90{ 91 struct sched_param sched_param; 92 93 pthread_attr_getschedpolicy(attr, &sna->sna_policy); 94 pthread_attr_getinheritsched(attr, &sna->sna_inherit); 95 pthread_attr_getschedparam(attr, &sched_param); 96 sna->sna_prio = sched_param.sched_priority; 97 pthread_attr_getscope(attr, &sna->sna_scope); 98 pthread_attr_getstacksize(attr, &sna->sna_stacksize); 99 pthread_attr_getstackaddr(attr, &sna->sna_stackaddr); 100 pthread_attr_getguardsize(attr, &sna->sna_guardsize); 101} 102 103static __inline int 104sna_eq(const struct sigev_thread_attr *a, const struct sigev_thread_attr *b) 105{ 106 return memcmp(a, b, sizeof(*a)) == 0; 107} 108 109static __inline int 110have_threads(void) 111{ 112 return (pthread_create != NULL); 113} 114 115void 116__sigev_thread_init(void) 117{ 118 static int notfirst = 0; 119 int i; 120 121 sigev_list_mtx = malloc(sizeof(pthread_mutex_t)); 122 _pthread_mutex_init(sigev_list_mtx, NULL); 123 sigev_threads_mtx = malloc(sizeof(pthread_mutex_t)); 124 _pthread_mutex_init(sigev_threads_mtx, NULL); 125 for (i = 0; i < HASH_QUEUES; ++i) 126 LIST_INIT(&sigev_hash[i]); 127 LIST_INIT(&sigev_all); 128 TAILQ_INIT(&sigev_threads); 129 if (!notfirst) { 130 pthread_attr_init(&sigev_default_attr); 131 pthread_attr_setscope(&sigev_default_attr, PTHREAD_SCOPE_SYSTEM); 132 pthread_attr_setdetachstate(&sigev_default_attr, 133 PTHREAD_CREATE_DETACHED); 134 pthread_atfork(__sigev_fork_prepare, __sigev_fork_parent, 135 __sigev_fork_child); 136 notfirst = 1; 137 } 138} 139 140int 141__sigev_check_init(void) 142{ 143 if (!have_threads()) 144 return (-1); 145 146 _pthread_once(&sigev_once, __sigev_thread_init); 147 return (0); 148} 149 150void 151__sigev_fork_prepare(void) 152{ 153 __sigev_thread_list_lock(); 154} 155 156void 157__sigev_fork_parent(void) 158{ 159 __sigev_thread_list_unlock(); 160} 161 162void 163__sigev_fork_child(void) 164{ 165 __sigev_thread_init(); 166} 167 168int 169__sigev_list_lock(void) 170{ 171 return _pthread_mutex_lock(sigev_list_mtx); 172} 173 174int 175__sigev_list_unlock(void) 176{ 177 return _pthread_mutex_unlock(sigev_list_mtx); 178} 179 180int 181__sigev_thread_list_lock(void) 182{ 183 return _pthread_mutex_lock(sigev_threads_mtx); 184} 185 186int 187__sigev_thread_list_unlock(void) 188{ 189 return _pthread_mutex_unlock(sigev_threads_mtx); 190} 191 192struct sigev_node * 193__sigev_alloc(int type, const struct sigevent *evp) 194{ 195 struct sigev_node *sn; 196 197 sn = calloc(1, sizeof(*sn)); 198 if (sn != NULL) { 199 sn->sn_value = evp->sigev_value; 200 sn->sn_func = evp->sigev_notify_function; 201 sn->sn_gen = atomic_fetchadd_int(&sigev_generation, 1); 202 sn->sn_type = type; 203 sn->sn_tn = sigev_thread_create(evp->sigev_notify_attributes); 204 if (sn->sn_tn == NULL) { 205 free(sn); 206 sn = NULL; 207 } 208 } 209 return (sn); 210} 211 212void 213__sigev_get_sigevent(struct sigev_node *sn, struct sigevent *newevp, 214 sigev_id_t id) 215{ 216 /* 217 * Build a new sigevent, and tell kernel to deliver SIGEV_SIGSERVICE 218 * signal to the new thread. 219 */ 220 newevp->sigev_notify = SIGEV_THREAD_ID; 221 newevp->sigev_signo = SIGEV_SIGSERVICE; 222 newevp->sigev_notify_thread_id = (lwpid_t)sn->sn_tn->tn_lwpid; 223 newevp->sigev_value.sival_ptr = (void *)id; 224} 225 226void 227__sigev_free(struct sigev_node *sn) 228{ 229 free(sn); 230} 231 232struct sigev_node * 233__sigev_find(int type, sigev_id_t id) 234{ 235 struct sigev_node *sn; 236 int chain = HASH(type, id); 237 238 LIST_FOREACH(sn, &sigev_hash[chain], sn_link) { 239 if (sn->sn_type == type && sn->sn_id == id) 240 break; 241 } 242 return (sn); 243} 244 245int 246__sigev_register(struct sigev_node *sn) 247{ 248 int chain = HASH(sn->sn_type, sn->sn_id); 249 250 LIST_INSERT_HEAD(&sigev_hash[chain], sn, sn_link); 251 LIST_INSERT_HEAD(&sigev_all, sn, sn_allist); 252 return (0); 253} 254 255int 256__sigev_delete(int type, sigev_id_t id) 257{ 258 struct sigev_node *sn; 259 260 sn = __sigev_find(type, id); 261 if (sn != NULL) 262 return (__sigev_delete_node(sn)); 263 return (0); 264} 265 266int 267__sigev_delete_node(struct sigev_node *sn) 268{ 269 LIST_REMOVE(sn, sn_link); 270 LIST_REMOVE(sn, sn_allist); 271 272 if (sn->sn_flags & SNF_WORKING) 273 sn->sn_flags |= SNF_REMOVED; 274 else 275 __sigev_free(sn); 276 return (0); 277} 278 279static 280sigev_id_t 281sigev_get_id(siginfo_t *si) 282{ 283 switch(si->si_code) { 284 case SI_TIMER: 285 return (si->si_timerid); 286 case SI_MESGQ: 287 return (si->si_mqd); 288 case SI_ASYNCIO: 289 return (sigev_id_t)si->si_value.sival_ptr; 290 default: 291 warnx("%s %s : unknown si_code %d\n", __FILE__, __func__, 292 si->si_code); 293 } 294 return (-1); 295} 296 297static struct sigev_thread_node * 298sigev_thread_create(pthread_attr_t *pattr) 299{ 300 struct sigev_thread_node *tn; 301 struct sigev_thread_attr sna; 302 sigset_t set; 303 int ret; 304 305 if (pattr == NULL) 306 pattr = &sigev_default_attr; 307 else { 308 pthread_attr_setscope(pattr, PTHREAD_SCOPE_SYSTEM); 309 pthread_attr_setdetachstate(pattr, PTHREAD_CREATE_DETACHED); 310 } 311 312 attr2sna(pattr, &sna); 313 314 __sigev_thread_list_lock(); 315 /* Search a thread matching the required pthread_attr. */ 316 TAILQ_FOREACH(tn, &sigev_threads, tn_link) { 317 if (sna.sna_stackaddr == NULL) { 318 if (sna_eq(&tn->tn_sna, &sna)) 319 break; 320 } else { 321 /* 322 * Reuse the thread if it has same stack address, 323 * because two threads can not run on same stack. 324 */ 325 if (sna.sna_stackaddr == tn->tn_sna.sna_stackaddr) 326 break; 327 } 328 } 329 if (tn != NULL) { 330 __sigev_thread_list_unlock(); 331 return (tn); 332 } 333 tn = malloc(sizeof(*tn)); 334 tn->tn_sna = sna; 335 tn->tn_cur = NULL; 336 TAILQ_INSERT_TAIL(&sigev_threads, tn, tn_link); 337 sigemptyset(&set); 338 sigaddset(&set, SIGEV_SIGSERVICE); 339 _sigprocmask(SIG_BLOCK, &set, NULL); 340 _pthread_cond_init(&tn->tn_cv, NULL); 341 ret = pthread_create(&tn->tn_thread, pattr, sigev_service_loop, tn); 342 _sigprocmask(SIG_UNBLOCK, &set, NULL); 343 if (ret != 0) { 344 TAILQ_REMOVE(&sigev_threads, tn, tn_link); 345 __sigev_thread_list_unlock(); 346 _pthread_cond_destroy(&tn->tn_cv); 347 free(tn); 348 tn = NULL; 349 } else { 350 /* wait the thread to get its lwpid */ 351 _pthread_cond_wait(&tn->tn_cv, sigev_threads_mtx); 352 __sigev_thread_list_unlock(); 353 } 354 return (tn); 355} 356 357static void 358after_dispatch(struct sigev_thread_node *tn) 359{ 360 struct sigev_node *sn; 361 362 if ((sn = tn->tn_cur) != NULL) { 363 __sigev_list_lock(); 364 sn->sn_flags &= ~SNF_WORKING; 365 if (sn->sn_flags & SNF_REMOVED) 366 __sigev_free(sn); 367 else if (sn->sn_flags & SNF_ONESHOT) 368 __sigev_delete_node(sn); 369 tn->tn_cur = NULL; 370 __sigev_list_unlock(); 371 } 372} 373 374/* 375 * This function is called if user callback calls 376 * pthread_exit() or pthread_cancel() for the thread. 377 */ 378static void 379thread_cleanup(void *arg) 380{ 381 struct sigev_thread_node *tn = arg; 382 383 fprintf(stderr, "Dangerous Robinson, calling pthread_exit() from " 384 "SIGEV_THREAD is undefined."); 385 after_dispatch(tn); 386 /* longjmp(tn->tn_jbuf, 1); */ 387 abort(); 388} 389 390static void * 391sigev_service_loop(void *arg) 392{ 393 siginfo_t si; 394 sigset_t set; 395 struct sigev_thread_node *tn; 396 struct sigev_node *sn; 397 sigev_id_t id; 398 399 tn = arg; 400 thr_self(&tn->tn_lwpid); 401 __sigev_list_lock(); 402 _pthread_cond_broadcast(&tn->tn_cv); 403 __sigev_list_unlock(); 404 405 /* 406 * Service thread should not be killed by callback, if user 407 * attempts to do so, the thread will be restarted. 408 */ 409 setjmp(tn->tn_jbuf); 410 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 411 sigemptyset(&set); 412 sigaddset(&set, SIGEV_SIGSERVICE); 413 pthread_cleanup_push(thread_cleanup, tn); 414 for (;;) { 415 if (__predict_false(sigwaitinfo(&set, &si) == -1)) 416 continue; 417 418 id = sigev_get_id(&si); 419 __sigev_list_lock(); 420 sn = __sigev_find(si.si_code, id); 421 if (sn != NULL) { 422 tn->tn_cur = sn; 423 sn->sn_flags |= SNF_WORKING; 424 __sigev_list_unlock(); 425 sn->sn_dispatch(sn, &si); 426 after_dispatch(tn); 427 } else 428 tn->tn_cur = NULL; 429 __sigev_list_unlock(); 430 } 431 pthread_cleanup_pop(0); 432 return (0); 433}
| 81static __inline void 82attr2sna(pthread_attr_t *attr, struct sigev_thread_attr *sna) 83{ 84 struct sched_param sched_param; 85 86 pthread_attr_getschedpolicy(attr, &sna->sna_policy); 87 pthread_attr_getinheritsched(attr, &sna->sna_inherit); 88 pthread_attr_getschedparam(attr, &sched_param); 89 sna->sna_prio = sched_param.sched_priority; 90 pthread_attr_getscope(attr, &sna->sna_scope); 91 pthread_attr_getstacksize(attr, &sna->sna_stacksize); 92 pthread_attr_getstackaddr(attr, &sna->sna_stackaddr); 93 pthread_attr_getguardsize(attr, &sna->sna_guardsize); 94} 95 96static __inline int 97sna_eq(const struct sigev_thread_attr *a, const struct sigev_thread_attr *b) 98{ 99 return memcmp(a, b, sizeof(*a)) == 0; 100} 101 102static __inline int 103have_threads(void) 104{ 105 return (pthread_create != NULL); 106} 107 108void 109__sigev_thread_init(void) 110{ 111 static int notfirst = 0; 112 int i; 113 114 sigev_list_mtx = malloc(sizeof(pthread_mutex_t)); 115 _pthread_mutex_init(sigev_list_mtx, NULL); 116 sigev_threads_mtx = malloc(sizeof(pthread_mutex_t)); 117 _pthread_mutex_init(sigev_threads_mtx, NULL); 118 for (i = 0; i < HASH_QUEUES; ++i) 119 LIST_INIT(&sigev_hash[i]); 120 LIST_INIT(&sigev_all); 121 TAILQ_INIT(&sigev_threads); 122 if (!notfirst) { 123 pthread_attr_init(&sigev_default_attr); 124 pthread_attr_setscope(&sigev_default_attr, PTHREAD_SCOPE_SYSTEM); 125 pthread_attr_setdetachstate(&sigev_default_attr, 126 PTHREAD_CREATE_DETACHED); 127 pthread_atfork(__sigev_fork_prepare, __sigev_fork_parent, 128 __sigev_fork_child); 129 notfirst = 1; 130 } 131} 132 133int 134__sigev_check_init(void) 135{ 136 if (!have_threads()) 137 return (-1); 138 139 _pthread_once(&sigev_once, __sigev_thread_init); 140 return (0); 141} 142 143void 144__sigev_fork_prepare(void) 145{ 146 __sigev_thread_list_lock(); 147} 148 149void 150__sigev_fork_parent(void) 151{ 152 __sigev_thread_list_unlock(); 153} 154 155void 156__sigev_fork_child(void) 157{ 158 __sigev_thread_init(); 159} 160 161int 162__sigev_list_lock(void) 163{ 164 return _pthread_mutex_lock(sigev_list_mtx); 165} 166 167int 168__sigev_list_unlock(void) 169{ 170 return _pthread_mutex_unlock(sigev_list_mtx); 171} 172 173int 174__sigev_thread_list_lock(void) 175{ 176 return _pthread_mutex_lock(sigev_threads_mtx); 177} 178 179int 180__sigev_thread_list_unlock(void) 181{ 182 return _pthread_mutex_unlock(sigev_threads_mtx); 183} 184 185struct sigev_node * 186__sigev_alloc(int type, const struct sigevent *evp) 187{ 188 struct sigev_node *sn; 189 190 sn = calloc(1, sizeof(*sn)); 191 if (sn != NULL) { 192 sn->sn_value = evp->sigev_value; 193 sn->sn_func = evp->sigev_notify_function; 194 sn->sn_gen = atomic_fetchadd_int(&sigev_generation, 1); 195 sn->sn_type = type; 196 sn->sn_tn = sigev_thread_create(evp->sigev_notify_attributes); 197 if (sn->sn_tn == NULL) { 198 free(sn); 199 sn = NULL; 200 } 201 } 202 return (sn); 203} 204 205void 206__sigev_get_sigevent(struct sigev_node *sn, struct sigevent *newevp, 207 sigev_id_t id) 208{ 209 /* 210 * Build a new sigevent, and tell kernel to deliver SIGEV_SIGSERVICE 211 * signal to the new thread. 212 */ 213 newevp->sigev_notify = SIGEV_THREAD_ID; 214 newevp->sigev_signo = SIGEV_SIGSERVICE; 215 newevp->sigev_notify_thread_id = (lwpid_t)sn->sn_tn->tn_lwpid; 216 newevp->sigev_value.sival_ptr = (void *)id; 217} 218 219void 220__sigev_free(struct sigev_node *sn) 221{ 222 free(sn); 223} 224 225struct sigev_node * 226__sigev_find(int type, sigev_id_t id) 227{ 228 struct sigev_node *sn; 229 int chain = HASH(type, id); 230 231 LIST_FOREACH(sn, &sigev_hash[chain], sn_link) { 232 if (sn->sn_type == type && sn->sn_id == id) 233 break; 234 } 235 return (sn); 236} 237 238int 239__sigev_register(struct sigev_node *sn) 240{ 241 int chain = HASH(sn->sn_type, sn->sn_id); 242 243 LIST_INSERT_HEAD(&sigev_hash[chain], sn, sn_link); 244 LIST_INSERT_HEAD(&sigev_all, sn, sn_allist); 245 return (0); 246} 247 248int 249__sigev_delete(int type, sigev_id_t id) 250{ 251 struct sigev_node *sn; 252 253 sn = __sigev_find(type, id); 254 if (sn != NULL) 255 return (__sigev_delete_node(sn)); 256 return (0); 257} 258 259int 260__sigev_delete_node(struct sigev_node *sn) 261{ 262 LIST_REMOVE(sn, sn_link); 263 LIST_REMOVE(sn, sn_allist); 264 265 if (sn->sn_flags & SNF_WORKING) 266 sn->sn_flags |= SNF_REMOVED; 267 else 268 __sigev_free(sn); 269 return (0); 270} 271 272static 273sigev_id_t 274sigev_get_id(siginfo_t *si) 275{ 276 switch(si->si_code) { 277 case SI_TIMER: 278 return (si->si_timerid); 279 case SI_MESGQ: 280 return (si->si_mqd); 281 case SI_ASYNCIO: 282 return (sigev_id_t)si->si_value.sival_ptr; 283 default: 284 warnx("%s %s : unknown si_code %d\n", __FILE__, __func__, 285 si->si_code); 286 } 287 return (-1); 288} 289 290static struct sigev_thread_node * 291sigev_thread_create(pthread_attr_t *pattr) 292{ 293 struct sigev_thread_node *tn; 294 struct sigev_thread_attr sna; 295 sigset_t set; 296 int ret; 297 298 if (pattr == NULL) 299 pattr = &sigev_default_attr; 300 else { 301 pthread_attr_setscope(pattr, PTHREAD_SCOPE_SYSTEM); 302 pthread_attr_setdetachstate(pattr, PTHREAD_CREATE_DETACHED); 303 } 304 305 attr2sna(pattr, &sna); 306 307 __sigev_thread_list_lock(); 308 /* Search a thread matching the required pthread_attr. */ 309 TAILQ_FOREACH(tn, &sigev_threads, tn_link) { 310 if (sna.sna_stackaddr == NULL) { 311 if (sna_eq(&tn->tn_sna, &sna)) 312 break; 313 } else { 314 /* 315 * Reuse the thread if it has same stack address, 316 * because two threads can not run on same stack. 317 */ 318 if (sna.sna_stackaddr == tn->tn_sna.sna_stackaddr) 319 break; 320 } 321 } 322 if (tn != NULL) { 323 __sigev_thread_list_unlock(); 324 return (tn); 325 } 326 tn = malloc(sizeof(*tn)); 327 tn->tn_sna = sna; 328 tn->tn_cur = NULL; 329 TAILQ_INSERT_TAIL(&sigev_threads, tn, tn_link); 330 sigemptyset(&set); 331 sigaddset(&set, SIGEV_SIGSERVICE); 332 _sigprocmask(SIG_BLOCK, &set, NULL); 333 _pthread_cond_init(&tn->tn_cv, NULL); 334 ret = pthread_create(&tn->tn_thread, pattr, sigev_service_loop, tn); 335 _sigprocmask(SIG_UNBLOCK, &set, NULL); 336 if (ret != 0) { 337 TAILQ_REMOVE(&sigev_threads, tn, tn_link); 338 __sigev_thread_list_unlock(); 339 _pthread_cond_destroy(&tn->tn_cv); 340 free(tn); 341 tn = NULL; 342 } else { 343 /* wait the thread to get its lwpid */ 344 _pthread_cond_wait(&tn->tn_cv, sigev_threads_mtx); 345 __sigev_thread_list_unlock(); 346 } 347 return (tn); 348} 349 350static void 351after_dispatch(struct sigev_thread_node *tn) 352{ 353 struct sigev_node *sn; 354 355 if ((sn = tn->tn_cur) != NULL) { 356 __sigev_list_lock(); 357 sn->sn_flags &= ~SNF_WORKING; 358 if (sn->sn_flags & SNF_REMOVED) 359 __sigev_free(sn); 360 else if (sn->sn_flags & SNF_ONESHOT) 361 __sigev_delete_node(sn); 362 tn->tn_cur = NULL; 363 __sigev_list_unlock(); 364 } 365} 366 367/* 368 * This function is called if user callback calls 369 * pthread_exit() or pthread_cancel() for the thread. 370 */ 371static void 372thread_cleanup(void *arg) 373{ 374 struct sigev_thread_node *tn = arg; 375 376 fprintf(stderr, "Dangerous Robinson, calling pthread_exit() from " 377 "SIGEV_THREAD is undefined."); 378 after_dispatch(tn); 379 /* longjmp(tn->tn_jbuf, 1); */ 380 abort(); 381} 382 383static void * 384sigev_service_loop(void *arg) 385{ 386 siginfo_t si; 387 sigset_t set; 388 struct sigev_thread_node *tn; 389 struct sigev_node *sn; 390 sigev_id_t id; 391 392 tn = arg; 393 thr_self(&tn->tn_lwpid); 394 __sigev_list_lock(); 395 _pthread_cond_broadcast(&tn->tn_cv); 396 __sigev_list_unlock(); 397 398 /* 399 * Service thread should not be killed by callback, if user 400 * attempts to do so, the thread will be restarted. 401 */ 402 setjmp(tn->tn_jbuf); 403 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 404 sigemptyset(&set); 405 sigaddset(&set, SIGEV_SIGSERVICE); 406 pthread_cleanup_push(thread_cleanup, tn); 407 for (;;) { 408 if (__predict_false(sigwaitinfo(&set, &si) == -1)) 409 continue; 410 411 id = sigev_get_id(&si); 412 __sigev_list_lock(); 413 sn = __sigev_find(si.si_code, id); 414 if (sn != NULL) { 415 tn->tn_cur = sn; 416 sn->sn_flags |= SNF_WORKING; 417 __sigev_list_unlock(); 418 sn->sn_dispatch(sn, &si); 419 after_dispatch(tn); 420 } else 421 tn->tn_cur = NULL; 422 __sigev_list_unlock(); 423 } 424 pthread_cleanup_pop(0); 425 return (0); 426}
|