int sync_file_range (int fd, __off64_t from, __off64_t to, unsigned int flags) { if (SINGLE_THREAD_P) return INLINE_SYSCALL (sync_file_range2, 4, fd, flags, from, to); int result; int oldtype = LIBC_CANCEL_ASYNC (); result = INLINE_SYSCALL (sync_file_range2, 4, fd, flags, from, to); LIBC_CANCEL_RESET (oldtype); return result; }
/* Send N bytes of BUF to socket FD. Returns the number sent or -1. */ ssize_t __libc_send (int fd, const void *buf, size_t n, int flags) { if (SINGLE_THREAD_P) return INLINE_SYSCALL (sendto, 6, fd, buf, n, flags, NULL, (size_t) 0); int oldtype = LIBC_CANCEL_ASYNC (); ssize_t result = INLINE_SYSCALL (sendto, 6, fd, buf, n, flags, NULL, (size_t) 0); LIBC_CANCEL_RESET (oldtype); return result; }
int accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags) { if (SINGLE_THREAD_P) return INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len, flags); int oldtype = LIBC_CANCEL_ASYNC (); int result = INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len, flags); LIBC_CANCEL_RESET (oldtype); return result; }
/* Wait for pending output to be written on FD. */ int __libc_tcdrain (int fd) { if (SINGLE_THREAD_P) /* With an argument of 1, TCSBRK for output to be drain. */ return INLINE_SYSCALL (ioctl, 3, fd, TCSBRK, 1); int oldtype = LIBC_CANCEL_ASYNC (); /* With an argument of 1, TCSBRK for output to be drain. */ int result = INLINE_SYSCALL (ioctl, 3, fd, TCSBRK, 1); LIBC_CANCEL_RESET (oldtype); return result; }
/* Wait for a child to die. When one does, put its status in *STAT_LOC and return its process ID. For errors, return (pid_t) -1. */ pid_t __libc_wait (__WAIT_STATUS_DEFN stat_loc) { if (SINGLE_THREAD_P) return INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0, (struct rusage *) NULL); int oldtype = LIBC_CANCEL_ASYNC (); pid_t result = INLINE_SYSCALL (wait4, 4, WAIT_ANY, stat_loc, 0, (struct rusage *) NULL); LIBC_CANCEL_RESET (oldtype); return result; }
/* Return any pending signal or wait for one for the given time. */ int attribute_hidden __sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout) { if(SINGLE_THREAD_P) return do_sigtimedwait(set, info, timeout); int oldtype = LIBC_CANCEL_ASYNC(); /* XXX The size argument hopefully will have to be changed to the real size of the user-level sigset_t. */ int result = do_sigtimedwait(set, info, timeout); LIBC_CANCEL_RESET(oldtype); return result; }
int epoll_pwait (int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *set) { if (SINGLE_THREAD_P) return INLINE_SYSCALL (epoll_pwait, 6, epfd, events, maxevents, timeout, set, _NSIG / 8); int oldtype = LIBC_CANCEL_ASYNC (); int result = INLINE_SYSCALL (epoll_pwait, 6, epfd, events, maxevents, timeout, set, _NSIG / 8); LIBC_CANCEL_RESET (oldtype); return result; }
/* We have to provide a default version of this function since the standards demand it. The version which is a bit more reasonable is the BSD version. So make this the default. */ int sigpause (int mask) { #ifdef __UCLIBC_HAS_THREADS_NATIVE__ if (SINGLE_THREAD_P) return __sigpause (mask, 0); int oldtype = LIBC_CANCEL_ASYNC (); int result = __sigpause (mask, 0); LIBC_CANCEL_RESET (oldtype); return result; #else return __sigpause (mask, 0); #endif }
ssize_t __libc_send (int sockfd, const void *buffer, size_t len, int flags) { ssize_t result; if (SINGLE_THREAD_P) result = INLINE_SYSCALL (sendto, 6, sockfd, buffer, len, flags, NULL, 0); else { int oldtype = LIBC_CANCEL_ASYNC (); result = INLINE_SYSCALL (sendto, 6, sockfd, buffer, len, flags, NULL, 0); LIBC_CANCEL_RESET (oldtype); } return result; }
int fcntl64(int fd, int cmd, ...) { long arg; va_list list; va_start(list, cmd); arg = va_arg(list, long); va_end(list); if (SINGLE_THREAD_P || (cmd != F_SETLKW64)) return __NC(fcntl64)(fd, cmd, arg); # ifdef __NEW_THREADS int oldtype = LIBC_CANCEL_ASYNC(); int result = __NC(fcntl64)(fd, cmd, arg); LIBC_CANCEL_RESET(oldtype); return result; # endif }
int __libc_accept(int s, struct sockaddr *addr, socklen_t * addrlen) { unsigned long args[3]; args[0] = s; args[1] = (unsigned long) addr; args[2] = (unsigned long) addrlen; if (SINGLE_THREAD_P) return __socketcall(SYS_ACCEPT, args); #ifdef __UCLIBC_HAS_THREADS_NATIVE__ int oldtype = LIBC_CANCEL_ASYNC (); int result = __socketcall(SYS_ACCEPT, args); LIBC_CANCEL_RESET (oldtype); return result; #endif }
ssize_t __libc_sendmsg(int sockfd, const struct msghdr *msg, int flags) { unsigned long args[3]; args[0] = sockfd; args[1] = (unsigned long) msg; args[2] = flags; if (SINGLE_THREAD_P) return (__socketcall(SYS_SENDMSG, args)); #ifdef __UCLIBC_HAS_THREADS_NATIVE__ int oldtype = LIBC_CANCEL_ASYNC (); int result = __socketcall(SYS_SENDMSG, args); LIBC_CANCEL_RESET (oldtype); return result; #endif }
int __libc_connect(int sockfd, const struct sockaddr *saddr, socklen_t addrlen) { unsigned long args[3]; args[0] = sockfd; args[1] = (unsigned long) saddr; args[2] = addrlen; if (SINGLE_THREAD_P) return __socketcall(SYS_CONNECT, args); #ifdef __UCLIBC_HAS_THREADS_NATIVE__ int oldtype = LIBC_CANCEL_ASYNC (); int result = __socketcall(SYS_CONNECT, args); LIBC_CANCEL_RESET (oldtype); return result; #endif }
int __libc_system (const char *line) { if (line == NULL) /* Check that we have a command processor available. It might not be available after a chroot(), for example. */ return do_system ("exit 0") == 0; if (SINGLE_THREAD_P) return do_system (line); int oldtype = LIBC_CANCEL_ASYNC (); int result = do_system (line); LIBC_CANCEL_RESET (oldtype); return result; }
int accept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags) { unsigned long args[4]; args[0] = fd; args[1] = (unsigned long) addr; args[2] = (unsigned long) addrlen; args[3] = flags; if (SINGLE_THREAD_P) return __socketcall(SYS_ACCEPT4, args); #ifdef __UCLIBC_HAS_THREADS_NATIVE__ else { int oldtype = LIBC_CANCEL_ASYNC (); int result = __socketcall(SYS_ACCEPT4, args); LIBC_CANCEL_RESET (oldtype); return result; } #endif }
/* send, sendto added by [email protected] */ ssize_t __libc_send(int sockfd, const void *buffer, size_t len, int flags) { unsigned long args[4]; args[0] = sockfd; args[1] = (unsigned long) buffer; args[2] = len; args[3] = flags; if (SINGLE_THREAD_P) return (__socketcall(SYS_SEND, args)); #ifdef __UCLIBC_HAS_THREADS_NATIVE__ int oldtype = LIBC_CANCEL_ASYNC (); int result = __socketcall(SYS_SEND, args); LIBC_CANCEL_RESET (oldtype); return result; #endif }
/* Helper function to support starting threads for SIGEV_THREAD. */ static void * timer_helper_thread (void *arg) { /* Wait for the SIGTIMER signal and none else. */ sigset_t ss; sigemptyset (&ss); sigaddset (&ss, SIGTIMER); /* Endless loop of waiting for signals. The loop is only ended when the thread is canceled. */ while (1) { siginfo_t si; /* sigwaitinfo cannot be used here, since it deletes SIGCANCEL == SIGTIMER from the set. */ int oldtype = LIBC_CANCEL_ASYNC (); /* XXX The size argument hopefully will have to be changed to the real size of the user-level sigset_t. */ int result = INLINE_SYSCALL (rt_sigtimedwait, 4, &ss, &si, NULL, _NSIG / 8); LIBC_CANCEL_RESET (oldtype); if (result > 0) { if (si.si_code == SI_TIMER) { struct timer *tk = (struct timer *) si.si_ptr; /* That the signal we are waiting for. */ pthread_t th; (void) pthread_create (&th, &tk->attr, timer_sigev_thread, tk); } else if (si.si_code == SI_TKILL) /* The thread is canceled. */ pthread_exit (NULL); } } }
int __libc_fcntl (int fd, int cmd, ...) { va_list ap; void *arg; va_start (ap, cmd); arg = va_arg (ap, void *); va_end (ap); #ifdef __UCLIBC_HAS_THREADS_NATIVE__ if (SINGLE_THREAD_P || (cmd != F_SETLKW && cmd != F_SETLKW64)) # if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); # else return __syscall_fcntl(fd, cmd, arg); # endif int oldtype = LIBC_CANCEL_ASYNC (); # if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 int result = INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); # else int result = __syscall_fcntl(fd, cmd, arg); # endif LIBC_CANCEL_RESET (oldtype); return result; #else # if __WORDSIZE == 32 if (cmd == F_GETLK64 || cmd == F_SETLK64 || cmd == F_SETLKW64) { # if defined __UCLIBC_HAS_LFS__ && defined __NR_fcntl64 return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); # else __set_errno(ENOSYS); return -1; # endif } # endif return __syscall_fcntl(fd, cmd, arg); #endif }
int ioctl(int fd, unsigned long int request, ...) { void *arg; va_list list; va_start(list, request); arg = va_arg(list, void *); va_end(list); if (SINGLE_THREAD_P) return __syscall_ioctl(fd, request, arg); #ifdef __UCLIBC_HAS_THREADS_NATIVE__ int oldtype = LIBC_CANCEL_ASYNC (); int result = __syscall_ioctl(fd, request, arg); LIBC_CANCEL_RESET (oldtype); return result; #endif }
/* Reserve storage for the data of the file associated with FD. */ int fallocate (int fd, int mode, __off_t offset, __off_t len) { #ifdef __NR_fallocate if (SINGLE_THREAD_P) return INLINE_SYSCALL (fallocate, 4, fd, mode, offset, len); int result; int oldtype = LIBC_CANCEL_ASYNC (); result = INLINE_SYSCALL (fallocate, 4, fd, mode, offset, len); LIBC_CANCEL_RESET (oldtype); return result; #else __set_errno (ENOSYS); return -1; #endif }
int open(const char *file, int oflag, ...) { mode_t mode = 0; if (oflag & O_CREAT) { va_list arg; va_start(arg, oflag); mode = va_arg(arg, mode_t); va_end(arg); } if (SINGLE_THREAD_P) return __NC(open)(file, oflag, mode); #ifdef __NEW_THREADS int oldtype = LIBC_CANCEL_ASYNC (); int result = __NC(open)(file, oflag, mode); LIBC_CANCEL_RESET (oldtype); return result; #endif }
int __libc_fcntl (int fd, int cmd, ...) { va_list ap; void *arg; va_start (ap, cmd); arg = va_arg (ap, void *); va_end (ap); if (SINGLE_THREAD_P || (cmd != F_SETLKW && cmd != F_SETLKW64)) return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); int oldtype = LIBC_CANCEL_ASYNC (); int result = INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg); LIBC_CANCEL_RESET (oldtype); return result; }
int __libc_fcntl (int fd, int cmd, ...) { va_list ap; void *arg; va_start (ap, cmd); arg = va_arg (ap, void *); va_end (ap); if (SINGLE_THREAD_P || cmd != F_SETLKW) return do_fcntl (fd, cmd, arg); int oldtype = LIBC_CANCEL_ASYNC (); int result = do_fcntl (fd, cmd, arg); LIBC_CANCEL_RESET (oldtype); return result; }
int __libc_connect (int fd, __CONST_SOCKADDR_ARG addr, socklen_t addrlen) { socklen_t new_addrlen; new_addrlen = __libc_sa_len ((addr.__sockaddr__)->sa_family); /* Only allow a smaller size, otherwise it could lead to stack corruption */ if ((new_addrlen != 0) && (new_addrlen < addrlen)) addrlen = new_addrlen; /* We pass 3 arguments. */ if (SINGLE_THREAD_P) return INLINE_SYSCALL (connect, 3, fd, addr.__sockaddr__, addrlen); int oldtype = LIBC_CANCEL_ASYNC (); int result = INLINE_SYSCALL (connect, 3, fd, addr.__sockaddr__, addrlen); LIBC_CANCEL_RESET (oldtype); return result; }
int __select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int result; struct timespec ts, *tsp = NULL; if (timeout) { TIMEVAL_TO_TIMESPEC (timeout, &ts); tsp = &ts; } if (SINGLE_THREAD_P) { result = INLINE_SYSCALL (pselect6, 6, nfds, readfds, writefds, exceptfds, tsp, NULL); } else { int oldtype = LIBC_CANCEL_ASYNC (); result = INLINE_SYSCALL (pselect6, 6, nfds, readfds, writefds, exceptfds, tsp, NULL); LIBC_CANCEL_RESET (oldtype); } if (timeout) { /* Linux by default will update the timeout after a pselect6 syscall (though the pselect() glibc call suppresses this behavior). Since select() on Linux has the same behavior as the pselect6 syscall, we update the timeout here. */ TIMESPEC_TO_TIMEVAL (timeout, &ts); } return result; }
/* recv, recvfrom added by [email protected] */ ssize_t __libc_recvfrom(int sockfd, __ptr_t buffer, size_t len, int flags, struct sockaddr *to, socklen_t * tolen) { unsigned long args[6]; args[0] = sockfd; args[1] = (unsigned long) buffer; args[2] = len; args[3] = flags; args[4] = (unsigned long) to; args[5] = (unsigned long) tolen; if (SINGLE_THREAD_P) return (__socketcall(SYS_RECVFROM, args)); #ifdef __UCLIBC_HAS_THREADS_NATIVE__ int oldtype = LIBC_CANCEL_ASYNC (); int result = __socketcall(SYS_RECVFROM, args); LIBC_CANCEL_RESET (oldtype); return result; #endif }
ssize_t __libc_msgrcv (int msqid, void *msgp, size_t msgsz, long int msgtyp, int msgflg) { /* The problem here is that Linux' calling convention only allows up to fives parameters to a system call. */ struct ipc_kludge tmp; tmp.msgp = msgp; tmp.msgtyp = msgtyp; if (SINGLE_THREAD_P) return INLINE_SYSCALL (ipc, 5, IPCOP_msgrcv, msqid, msgsz, msgflg, &tmp); int oldtype = LIBC_CANCEL_ASYNC (); ssize_t result = INLINE_SYSCALL (ipc, 5, IPCOP_msgrcv, msqid, msgsz, msgflg, &tmp); LIBC_CANCEL_RESET (oldtype); return result; }
int __poll (struct pollfd *fds, nfds_t nfds, int timeout) { struct timespec timeout_ts; struct timespec *timeout_ts_p = NULL; if (timeout >= 0) { timeout_ts.tv_sec = timeout / 1000; timeout_ts.tv_nsec = (timeout % 1000) * 1000000; timeout_ts_p = &timeout_ts; } if (SINGLE_THREAD_P) return INLINE_SYSCALL (ppoll, 5, fds, nfds, timeout_ts_p, NULL, 0); int oldtype = LIBC_CANCEL_ASYNC (); int result = INLINE_SYSCALL (ppoll, 5, fds, nfds, timeout_ts_p, NULL, 0); LIBC_CANCEL_RESET (oldtype); return result; }
/* Helper function to support starting threads for SIGEV_THREAD. */ static void * timer_helper_thread (void *arg) { /* Wait for the SIGTIMER signal, allowing the setXid signal, and none else. */ sigset_t ss; sigemptyset (&ss); __sigaddset (&ss, SIGTIMER); syscall (SYS_thr_self, &__helper_tid); sem_post (&__helper_tid_semaphore); /* Endless loop of waiting for signals. The loop is only ended when the thread is canceled. */ while (1) { siginfo_t si; /* sigwaitinfo cannot be used here, since it deletes SIGCANCEL == SIGTIMER from the set. */ int oldtype = LIBC_CANCEL_ASYNC (); /* XXX The size argument hopefully will have to be changed to the real size of the user-level sigset_t. */ int result = sigtimedwait (&ss, &si, NULL); LIBC_CANCEL_RESET (oldtype); if (result > 0) { if (si.si_code == SI_TIMER) { struct timer *tk = (struct timer *) si.si_value.sival_ptr; /* Check the timer is still used and will not go away while we are reading the values here. */ pthread_mutex_lock (&__active_timer_sigev_thread_lock); struct timer *runp = __active_timer_sigev_thread; while (runp != NULL) if (runp == tk) break; else runp = runp->next; if (runp != NULL) { struct thread_start_data *td = malloc (sizeof (*td)); /* There is not much we can do if the allocation fails. */ if (td != NULL) { /* This is the signal we are waiting for. */ td->thrfunc = tk->thrfunc; td->sival = tk->sival; pthread_t th; (void) pthread_create (&th, &tk->attr, timer_sigev_thread, td); } } pthread_mutex_unlock (&__active_timer_sigev_thread_lock); } else if (si.si_code == SI_LWP /* Backward compatibility (see rev 211732 in -CURRENT). */ || si.si_code == SI_USER) /* The thread is canceled. */ pthread_exit (NULL); } } }
/* Spawn a new process executing PATH with the attributes describes in *ATTRP. Before running the process perform the actions described in FILE-ACTIONS. */ static int __spawnix (pid_t * pid, const char *file, const posix_spawn_file_actions_t * file_actions, const posix_spawnattr_t * attrp, char *const argv[], char *const envp[], int xflags, int (*exec) (const char *, char *const *, char *const *)) { pid_t new_pid; struct posix_spawn_args args; int ec; if (__pipe2 (args.pipe, O_CLOEXEC)) return errno; /* To avoid imposing hard limits on posix_spawn{p} the total number of arguments is first calculated to allocate a mmap to hold all possible values. */ ptrdiff_t argc = 0; /* Linux allows at most max (0x7FFFFFFF, 1/4 stack size) arguments to be used in a execve call. We limit to INT_MAX minus one due the compatiblity code that may execute a shell script (maybe_script_execute) where it will construct another argument list with an additional argument. */ ptrdiff_t limit = INT_MAX - 1; while (argv[argc++] != NULL) if (argc == limit) { errno = E2BIG; return errno; } int prot = (PROT_READ | PROT_WRITE | ((GL (dl_stack_flags) & PF_X) ? PROT_EXEC : 0)); /* Add a slack area for child's stack. */ size_t argv_size = (argc * sizeof (void *)) + 512; size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize)); void *stack = __mmap (NULL, stack_size, prot, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); if (__glibc_unlikely (stack == MAP_FAILED)) { close_not_cancel (args.pipe[0]); close_not_cancel (args.pipe[1]); return errno; } /* Disable asynchronous cancellation. */ int cs = LIBC_CANCEL_ASYNC (); args.file = file; args.exec = exec; args.fa = file_actions; args.attr = attrp ? attrp : &(const posix_spawnattr_t) { 0 }; args.argv = argv; args.argc = argc; args.envp = envp; args.xflags = xflags; __sigprocmask (SIG_BLOCK, &SIGALL_SET, &args.oldmask); /* The clone flags used will create a new child that will run in the same memory space (CLONE_VM) and the execution of calling thread will be suspend until the child calls execve or _exit. These condition as signal below either by pipe write (_exit with SPAWN_ERROR) or a successful execve. Also since the calling thread execution will be suspend, there is not need for CLONE_SETTLS. Although parent and child share the same TLS namespace, there will be no concurrent access for TLS variables (errno for instance). */ new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size, CLONE_VM | CLONE_VFORK | SIGCHLD, &args); close_not_cancel (args.pipe[1]); if (new_pid > 0) { if (__read (args.pipe[0], &ec, sizeof ec) != sizeof ec) ec = 0; else __waitpid (new_pid, NULL, 0); } else ec = -new_pid; __munmap (stack, stack_size); close_not_cancel (args.pipe[0]); if (!ec && new_pid) *pid = new_pid; __sigprocmask (SIG_SETMASK, &args.oldmask, 0); LIBC_CANCEL_RESET (cs); return ec; } /* Spawn a new process executing PATH with the attributes describes in *ATTRP. Before running the process perform the actions described in FILE-ACTIONS. */ int __spawni (pid_t * pid, const char *file, const posix_spawn_file_actions_t * acts, const posix_spawnattr_t * attrp, char *const argv[], char *const envp[], int xflags) { return __spawnix (pid, file, acts, attrp, argv, envp, xflags, xflags & SPAWN_XFLAGS_USE_PATH ? __execvpe : __execve); }