xref: /openbsd-src/lib/librthread/rthread.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: rthread.c,v 1.91 2016/05/07 19:05:22 guenther Exp $ */
2 /*
3  * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 /*
19  * The heart of rthreads.  Basic functions like creating and joining
20  * threads.
21  */
22 
23 #include <sys/types.h>
24 #ifndef NO_PIC
25 #include <sys/exec_elf.h>
26 #pragma weak _DYNAMIC
27 #endif
28 
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <dlfcn.h>
36 #include <tib.h>
37 
38 #include <pthread.h>
39 
40 #include "cancel.h"		/* in libc/include */
41 #include "rthread.h"
42 #include "rthread_cb.h"
43 
44 /*
45  * Call nonstandard functions via names in the reserved namespace:
46  *	dlctl() -> _dlctl()
47  *	getthrid -> _thread_sys_getthrid
48  */
49 typeof(dlctl) dlctl asm("_dlctl") __attribute__((weak));
50 REDIRECT_SYSCALL(getthrid);
51 
52 /* weak stub to be overriden by ld.so */
53 int	dlctl(void *handle, int cmd, void *data) { return 0; }
54 
55 /*
56  * libc's signal wrappers hide SIGTHR; we need to call the real syscall
57  * stubs _thread_sys_* directly.
58  */
59 REDIRECT_SYSCALL(sigaction);
60 REDIRECT_SYSCALL(sigprocmask);
61 REDIRECT_SYSCALL(thrkill);
62 
63 static int concurrency_level;	/* not used */
64 
65 struct _spinlock _SPINLOCK_UNLOCKED_ASSIGN = _SPINLOCK_UNLOCKED;
66 
67 int _threads_ready;
68 size_t _thread_pagesize;
69 struct listhead _thread_list = LIST_HEAD_INITIALIZER(_thread_list);
70 struct _spinlock _thread_lock = _SPINLOCK_UNLOCKED;
71 static struct pthread_queue _thread_gc_list
72     = TAILQ_HEAD_INITIALIZER(_thread_gc_list);
73 static struct _spinlock _thread_gc_lock = _SPINLOCK_UNLOCKED;
74 static struct pthread _initial_thread;
75 
76 struct pthread_attr _rthread_attr_default = {
77 	.stack_addr			= NULL,
78 	.stack_size			= RTHREAD_STACK_SIZE_DEF,
79 /*	.guard_size		set in _rthread_init */
80 	.detach_state			= PTHREAD_CREATE_JOINABLE,
81 	.contention_scope		= PTHREAD_SCOPE_SYSTEM,
82 	.sched_policy			= SCHED_OTHER,
83 	.sched_param = { .sched_priority = 0 },
84 	.sched_inherit			= PTHREAD_INHERIT_SCHED,
85 };
86 
87 /*
88  * internal support functions
89  */
90 void
91 _spinlock(volatile struct _spinlock *lock)
92 {
93 	while (_atomic_lock(&lock->ticket))
94 		sched_yield();
95 }
96 
97 int
98 _spinlocktry(volatile struct _spinlock *lock)
99 {
100 	return 0 == _atomic_lock(&lock->ticket);
101 }
102 
103 void
104 _spinunlock(volatile struct _spinlock *lock)
105 {
106 	lock->ticket = _ATOMIC_LOCK_UNLOCKED;
107 }
108 
109 static void
110 _rthread_start(void *v)
111 {
112 	pthread_t thread = v;
113 	void *retval;
114 
115 	retval = thread->fn(thread->arg);
116 	pthread_exit(retval);
117 }
118 
119 static void
120 sigthr_handler(__unused int sig)
121 {
122 	struct tib *tib = TIB_GET();
123 	pthread_t self = tib->tib_thread;
124 
125 	/*
126 	 * Do nothing unless
127 	 * 1) pthread_cancel() has been called on this thread,
128 	 * 2) cancelation is enabled for it, and
129 	 * 3) we're not already in cancelation processing
130 	 */
131 	if (!tib->tib_canceled || tib->tib_cantcancel)
132 		return;
133 
134 	/*
135 	 * If delaying cancels inside complex ops (pthread_cond_wait,
136 	 * pthread_join, etc), just mark that this has happened to
137 	 * prevent a race with going to sleep
138 	 */
139 	if (tib->tib_cancel_point & CANCEL_POINT_DELAYED) {
140 		self->delayed_cancel = 1;
141 		return;
142 	}
143 
144 	/*
145 	 * otherwise, if in a cancel point or async cancels are
146 	 * enabled, then exit
147 	 */
148 	if (tib->tib_cancel_point ||
149 	    (tib->tib_thread_flags & TIB_THREAD_ASYNC_CANCEL))
150 		pthread_exit(PTHREAD_CANCELED);
151 }
152 
153 
154 /*
155  * A few basic callbacks for libc.  The first couple are only used
156  * on archs where there isn't a fast TCB_GET()
157  */
158 #ifndef TCB_HAVE_MD_GET
159 static int *
160 multi_threaded_errnoptr(void)
161 {
162         return (&TIB_GET()->tib_errno);
163 }
164 
165 static void *
166 multi_threaded_tcb(void)
167 {
168 	return (TCB_GET());
169 }
170 #endif /* TCB_HAVE_MD_GET */
171 
172 void
173 _thread_canceled(void)
174 {
175 	pthread_exit(PTHREAD_CANCELED);
176 }
177 
178 void
179 _rthread_init(void)
180 {
181 	pthread_t thread = &_initial_thread;
182 	struct tib *tib;
183 	struct sigaction sa;
184 
185 	tib = TIB_GET();
186 	tib->tib_thread = thread;
187 	thread->tib = tib;
188 
189 	thread->donesem.lock = _SPINLOCK_UNLOCKED_ASSIGN;
190 	tib->tib_thread_flags = TIB_THREAD_INITIAL_STACK;
191 	thread->flags_lock = _SPINLOCK_UNLOCKED_ASSIGN;
192 	strlcpy(thread->name, "Main process", sizeof(thread->name));
193 	LIST_INSERT_HEAD(&_thread_list, thread, threads);
194 	_rthread_debug_init();
195 
196 	_thread_pagesize = (size_t)sysconf(_SC_PAGESIZE);
197 	_rthread_attr_default.guard_size = _thread_pagesize;
198 	thread->attr = _rthread_attr_default;
199 
200 	/* get libc to start using our callbacks */
201 	{
202 		struct thread_callbacks cb = { 0 };
203 
204 #ifndef TCB_HAVE_MD_GET
205 		cb.tc_errnoptr		= multi_threaded_errnoptr;
206 		cb.tc_tcb		= multi_threaded_tcb;
207 #endif
208 		cb.tc_canceled		= _thread_canceled;
209 		cb.tc_flockfile		= _thread_flockfile;
210 		cb.tc_ftrylockfile	= _thread_ftrylockfile;
211 		cb.tc_funlockfile	= _thread_funlockfile;
212 		cb.tc_malloc_lock	= _thread_malloc_lock;
213 		cb.tc_malloc_unlock	= _thread_malloc_unlock;
214 		cb.tc_atexit_lock	= _thread_atexit_lock;
215 		cb.tc_atexit_unlock	= _thread_atexit_unlock;
216 		cb.tc_atfork_lock	= _thread_atfork_lock;
217 		cb.tc_atfork_unlock	= _thread_atfork_unlock;
218 		cb.tc_arc4_lock		= _thread_arc4_lock;
219 		cb.tc_arc4_unlock	= _thread_arc4_unlock;
220 		cb.tc_mutex_lock	= _thread_mutex_lock;
221 		cb.tc_mutex_unlock	= _thread_mutex_unlock;
222 		cb.tc_mutex_destroy	= _thread_mutex_destroy;
223 		cb.tc_tag_lock		= _thread_tag_lock;
224 		cb.tc_tag_unlock	= _thread_tag_unlock;
225 		cb.tc_tag_storage	= _thread_tag_storage;
226 		cb.tc_fork		= _thread_fork;
227 		cb.tc_vfork		= _thread_vfork;
228 		_thread_set_callbacks(&cb, sizeof(cb));
229 	}
230 
231 #ifndef NO_PIC
232 	if (_DYNAMIC) {
233 		dlctl(NULL, DL_SETTHREADLCK, _rthread_dl_lock);
234 	}
235 #endif
236 
237 	/*
238 	 * Set the handler on the signal used for cancelation and
239 	 * suspension, and make sure it's unblocked
240 	 */
241 	memset(&sa, 0, sizeof(sa));
242 	sigemptyset(&sa.sa_mask);
243 	sa.sa_handler = sigthr_handler;
244 	sigaction(SIGTHR, &sa, NULL);
245 	sigaddset(&sa.sa_mask, SIGTHR);
246 	sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
247 
248 	_threads_ready = 1;
249 
250 	_rthread_debug(1, "rthread init\n");
251 }
252 
253 static void
254 _rthread_free(pthread_t thread)
255 {
256 	_spinlock(&_thread_gc_lock);
257 	TAILQ_INSERT_TAIL(&_thread_gc_list, thread, waiting);
258 	_spinunlock(&_thread_gc_lock);
259 }
260 
261 /*
262  * real pthread functions
263  */
264 pthread_t
265 pthread_self(void)
266 {
267 	if (!_threads_ready)
268 		_rthread_init();
269 
270 	return (TIB_GET()->tib_thread);
271 }
272 DEF_STD(pthread_self);
273 
274 static void
275 _rthread_reaper(void)
276 {
277 	pthread_t thread;
278 
279 restart:
280 	_spinlock(&_thread_gc_lock);
281 	TAILQ_FOREACH(thread, &_thread_gc_list, waiting) {
282 		if (thread->tib->tib_tid != 0)
283 			continue;
284 		TAILQ_REMOVE(&_thread_gc_list, thread, waiting);
285 		_spinunlock(&_thread_gc_lock);
286 		if (thread != &_initial_thread) {
287 			_rthread_debug(3, "rthread reaping %p stack %p\n",
288 			    (void *)thread, (void *)thread->stack);
289 			_rthread_free_stack(thread->stack);
290 			_dl_free_tib(thread->tib, sizeof(*thread));
291 		} else {
292 			/* initial thread isn't part of TIB allocation */
293 			_rthread_debug(3, "rthread reaping %p (initial)\n",
294 			    (void *)thread);
295 			_dl_free_tib(thread->tib, 0);
296 		}
297 		goto restart;
298 	}
299 	_spinunlock(&_thread_gc_lock);
300 }
301 
302 void
303 pthread_exit(void *retval)
304 {
305 	struct rthread_cleanup_fn *clfn;
306 	struct tib *tib = TIB_GET();
307 	pthread_t thread;
308 
309 	if (!_threads_ready)
310 		_rthread_init();
311 	thread = tib->tib_thread;
312 
313 	if (tib->tib_cantcancel & CANCEL_DYING) {
314 		/*
315 		 * Called pthread_exit() from destructor or cancelation
316 		 * handler: blow up.  XXX write something to stderr?
317 		 */
318 		abort();
319 		//_exit(42);
320 	}
321 
322 	tib->tib_cantcancel |= CANCEL_DYING;
323 
324 	thread->retval = retval;
325 
326 	for (clfn = thread->cleanup_fns; clfn; ) {
327 		struct rthread_cleanup_fn *oclfn = clfn;
328 		clfn = clfn->next;
329 		oclfn->fn(oclfn->arg);
330 		free(oclfn);
331 	}
332 	_rthread_tls_destructors(thread);
333 	_spinlock(&_thread_lock);
334 	LIST_REMOVE(thread, threads);
335 	_spinunlock(&_thread_lock);
336 
337 	_spinlock(&thread->flags_lock);
338 	if (thread->flags & THREAD_DETACHED) {
339 		_spinunlock(&thread->flags_lock);
340 		_rthread_free(thread);
341 	} else {
342 		thread->flags |= THREAD_DONE;
343 		_spinunlock(&thread->flags_lock);
344 		_sem_post(&thread->donesem);
345 	}
346 
347 	__threxit(&tib->tib_tid);
348 	for(;;);
349 }
350 DEF_STD(pthread_exit);
351 
352 int
353 pthread_join(pthread_t thread, void **retval)
354 {
355 	int e;
356 	struct tib *tib = TIB_GET();
357 	pthread_t self;
358 	PREP_CANCEL_POINT(tib);
359 
360 	if (!_threads_ready)
361 		_rthread_init();
362 	self = tib->tib_thread;
363 
364 	e = 0;
365 	ENTER_DELAYED_CANCEL_POINT(tib, self);
366 	if (thread == NULL)
367 		e = EINVAL;
368 	else if (thread == self)
369 		e = EDEADLK;
370 	else if (thread->flags & THREAD_DETACHED)
371 		e = EINVAL;
372 	else if ((e = _sem_wait(&thread->donesem, 0, NULL,
373 	    &self->delayed_cancel)) == 0) {
374 		if (retval)
375 			*retval = thread->retval;
376 
377 		/*
378 		 * We should be the last having a ref to this thread,
379 		 * but someone stupid or evil might haved detached it;
380 		 * in that case the thread will clean up itself
381 		 */
382 		if ((thread->flags & THREAD_DETACHED) == 0)
383 			_rthread_free(thread);
384 	}
385 
386 	LEAVE_CANCEL_POINT_INNER(tib, e);
387 	_rthread_reaper();
388 	return (e);
389 }
390 
391 int
392 pthread_detach(pthread_t thread)
393 {
394 	int rc = 0;
395 
396 	_spinlock(&thread->flags_lock);
397 	if (thread->flags & THREAD_DETACHED) {
398 		rc = EINVAL;
399 		_spinunlock(&thread->flags_lock);
400 	} else if (thread->flags & THREAD_DONE) {
401 		_spinunlock(&thread->flags_lock);
402 		_rthread_free(thread);
403 	} else {
404 		thread->flags |= THREAD_DETACHED;
405 		_spinunlock(&thread->flags_lock);
406 	}
407 	_rthread_reaper();
408 	return (rc);
409 }
410 
411 int
412 pthread_create(pthread_t *threadp, const pthread_attr_t *attr,
413     void *(*start_routine)(void *), void *arg)
414 {
415 	extern int __isthreaded;
416 	struct tib *tib;
417 	pthread_t thread;
418 	struct __tfork param;
419 	int rc;
420 
421 	if (!_threads_ready)
422 		_rthread_init();
423 
424 	_rthread_reaper();
425 
426 	tib = _dl_allocate_tib(sizeof(*thread));
427 	if (tib == NULL)
428 		return (ENOMEM);
429 	thread = tib->tib_thread;
430 	memset(thread, 0, sizeof(*thread));
431 	thread->tib = tib;
432 	thread->donesem.lock = _SPINLOCK_UNLOCKED_ASSIGN;
433 	thread->flags_lock = _SPINLOCK_UNLOCKED_ASSIGN;
434 	thread->fn = start_routine;
435 	thread->arg = arg;
436 	tib->tib_tid = -1;
437 
438 	thread->attr = attr != NULL ? *(*attr) : _rthread_attr_default;
439 	if (thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
440 		pthread_t self = pthread_self();
441 
442 		thread->attr.sched_policy = self->attr.sched_policy;
443 		thread->attr.sched_param = self->attr.sched_param;
444 	}
445 	if (thread->attr.detach_state == PTHREAD_CREATE_DETACHED)
446 		thread->flags |= THREAD_DETACHED;
447 
448 	thread->stack = _rthread_alloc_stack(thread);
449 	if (!thread->stack) {
450 		rc = errno;
451 		goto fail1;
452 	}
453 
454 	param.tf_tcb = TIB_TO_TCB(tib);
455 	param.tf_tid = &tib->tib_tid;
456 	param.tf_stack = thread->stack->sp;
457 
458 	_spinlock(&_thread_lock);
459 	LIST_INSERT_HEAD(&_thread_list, thread, threads);
460 	_spinunlock(&_thread_lock);
461 
462 	/* we're going to be multi-threaded real soon now */
463 	__isthreaded = 1;
464 	rc = __tfork_thread(&param, sizeof(param), _rthread_start, thread);
465 	if (rc != -1) {
466 		/* success */
467 		*threadp = thread;
468 		return (0);
469 	}
470 
471 	rc = errno;
472 
473 	_spinlock(&_thread_lock);
474 	LIST_REMOVE(thread, threads);
475 	_spinunlock(&_thread_lock);
476 	_rthread_free_stack(thread->stack);
477 fail1:
478 	_dl_free_tib(tib, sizeof(*thread));
479 
480 	return (rc);
481 }
482 
483 int
484 pthread_kill(pthread_t thread, int sig)
485 {
486 	struct tib *tib = thread->tib;
487 
488 	if (sig == SIGTHR)
489 		return (EINVAL);
490 	if (thrkill(tib->tib_tid, sig, TIB_TO_TCB(tib)))
491 		return (errno);
492 	return (0);
493 }
494 
495 int
496 pthread_equal(pthread_t t1, pthread_t t2)
497 {
498 	return (t1 == t2);
499 }
500 
501 int
502 pthread_cancel(pthread_t thread)
503 {
504 	struct tib *tib = thread->tib;
505 	pid_t tid = tib->tib_tid;
506 
507 	if (tib->tib_canceled == 0 && tid != 0 &&
508 	    (tib->tib_cantcancel & CANCEL_DYING) == 0) {
509 		tib->tib_canceled = 1;
510 
511 		if ((tib->tib_cantcancel & CANCEL_DISABLED) == 0) {
512 			thrkill(tid, SIGTHR, TIB_TO_TCB(tib));
513 			return (0);
514 		}
515 	}
516 	return (0);
517 }
518 
519 void
520 pthread_testcancel(void)
521 {
522 	struct tib *tib = TIB_GET();
523 
524 	if (tib->tib_canceled && (tib->tib_cantcancel & CANCEL_DISABLED) == 0)
525 		pthread_exit(PTHREAD_CANCELED);
526 }
527 
528 int
529 pthread_setcancelstate(int state, int *oldstatep)
530 {
531 	struct tib *tib = TIB_GET();
532 	int oldstate;
533 
534 	oldstate = tib->tib_cantcancel & CANCEL_DISABLED ?
535 	    PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE;
536 	if (state == PTHREAD_CANCEL_ENABLE) {
537 		tib->tib_cantcancel &= ~CANCEL_DISABLED;
538 	} else if (state == PTHREAD_CANCEL_DISABLE) {
539 		tib->tib_cantcancel |= CANCEL_DISABLED;
540 	} else {
541 		return (EINVAL);
542 	}
543 	if (oldstatep)
544 		*oldstatep = oldstate;
545 
546 	return (0);
547 }
548 DEF_STD(pthread_setcancelstate);
549 
550 int
551 pthread_setcanceltype(int type, int *oldtypep)
552 {
553 	struct tib *tib = TIB_GET();
554 	int oldtype;
555 
556 	oldtype = tib->tib_thread_flags & TIB_THREAD_ASYNC_CANCEL ?
557 	    PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED;
558 	if (type == PTHREAD_CANCEL_DEFERRED) {
559 		tib->tib_thread_flags &=~ TIB_THREAD_ASYNC_CANCEL;
560 	} else if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
561 		tib->tib_thread_flags |= TIB_THREAD_ASYNC_CANCEL;
562 	} else {
563 		return (EINVAL);
564 	}
565 	if (oldtypep)
566 		*oldtypep = oldtype;
567 
568 	return (0);
569 }
570 
571 void
572 pthread_cleanup_push(void (*fn)(void *), void *arg)
573 {
574 	struct rthread_cleanup_fn *clfn;
575 	pthread_t self = pthread_self();
576 
577 	clfn = calloc(1, sizeof(*clfn));
578 	if (!clfn)
579 		return;
580 	clfn->fn = fn;
581 	clfn->arg = arg;
582 	clfn->next = self->cleanup_fns;
583 	self->cleanup_fns = clfn;
584 }
585 
586 void
587 pthread_cleanup_pop(int execute)
588 {
589 	struct rthread_cleanup_fn *clfn;
590 	pthread_t self = pthread_self();
591 
592 	clfn = self->cleanup_fns;
593 	if (clfn) {
594 		self->cleanup_fns = clfn->next;
595 		if (execute)
596 			clfn->fn(clfn->arg);
597 		free(clfn);
598 	}
599 }
600 
601 int
602 pthread_getconcurrency(void)
603 {
604 	return (concurrency_level);
605 }
606 
607 int
608 pthread_setconcurrency(int new_level)
609 {
610 	if (new_level < 0)
611 		return (EINVAL);
612 	concurrency_level = new_level;
613 	return (0);
614 }
615 
616 /*
617  * compat debug stuff
618  */
619 void
620 _thread_dump_info(void)
621 {
622 	pthread_t thread;
623 
624 	_spinlock(&_thread_lock);
625 	LIST_FOREACH(thread, &_thread_list, threads)
626 		printf("thread %d flags 0x%x name %s\n", thread->tib->tib_tid,
627 		    thread->tib->tib_thread_flags, thread->name);
628 	_spinunlock(&_thread_lock);
629 }
630 
631 #ifndef NO_PIC
632 /*
633  * _rthread_dl_lock() provides the locking for dlopen(), dlclose(), and
634  * the function called via atexit() to invoke all destructors.  The latter
635  * two call shared-object destructors, which may need to call dlclose(),
636  * so this lock needs to permit recursive locking.
637  * The specific code here was extracted from _rthread_mutex_lock() and
638  * pthread_mutex_unlock() and simplified to use the static variables.
639  */
640 void
641 _rthread_dl_lock(int what)
642 {
643 	static struct _spinlock lock = _SPINLOCK_UNLOCKED;
644 	static pthread_t owner = NULL;
645 	static struct pthread_queue lockers = TAILQ_HEAD_INITIALIZER(lockers);
646 	static int count = 0;
647 
648 	if (what == 0) {
649 		pthread_t self = pthread_self();
650 
651 		/* lock, possibly recursive */
652 		_spinlock(&lock);
653 		if (owner == NULL) {
654 			owner = self;
655 		} else if (owner != self) {
656 			TAILQ_INSERT_TAIL(&lockers, self, waiting);
657 			while (owner != self) {
658 				__thrsleep(self, 0 | _USING_TICKETS, NULL,
659 				    &lock.ticket, NULL);
660 				_spinlock(&lock);
661 			}
662 		}
663 		count++;
664 		_spinunlock(&lock);
665 	} else if (what == 1) {
666 		/* unlock, possibly recursive */
667 		if (--count == 0) {
668 			pthread_t next;
669 
670 			_spinlock(&lock);
671 			owner = next = TAILQ_FIRST(&lockers);
672 			if (next != NULL)
673 				TAILQ_REMOVE(&lockers, next, waiting);
674 			_spinunlock(&lock);
675 			if (next != NULL)
676 				__thrwakeup(next, 1);
677 		}
678 	} else {
679 		/* reinit: used in child after fork to clear the queue */
680 		lock = _SPINLOCK_UNLOCKED_ASSIGN;
681 		if (--count == 0)
682 			owner = NULL;
683 		TAILQ_INIT(&lockers);
684 	}
685 }
686 #endif
687