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 *
|
27 * 28 */ 29 30#include <sys/types.h> 31#include <machine/atomic.h> 32 33#include "namespace.h" 34#include <err.h> 35#include <ucontext.h> 36#include <sys/thr.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40#include <signal.h> 41#include <pthread.h> 42#include "un-namespace.h" 43 44#include "sigev_thread.h" 45 46LIST_HEAD(sigev_list_head, sigev_node); 47#define HASH_QUEUES 17 48#define HASH(t, id) ((((id) << 3) + (t)) % HASH_QUEUES) 49static struct sigev_list_head sigev_hash[HASH_QUEUES]; 50static struct sigev_list_head sigev_all; 51static int sigev_generation; 52static pthread_mutex_t *sigev_list_mtx; 53static TAILQ_HEAD(,sigev_thread_node) sigev_threads; 54static pthread_mutex_t *sigev_threads_mtx; 55static pthread_attr_t sigev_default_attr; 56static pthread_once_t sigev_once = PTHREAD_ONCE_INIT; 57 58static void __sigev_fork_prepare(void); 59static void __sigev_fork_parent(void); 60static void __sigev_fork_child(void); 61static struct sigev_thread_node *sigev_thread_create(pthread_attr_t *); 62static void *sigev_service_loop(void *); 63 64#pragma weak pthread_create 65#pragma weak pthread_attr_getschedpolicy 66#pragma weak pthread_attr_getinheritsched 67#pragma weak pthread_attr_getschedparam 68#pragma weak pthread_attr_getscope 69#pragma weak pthread_attr_getstacksize 70#pragma weak pthread_attr_getstackaddr 71#pragma weak pthread_attr_getguardsize 72#pragma weak pthread_attr_init 73#pragma weak pthread_attr_setscope 74#pragma weak pthread_attr_setdetachstate 75#pragma weak pthread_atfork 76#pragma weak _pthread_once 77#pragma weak pthread_cleanup_push 78#pragma weak pthread_cleanup_pop 79#pragma weak pthread_setcancelstate 80 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);
| 27 * 28 */ 29 30#include <sys/types.h> 31#include <machine/atomic.h> 32 33#include "namespace.h" 34#include <err.h> 35#include <ucontext.h> 36#include <sys/thr.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40#include <signal.h> 41#include <pthread.h> 42#include "un-namespace.h" 43 44#include "sigev_thread.h" 45 46LIST_HEAD(sigev_list_head, sigev_node); 47#define HASH_QUEUES 17 48#define HASH(t, id) ((((id) << 3) + (t)) % HASH_QUEUES) 49static struct sigev_list_head sigev_hash[HASH_QUEUES]; 50static struct sigev_list_head sigev_all; 51static int sigev_generation; 52static pthread_mutex_t *sigev_list_mtx; 53static TAILQ_HEAD(,sigev_thread_node) sigev_threads; 54static pthread_mutex_t *sigev_threads_mtx; 55static pthread_attr_t sigev_default_attr; 56static pthread_once_t sigev_once = PTHREAD_ONCE_INIT; 57 58static void __sigev_fork_prepare(void); 59static void __sigev_fork_parent(void); 60static void __sigev_fork_child(void); 61static struct sigev_thread_node *sigev_thread_create(pthread_attr_t *); 62static void *sigev_service_loop(void *); 63 64#pragma weak pthread_create 65#pragma weak pthread_attr_getschedpolicy 66#pragma weak pthread_attr_getinheritsched 67#pragma weak pthread_attr_getschedparam 68#pragma weak pthread_attr_getscope 69#pragma weak pthread_attr_getstacksize 70#pragma weak pthread_attr_getstackaddr 71#pragma weak pthread_attr_getguardsize 72#pragma weak pthread_attr_init 73#pragma weak pthread_attr_setscope 74#pragma weak pthread_attr_setdetachstate 75#pragma weak pthread_atfork 76#pragma weak _pthread_once 77#pragma weak pthread_cleanup_push 78#pragma weak pthread_cleanup_pop 79#pragma weak pthread_setcancelstate 80 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);
|