From 4b88e6e858b55def2ef0392278ddf81835f2ac45 Mon Sep 17 00:00:00 2001 From: Salvatore Cro Date: Thu, 9 Sep 2010 16:01:04 +0200 Subject: libc: Fix cancellation handling in some C functions According to POSIX.1-2008 standard, the following syscalls shall be cancellation points : waitid, sleep, fdatasync, ppoll. Further, if generic syscall is not available and stubs are configured, provide the stub implementation for function. Signed-off-by: Salvatore Cro Signed-off-by: Carmelo Amoroso --- libc/sysdeps/linux/common/Makefile.in | 2 +- libc/sysdeps/linux/common/fdatasync.c | 35 ++++++++++++++++++++++++++++++++++- libc/sysdeps/linux/common/ppoll.c | 15 ++++++++++++++- libc/sysdeps/linux/common/waitid.c | 27 +++++++++++++++++++++++---- libc/unistd/sleep.c | 7 ++++++- 5 files changed, 78 insertions(+), 8 deletions(-) diff --git a/libc/sysdeps/linux/common/Makefile.in b/libc/sysdeps/linux/common/Makefile.in index 4f0a72c09..1711e8025 100644 --- a/libc/sysdeps/linux/common/Makefile.in +++ b/libc/sysdeps/linux/common/Makefile.in @@ -27,7 +27,7 @@ endif ifneq ($(UCLIBC_LINUX_SPECIFIC),y) # we need these internally: fstatfs.c statfs.c CSRC := $(filter-out capget.c capset.c inotify.c ioperm.c iopl.c madvise.c \ - modify_ldt.c personality.c prctl.c readahead.c reboot.c \ + modify_ldt.c personality.c ppoll.c prctl.c readahead.c reboot.c \ remap_file_pages.c sched_getaffinity.c sched_setaffinity.c \ sendfile64.c sendfile.c setfsgid.c setfsuid.c setresuid.c \ splice.c vmsplice.c tee.c signalfd.c swapoff.c swapon.c \ diff --git a/libc/sysdeps/linux/common/fdatasync.c b/libc/sysdeps/linux/common/fdatasync.c index a40f3e00c..19d37b6e0 100644 --- a/libc/sysdeps/linux/common/fdatasync.c +++ b/libc/sysdeps/linux/common/fdatasync.c @@ -14,4 +14,37 @@ # define __NR_fdatasync __NR_osf_fdatasync #endif -_syscall1(int, fdatasync, int, fd) +#ifdef __NR_fdatasync + +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# include +# else +# define SINGLE_THREAD_P 1 +# endif + +#define __NR___syscall_fdatasync __NR_fdatasync + +static __always_inline +_syscall1(int, __syscall_fdatasync, int, fd) + +int fdatasync(int fd) +{ + if (SINGLE_THREAD_P) + return __syscall_fdatasync(fd); + +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = __syscall_fdatasync(fd); + LIBC_CANCEL_RESET (oldtype); + return result; +# endif +} + +#elif defined __UCLIBC_HAS_STUBS__ +/* no syscall available, so provide a stub */ +int fdatasync(int fd) +{ + __set_errno(ENOSYS); + return -1; +} +#endif diff --git a/libc/sysdeps/linux/common/ppoll.c b/libc/sysdeps/linux/common/ppoll.c index 02c8013a5..09b2b1539 100644 --- a/libc/sysdeps/linux/common/ppoll.c +++ b/libc/sysdeps/linux/common/ppoll.c @@ -24,6 +24,12 @@ #include #if defined __NR_ppoll && defined __UCLIBC_LINUX_SPECIFIC__ +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# include +# else +# define SINGLE_THREAD_P 1 +# endif + int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask) @@ -35,8 +41,15 @@ ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, tval = *timeout; timeout = &tval; } + if (SINGLE_THREAD_P) + return INLINE_SYSCALL(ppoll, 5, fds, nfds, timeout, sigmask, _NSIG / 8); - return INLINE_SYSCALL(ppoll, 5, fds, nfds, timeout, sigmask, _NSIG / 8); +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = INLINE_SYSCALL(ppoll, 5, fds, nfds, timeout, sigmask, _NSIG / 8); + LIBC_CANCEL_RESET (oldtype); + return result; +# endif } libc_hidden_def(ppoll) #endif diff --git a/libc/sysdeps/linux/common/waitid.c b/libc/sysdeps/linux/common/waitid.c index af55c914a..c8115f9a5 100644 --- a/libc/sysdeps/linux/common/waitid.c +++ b/libc/sysdeps/linux/common/waitid.c @@ -14,20 +14,37 @@ # include # ifdef __NR_waitid + +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ +# include +# else +# define SINGLE_THREAD_P 1 +# endif + /* The waitid() POSIX interface takes 4 arguments, but the kernel function * actually takes 5. The fifth is a pointer to struct rusage. Make sure * we pass NULL rather than letting whatever was in the register bleed up. */ #define __NR_waitid5 __NR_waitid -static _syscall5(int, waitid5, idtype_t, idtype, id_t, id, siginfo_t*, infop, +static __always_inline +_syscall5(int, waitid5, idtype_t, idtype, id_t, id, siginfo_t*, infop, int, options, struct rusage*, ru) # endif int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) { # ifdef __NR_waitid - return waitid5(idtype, id, infop, options, NULL); -# else + if (SINGLE_THREAD_P) + return waitid5(idtype, id, infop, options, NULL); + +# ifdef __UCLIBC_HAS_THREADS_NATIVE__ + int oldtype = LIBC_CANCEL_ASYNC (); + int result = waitid5(idtype, id, infop, options, NULL); + LIBC_CANCEL_RESET (oldtype); + return result; +# endif + +# elif defined __NR_waitpid switch (idtype) { case P_PID: if (id <= 0) @@ -56,7 +73,9 @@ int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) if (infop->si_pid < 0) return infop->si_pid; return 0; +# else + __set_errno(ENOSYS); + return -1; # endif } - #endif diff --git a/libc/unistd/sleep.c b/libc/unistd/sleep.c index 0c0416e6d..b0031f022 100644 --- a/libc/unistd/sleep.c +++ b/libc/unistd/sleep.c @@ -54,7 +54,12 @@ unsigned int sleep (unsigned int seconds) /* This is not necessary but some buggy programs depend on this. */ if (seconds == 0) - return 0; + { +# ifdef CANCELLATION_P + CANCELLATION_P (THREAD_SELF); +# endif + return 0; + } /* Linux will wake up the system call, nanosleep, when SIGCHLD arrives even if SIGCHLD is ignored. We have to deal with it -- cgit v1.2.3