xref: /freebsd/lib/libthr/thread/thr_syscalls.c (revision 6af83ee0d2941d18880b6aaa2b4facd1d30c6106)
1 /*
2  * Copyright (c) 2000 Jason Evans <jasone@freebsd.org>.
3  * Copyright (c) 2002 Daniel M. Eischen <deischen@freebsd.org>
4  * Copyright (c) 2003 Jeff Roberson <jeff@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice(s), this list of conditions and the following disclaimer as
12  *    the first lines of this file unmodified other than the possible
13  *    addition of one or more copyright notices.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice(s), this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33 
34 /*
35  * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
36  * All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *	This product includes software developed by John Birrell.
49  * 4. Neither the name of the author nor the names of any co-contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  */
66 
67 #include <sys/cdefs.h>
68 #include <sys/fcntl.h>
69 #include <sys/mman.h>
70 #include <sys/param.h>
71 #include <sys/select.h>
72 #include <sys/socket.h>
73 #include <sys/time.h>
74 #include <sys/types.h>
75 #include <sys/uio.h>
76 #include <sys/wait.h>
77 
78 #include <aio.h>
79 #include <dirent.h>
80 #include <errno.h>
81 #include <fcntl.h>
82 #include <poll.h>
83 #include <pthread.h>
84 #include <semaphore.h>
85 #include <signal.h>
86 #include <stdarg.h>
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include <termios.h>
91 #include <unistd.h>
92 
93 #include "thr_private.h"
94 
95 extern spinlock_t *__malloc_lock;
96 
97 extern int __creat(const char *, mode_t);
98 extern int __sleep(unsigned int);
99 extern int __sys_nanosleep(const struct timespec *, struct timespec *);
100 extern int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
101 extern int __sys_sigaction(int, const struct sigaction *, struct sigaction *);
102 extern int __system(const char *);
103 extern int __tcdrain(int);
104 extern pid_t __wait(int *);
105 extern pid_t __sys_wait4(pid_t, int *, int, struct rusage *);
106 extern pid_t __waitpid(pid_t, int *, int);
107 
108 __weak_reference(_accept, accept);
109 
110 int
111 _accept(int s, struct sockaddr *addr, socklen_t *addrlen)
112 {
113 	int ret;
114 
115 	_thread_enter_cancellation_point();
116 	ret = __sys_accept(s, addr, addrlen);
117 	_thread_leave_cancellation_point();
118 	return (ret);
119 }
120 
121 __weak_reference(_aio_suspend, aio_suspend);
122 
123 int
124 _aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct
125     timespec *timeout)
126 {
127 	int	ret;
128 
129 	_thread_enter_cancellation_point();
130 	ret = __sys_aio_suspend(iocbs, niocb, timeout);
131 	_thread_leave_cancellation_point();
132 
133 	return ret;
134 }
135 
136 __weak_reference(_close, close);
137 
138 int
139 _close(int fd)
140 {
141 	int	ret;
142 
143 	_thread_enter_cancellation_point();
144 	ret = __sys_close(fd);
145 	_thread_leave_cancellation_point();
146 
147 	return ret;
148 }
149 
150 __weak_reference(_connect, connect);
151 
152 int
153 _connect(int s, const struct sockaddr *n, socklen_t l)
154 {
155 	int ret;
156 
157 	_thread_enter_cancellation_point();
158 	ret = __sys_connect(s, n, l);
159 	_thread_leave_cancellation_point();
160 	return ret;
161 }
162 
163 __weak_reference(_creat, creat);
164 
165 int
166 _creat(const char *path, mode_t mode)
167 {
168 	int	ret;
169 
170 	_thread_enter_cancellation_point();
171 	ret = __creat(path, mode);
172 	_thread_leave_cancellation_point();
173 
174 	return ret;
175 }
176 
177 __weak_reference(_fcntl, fcntl);
178 
179 int
180 _fcntl(int fd, int cmd,...)
181 {
182 	int	ret;
183 	va_list	ap;
184 
185 	_thread_enter_cancellation_point();
186 
187 	va_start(ap, cmd);
188 	switch (cmd) {
189 		case F_DUPFD:
190 		case F_SETFD:
191 		case F_SETFL:
192 			ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
193 			break;
194 		case F_GETFD:
195 		case F_GETFL:
196 			ret = __sys_fcntl(fd, cmd);
197 			break;
198 		default:
199 			ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
200 	}
201 	va_end(ap);
202 
203 	_thread_leave_cancellation_point();
204 
205 	return ret;
206 }
207 
208 __weak_reference(_fork, fork);
209 
210 int
211 _fork(int fd)
212 {
213 	int	ret;
214 	struct pthread_atfork *af;
215 
216 	_pthread_mutex_lock(&_atfork_mutex);
217 
218 	/* Run down atfork prepare handlers. */
219 	TAILQ_FOREACH_REVERSE(af, &_atfork_list, atfork_head, qe) {
220 		if (af->prepare != NULL)
221 			af->prepare();
222 	}
223 
224  	/*
225 	 * Fork a new process.
226 	 * XXX - The correct way to handle __malloc_lock is to have
227 	 *	 the threads libraries (or libc) install fork handlers for it
228 	 *	 in their initialization routine. We should probably
229 	 *	 do that for all the locks in libc.
230 	 */
231 	if (__isthreaded && __malloc_lock != NULL)
232 		_SPINLOCK(__malloc_lock);
233 	ret = __sys_fork();
234  	if (ret == 0) {
235 		__isthreaded = 0;
236 		if (__malloc_lock != NULL)
237 			memset(__malloc_lock, 0, sizeof(spinlock_t));
238 		init_tdlist(curthread, 1);
239 		init_td_common(curthread, NULL, 1);
240 		_mutex_reinit(&_atfork_mutex);
241 
242 		/* Run down atfork child handlers. */
243 		TAILQ_FOREACH(af, &_atfork_list, qe) {
244 			if (af->child != NULL)
245 				af->child();
246 		}
247  	} else if (ret != -1) {
248 		/* Run down atfork parent handlers. */
249 		TAILQ_FOREACH(af, &_atfork_list, qe) {
250 			if (af->parent != NULL)
251 			af->parent();
252 		}
253 	}
254 
255 	if (ret != 0) {
256 		if (__isthreaded && __malloc_lock != NULL)
257 			_SPINUNLOCK(__malloc_lock);
258 		_pthread_mutex_unlock(&_atfork_mutex);
259 	}
260 	return ret;
261 }
262 
263 
264 __weak_reference(_fsync, fsync);
265 
266 int
267 _fsync(int fd)
268 {
269 	int	ret;
270 
271 	_thread_enter_cancellation_point();
272 	ret = __sys_fsync(fd);
273 	_thread_leave_cancellation_point();
274 
275 	return ret;
276 }
277 
278 __weak_reference(_msgrcv, msgrcv);
279 
280 int
281 _msgrcv(int id, void *p, size_t sz, long t, int f)
282 {
283 	int ret;
284 
285 	_thread_enter_cancellation_point();
286 	ret = __sys_msgrcv(id, p, sz, t, f);
287 	_thread_leave_cancellation_point();
288 	return ret;
289 }
290 
291 __weak_reference(_msgsnd, msgsnd);
292 
293 int
294 _msgsnd(int id, const void *p, size_t sz, int f)
295 {
296 	int ret;
297 
298 	_thread_enter_cancellation_point();
299 	ret = __sys_msgsnd(id, p, sz, f);
300 	_thread_leave_cancellation_point();
301 	return ret;
302 }
303 
304 __weak_reference(_msync, msync);
305 
306 int
307 _msync(void *addr, size_t len, int flags)
308 {
309 	int	ret;
310 
311 	_thread_enter_cancellation_point();
312 	ret = __sys_msync(addr, len, flags);
313 	_thread_leave_cancellation_point();
314 
315 	return ret;
316 }
317 
318 __weak_reference(_nanosleep, nanosleep);
319 
320 int
321 _nanosleep(const struct timespec * time_to_sleep, struct timespec *
322     time_remaining)
323 {
324 	int	ret;
325 
326 	_thread_enter_cancellation_point();
327 	ret = __sys_nanosleep(time_to_sleep, time_remaining);
328 	_thread_leave_cancellation_point();
329 
330 	return ret;
331 }
332 
333 __weak_reference(_open, open);
334 
335 int
336 _open(const char *path, int flags,...)
337 {
338 	int	ret;
339 	int	mode = 0;
340 	va_list	ap;
341 
342 	_thread_enter_cancellation_point();
343 
344 	/* Check if the file is being created: */
345 	if (flags & O_CREAT) {
346 		/* Get the creation mode: */
347 		va_start(ap, flags);
348 		mode = va_arg(ap, int);
349 		va_end(ap);
350 	}
351 
352 	ret = __sys_open(path, flags, mode);
353 	_thread_leave_cancellation_point();
354 
355 	return ret;
356 }
357 
358 /*
359  * The implementation in libc calls sigpause(), which is also
360  * a cancellation point.
361  */
362 #if 0
363 __weak_reference(_pause, pause);
364 
365 int
366 _pause(void)
367 {
368 	_thread_enter_cancellation_point();
369 	__pause();
370 	_thread_leave_cancellation_point();
371 }
372 #endif
373 
374 __weak_reference(_poll, poll);
375 
376 int
377 _poll(struct pollfd *fds, unsigned int nfds, int timeout)
378 {
379 	int ret;
380 
381 	_thread_enter_cancellation_point();
382 	ret = __sys_poll(fds, nfds, timeout);
383 	_thread_leave_cancellation_point();
384 
385 	return ret;
386 }
387 
388 /* XXXFix */
389 #if 0
390 __weak_reference(_pread, pread);
391 
392 ssize_t
393 _pread(int d, void *b, size_t n, off_t o)
394 {
395 	ssize_t ret;
396 
397 	_thread_enter_cancellation_point();
398 	ret = __sys_pread(d, b, n, o);
399 	_thread_leave_cancellation_point();
400 	return (ret);
401 }
402 #endif
403 
404 /* The libc version calls select(), which is also a cancellation point. */
405 #if 0
406 extern int __pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
407 		const struct timespec *timo, const sigset_t *mask);
408 
409 int
410 pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
411 	const struct timespec *timo, const sigset_t *mask)
412 {
413 	int ret;
414 
415 	_thread_enter_cancellation_point();
416 	ret = __pselect(count, rfds, wfds, efds, timo, mask);
417 	_thread_leave_cancellation_point();
418 
419 	return (ret);
420 }
421 #endif
422 
423 /* XXXFix */
424 #if 0
425 __weak_reference(_pwrite, pwrite);
426 
427 ssize_t
428 _pwrite(int d, const void *b, size_t n, off_t o)
429 {
430 	ssize_t ret;
431 
432 	_thread_enter_cancellation_point();
433 	ret = __sys_pwrite(d, b, n, o);
434 	_thread_leave_cancellation_point();
435 	return (ret);
436 }
437 #endif
438 
439 __weak_reference(_raise, raise);
440 
441 int
442 _raise(int sig)
443 {
444 	int error;
445 
446 	error = pthread_kill(pthread_self(), sig);
447 	if (error != 0) {
448 		errno = error;
449 		error = -1;
450 	}
451 	return (error);
452 }
453 
454 __weak_reference(_read, read);
455 
456 ssize_t
457 _read(int fd, void *buf, size_t nbytes)
458 {
459 	ssize_t	ret;
460 
461 	_thread_enter_cancellation_point();
462 	ret = __sys_read(fd, buf, nbytes);
463 	_thread_leave_cancellation_point();
464 
465 	return ret;
466 }
467 
468 __weak_reference(_readv, readv);
469 
470 ssize_t
471 _readv(int fd, const struct iovec *iov, int iovcnt)
472 {
473 	ssize_t ret;
474 
475 	_thread_enter_cancellation_point();
476 	ret = __sys_readv(fd, iov, iovcnt);
477 	_thread_leave_cancellation_point();
478 
479 	return ret;
480 }
481 
482 /*
483  * The libc implementation of recv() calls recvfrom, which
484  * is also a cancellation point.
485  */
486 #if 0
487 __weak_reference(_recv, recv);
488 
489 ssize_t
490 _recv(int s, void *b, size_t l, int f)
491 {
492 	ssize_t ret;
493 
494 	_thread_enter_cancellation_point();
495 	ret = __sys_recv(s, b, l, f);
496 	_thread_leave_cancellation_point();
497 	return (ret);
498 }
499 #endif
500 
501 __weak_reference(_recvfrom, recvfrom);
502 
503 ssize_t
504 _recvfrom(int s, void *b, size_t l, int f, struct sockaddr *from,
505     socklen_t *fl)
506 {
507 	ssize_t ret;
508 
509 	_thread_enter_cancellation_point();
510 	ret = __sys_recvfrom(s, b, l, f, from, fl);
511 	_thread_leave_cancellation_point();
512 	return (ret);
513 }
514 
515 __weak_reference(_recvmsg, recvmsg);
516 
517 ssize_t
518 _recvmsg(int s, struct msghdr *m, int f)
519 {
520 	ssize_t ret;
521 
522 	_thread_enter_cancellation_point();
523 	ret = __sys_recvmsg(s, m, f);
524 	_thread_leave_cancellation_point();
525 	return (ret);
526 }
527 
528 __weak_reference(_select, select);
529 
530 int
531 _select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
532 	struct timeval *timeout)
533 {
534 	int ret;
535 
536 	_thread_enter_cancellation_point();
537 	ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout);
538 	_thread_leave_cancellation_point();
539 
540 	return ret;
541 }
542 
543 /*
544  * Libc implements this by calling _sendto(), which is also a
545  * cancellation point.
546  */
547 #if 0
548 __weak_reference(_send, send);
549 
550 ssize_t
551 _send(int s, const void *m, size_t l, int f)
552 {
553 	ssize_t ret;
554 
555 	_thread_enter_cancellation_point();
556 	ret = _sendto(s, m, l, f, NULL, 0);
557 	_thread_leave_cancellation_point();
558 	return (ret);
559 }
560 #endif
561 
562 __weak_reference(_sendmsg, sendmsg);
563 
564 ssize_t
565 _sendmsg(int s, const struct msghdr *m, int f)
566 {
567 	ssize_t ret;
568 
569 	_thread_enter_cancellation_point();
570 	ret = __sys_sendmsg(s, m, f);
571 	_thread_leave_cancellation_point();
572 	return (ret);
573 }
574 
575 __weak_reference(_sendto, sendto);
576 
577 ssize_t
578 _sendto(int s, const void *m, size_t l, int f, const struct sockaddr *t,
579     socklen_t tl)
580 {
581 	ssize_t ret;
582 
583 	_thread_enter_cancellation_point();
584 	ret = __sys_sendto(s, m, l, f, t, tl);
585 	_thread_leave_cancellation_point();
586 	return (ret);
587 }
588 
589 /*
590  * The implementation in libc calls sigsuspend(), which is also
591  * a cancellation point.
592  */
593 #if 0
594 __weak_reference(_sigpause, sigpause);
595 
596 int
597 _sigpause(int m)
598 {
599 	int ret;
600 
601 	_thread_enter_cancellation_point();
602 	ret = __sys_sigpause(m);
603 	_thread_leave_cancellation_point();
604 	return (ret);
605 }
606 #endif
607 
608 __weak_reference(_sigsuspend, sigsuspend);
609 
610 int
611 _sigsuspend(const sigset_t *m)
612 {
613 	int ret;
614 
615 	_thread_enter_cancellation_point();
616 	ret = __sys_sigsuspend(m);
617 	_thread_leave_cancellation_point();
618 	return (ret);
619 }
620 
621 __weak_reference(_sigtimedwait, sigtimedwait);
622 
623 int
624 _sigtimedwait(const sigset_t *s, siginfo_t *i, const struct timespec *t)
625 {
626 	int ret;
627 
628 	_thread_enter_cancellation_point();
629 	ret = __sys_sigtimedwait(s, i, t);
630 	_thread_leave_cancellation_point();
631 	return (ret);
632 }
633 
634 __weak_reference(_sigwait, sigwait);
635 
636 int
637 _sigwait(const sigset_t *s, int *i)
638 {
639 	int ret;
640 
641 	_thread_enter_cancellation_point();
642 	ret = __sys_sigwait(s, i);
643 	_thread_leave_cancellation_point();
644 	return (ret);
645 }
646 
647 __weak_reference(_sigwaitinfo, sigwaitinfo);
648 
649 int
650 _sigwaitinfo(const sigset_t *s, siginfo_t *i)
651 {
652 	int ret;
653 
654 	_thread_enter_cancellation_point();
655 	ret = __sys_sigwaitinfo(s, i);
656 	_thread_leave_cancellation_point();
657 	return (ret);
658 }
659 
660 __weak_reference(_sleep, sleep);
661 
662 unsigned int
663 _sleep(unsigned int seconds)
664 {
665 	unsigned int	ret;
666 
667 	_thread_enter_cancellation_point();
668 	ret = __sleep(seconds);
669 	_thread_leave_cancellation_point();
670 
671 	return ret;
672 }
673 
674 __weak_reference(_system, system);
675 
676 int
677 _system(const char *string)
678 {
679 	int	ret;
680 
681 	_thread_enter_cancellation_point();
682 	ret = __system(string);
683 	_thread_leave_cancellation_point();
684 
685 	return ret;
686 }
687 
688 
689 __weak_reference(_tcdrain, tcdrain);
690 
691 int
692 _tcdrain(int fd)
693 {
694 	int	ret;
695 
696 	_thread_enter_cancellation_point();
697 	ret = __tcdrain(fd);
698 	_thread_leave_cancellation_point();
699 
700 	return ret;
701 }
702 
703 /*
704  * The usleep() implementation calls nanosleep(), which is also
705  * a cancellation point.
706  */
707 #if 0
708 __weak_reference(_usleep, usleep);
709 
710 int
711 _usleep(useconds_t u)
712 {
713 	int ret;
714 
715 	_thread_enter_cancellation_point();
716 	ret = __sys_usleep(u);
717 	_thread_leave_cancellation_point();
718 	return (ret);
719 }
720 #endif
721 
722 __weak_reference(_wait, wait);
723 
724 pid_t
725 _wait(int *istat)
726 {
727 	pid_t	ret;
728 
729 	_thread_enter_cancellation_point();
730 	ret = __wait(istat);
731 	_thread_leave_cancellation_point();
732 
733 	return ret;
734 }
735 
736 __weak_reference(_wait4, wait4);
737 
738 pid_t
739 _wait4(pid_t pid, int *istat, int options, struct rusage *rusage)
740 {
741 	pid_t ret;
742 
743 	_thread_enter_cancellation_point();
744 	ret = __sys_wait4(pid, istat, options, rusage);
745 	_thread_leave_cancellation_point();
746 
747 	return ret;
748 }
749 
750 /*
751  * The libc implementation of waitpid calls wait4().
752  */
753 #if 0
754 __weak_reference(_waitpid, waitpid);
755 
756 pid_t
757 _waitpid(pid_t wpid, int *status, int options)
758 {
759 	pid_t	ret;
760 
761 	_thread_enter_cancellation_point();
762 	ret = __waitpid(wpid, status, options);
763 	_thread_leave_cancellation_point();
764 
765 	return ret;
766 }
767 #endif
768 
769 __weak_reference(_write, write);
770 
771 ssize_t
772 _write(int fd, const void *buf, size_t nbytes)
773 {
774 	ssize_t	ret;
775 
776 	_thread_enter_cancellation_point();
777 	ret = __sys_write(fd, buf, nbytes);
778 	_thread_leave_cancellation_point();
779 
780 	return ret;
781 }
782 
783 __weak_reference(_writev, writev);
784 
785 ssize_t
786 _writev(int fd, const struct iovec *iov, int iovcnt)
787 {
788 	ssize_t ret;
789 
790 	_thread_enter_cancellation_point();
791 	ret = __sys_writev(fd, iov, iovcnt);
792 	_thread_leave_cancellation_point();
793 
794 	return ret;
795 }
796