diff options
Diffstat (limited to 'lib/libthr/thread/thr_syscalls.c')
-rw-r--r-- | lib/libthr/thread/thr_syscalls.c | 692 |
1 files changed, 692 insertions, 0 deletions
diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c new file mode 100644 index 000000000000..188374a30070 --- /dev/null +++ b/lib/libthr/thread/thr_syscalls.c @@ -0,0 +1,692 @@ +/* + * Copyright (c) 2014 The FreeBSD Foundation. + * Copyright (C) 2005 David Xu <davidxu@freebsd.org>. + * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>. + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * All rights reserved. + * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/exterrvar.h> +#include <sys/mman.h> +#include <sys/select.h> +#include <sys/signalvar.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <aio.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <poll.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "thr_private.h" + +static int +__thr_accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_accept(s, addr, addrlen); + _thr_cancel_leave(curthread, ret == -1); + + return (ret); +} + +/* + * Cancellation behavior: + * If thread is canceled, no socket is created. + */ +static int +__thr_accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_accept4(s, addr, addrlen, flags); + _thr_cancel_leave(curthread, ret == -1); + + return (ret); +} + +static int +__thr_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct + timespec *timeout) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_aio_suspend(iocbs, niocb, timeout); + _thr_cancel_leave(curthread, 1); + + return (ret); +} + +/* + * Cancellation behavior: + * According to manual of close(), the file descriptor is always deleted. + * Here, thread is only canceled after the system call, so the file + * descriptor is always deleted despite whether the thread is canceled + * or not. + */ +static int +__thr_close(int fd) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter2(curthread, 0); + ret = __sys_close(fd); + _thr_cancel_leave(curthread, 1); + + return (ret); +} + +/* + * Cancellation behavior: + * If the thread is canceled, connection is not made. + */ +static int +__thr_connect(int fd, const struct sockaddr *name, socklen_t namelen) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_connect(fd, name, namelen); + _thr_cancel_leave(curthread, ret == -1); + + return (ret); +} + +/* + * Cancellation behavior: + * According to specification, only F_SETLKW is a cancellation point. + * Thread is only canceled at start, or canceled if the system call + * is failure, this means the function does not generate side effect + * if it is canceled. + */ +static int +__thr_fcntl(int fd, int cmd, __intptr_t arg) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + if (cmd == F_OSETLKW || cmd == F_SETLKW) { + _thr_cancel_enter(curthread); + ret = __sys_fcntl(fd, cmd, arg); + _thr_cancel_leave(curthread, ret == -1); + } else { + ret = __sys_fcntl(fd, cmd, arg); + } + + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled after system call. + */ +static int +__thr_fsync(int fd) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter2(curthread, 0); + ret = __sys_fsync(fd); + _thr_cancel_leave(curthread, 1); + + return (ret); +} + +static int +__thr_fdatasync(int fd) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter2(curthread, 0); + ret = __sys_fdatasync(fd); + _thr_cancel_leave(curthread, 1); + + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled after system call. + */ +static int +__thr_msync(void *addr, size_t len, int flags) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter2(curthread, 0); + ret = __sys_msync(addr, len, flags); + _thr_cancel_leave(curthread, 1); + + return (ret); +} + +static int +__thr_clock_nanosleep(clockid_t clock_id, int flags, + const struct timespec *time_to_sleep, struct timespec *time_remaining) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_clock_nanosleep(clock_id, flags, time_to_sleep, + time_remaining); + _thr_cancel_leave(curthread, 1); + + return (ret); +} + +static int +__thr_nanosleep(const struct timespec *time_to_sleep, + struct timespec *time_remaining) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_nanosleep(time_to_sleep, time_remaining); + _thr_cancel_leave(curthread, 1); + + return (ret); +} + +/* + * Cancellation behavior: + * If the thread is canceled, file is not opened. + */ +static int +__thr_openat(int fd, const char *path, int flags, int mode) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_openat(fd, path, flags, mode); + _thr_cancel_leave(curthread, ret == -1); + + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call returns something, + * the thread is not canceled. + */ +static int +__thr_poll(struct pollfd *fds, unsigned int nfds, int timeout) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_poll(fds, nfds, timeout); + _thr_cancel_leave(curthread, ret == -1); + + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call returns something, + * the thread is not canceled. + */ +static int +__thr_ppoll(struct pollfd pfd[], nfds_t nfds, const struct timespec * + timeout, const sigset_t *newsigmask) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_ppoll(pfd, nfds, timeout, newsigmask); + _thr_cancel_leave(curthread, ret == -1); + + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call returns something, + * the thread is not canceled. + */ +static int +__thr_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds, + const struct timespec *timo, const sigset_t *mask) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_pselect(count, rfds, wfds, efds, timo, mask); + _thr_cancel_leave(curthread, ret == -1); + + return (ret); +} + +static int +__thr_kevent(int kq, const struct kevent *changelist, int nchanges, + struct kevent *eventlist, int nevents, const struct timespec *timeout) +{ + struct pthread *curthread; + int ret; + + if (nevents == 0) { + /* + * No blocking, do not make the call cancellable. + */ + return (__sys_kevent(kq, changelist, nchanges, eventlist, + nevents, timeout)); + } + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_kevent(kq, changelist, nchanges, eventlist, nevents, + timeout); + _thr_cancel_leave(curthread, ret == -1 && nchanges == 0); + + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call got some data, + * the thread is not canceled. + */ +static ssize_t +__thr_read(int fd, void *buf, size_t nbytes) +{ + struct pthread *curthread; + ssize_t ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_read(fd, buf, nbytes); + _thr_cancel_leave(curthread, ret == -1); + + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call got some data, + * the thread is not canceled. + */ +static ssize_t +__thr_readv(int fd, const struct iovec *iov, int iovcnt) +{ + struct pthread *curthread; + ssize_t ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_readv(fd, iov, iovcnt); + _thr_cancel_leave(curthread, ret == -1); + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call got some data, + * the thread is not canceled. + */ +static ssize_t +__thr_recvfrom(int s, void *b, size_t l, int f, struct sockaddr *from, + socklen_t *fl) +{ + struct pthread *curthread; + ssize_t ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_recvfrom(s, b, l, f, from, fl); + _thr_cancel_leave(curthread, ret == -1); + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call got some data, + * the thread is not canceled. + */ +static ssize_t +__thr_recvmsg(int s, struct msghdr *m, int f) +{ + struct pthread *curthread; + ssize_t ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_recvmsg(s, m, f); + _thr_cancel_leave(curthread, ret == -1); + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call returns something, + * the thread is not canceled. + */ +static int +__thr_select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *timeout) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout); + _thr_cancel_leave(curthread, ret == -1); + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call sent + * data, the thread is not canceled. + */ +static ssize_t +__thr_sendmsg(int s, const struct msghdr *m, int f) +{ + struct pthread *curthread; + ssize_t ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_sendmsg(s, m, f); + _thr_cancel_leave(curthread, ret <= 0); + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call sent some + * data, the thread is not canceled. + */ +static ssize_t +__thr_sendto(int s, const void *m, size_t l, int f, const struct sockaddr *t, + socklen_t tl) +{ + struct pthread *curthread; + ssize_t ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_sendto(s, m, l, f, t, tl); + _thr_cancel_leave(curthread, ret <= 0); + return (ret); +} + +static int +__thr_system(const char *string) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __libc_system(string); + _thr_cancel_leave(curthread, 1); + return (ret); +} + +/* + * Cancellation behavior: + * If thread is canceled, the system call is not completed, + * this means not all bytes were drained. + */ +static int +__thr_tcdrain(int fd) +{ + struct pthread *curthread; + int ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __libc_tcdrain(fd); + _thr_cancel_leave(curthread, ret == -1); + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call returns + * a child pid, the thread is not canceled. + */ +static pid_t +__thr_wait4(pid_t pid, int *status, int options, struct rusage *rusage) +{ + struct pthread *curthread; + pid_t ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_wait4(pid, status, options, rusage); + _thr_cancel_leave(curthread, ret <= 0); + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the system call returns + * a child pid, the thread is not canceled. + */ +static pid_t +__thr_wait6(idtype_t idtype, id_t id, int *status, int options, + struct __wrusage *ru, siginfo_t *infop) +{ + struct pthread *curthread; + pid_t ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_wait6(idtype, id, status, options, ru, infop); + _thr_cancel_leave(curthread, ret <= 0); + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the thread wrote some data, + * it is not canceled. + */ +static ssize_t +__thr_write(int fd, const void *buf, size_t nbytes) +{ + struct pthread *curthread; + ssize_t ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_write(fd, buf, nbytes); + _thr_cancel_leave(curthread, (ret <= 0)); + return (ret); +} + +/* + * Cancellation behavior: + * Thread may be canceled at start, but if the thread wrote some data, + * it is not canceled. + */ +static ssize_t +__thr_writev(int fd, const struct iovec *iov, int iovcnt) +{ + struct pthread *curthread; + ssize_t ret; + + curthread = _get_curthread(); + _thr_cancel_enter(curthread); + ret = __sys_writev(fd, iov, iovcnt); + _thr_cancel_leave(curthread, (ret <= 0)); + return (ret); +} + +static int +__thr_uexterr_gettext(char *buf, size_t bufsz) +{ + struct pthread *curthread; + + curthread = _get_curthread(); + return (__uexterr_format(&curthread->uexterr, buf, bufsz)); +} + +void +__thr_interpose_libc(void) +{ + + __set_error_selector(__error_threaded); +#define SLOT(name) \ + *(__libc_interposing_slot(INTERPOS_##name)) = \ + (interpos_func_t)__thr_##name; + SLOT(system); + SLOT(tcdrain); + SLOT(spinlock); + SLOT(spinunlock); + SLOT(map_stacks_exec); +#undef SLOT + +#define SLOT(name) \ + *(__libc_interposing_slot(INTERPOS_##name)) = \ + (interpos_func_t)__thr_##name; + SLOT(accept); + SLOT(accept4); + SLOT(aio_suspend); + SLOT(close); + SLOT(connect); + SLOT(fcntl); + SLOT(fsync); + SLOT(fork); + SLOT(msync); + SLOT(nanosleep); + SLOT(openat); + SLOT(poll); + SLOT(pselect); + SLOT(read); + SLOT(readv); + SLOT(recvfrom); + SLOT(recvmsg); + SLOT(select); + SLOT(sendmsg); + SLOT(sendto); + SLOT(setcontext); + SLOT(sigaction); + SLOT(sigprocmask); + SLOT(sigsuspend); + SLOT(sigwait); + SLOT(sigtimedwait); + SLOT(sigwaitinfo); + SLOT(swapcontext); + SLOT(wait4); + SLOT(write); + SLOT(writev); + SLOT(kevent); + SLOT(wait6); + SLOT(ppoll); + SLOT(fdatasync); + SLOT(clock_nanosleep); + SLOT(pdfork); + SLOT(uexterr_gettext); +#undef SLOT + *(__libc_interposing_slot( + INTERPOS__pthread_mutex_init_calloc_cb)) = + (interpos_func_t)_pthread_mutex_init_calloc_cb; +} |