summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/complex/cacosh.c2
-rw-r--r--src/complex/catan.c25
-rw-r--r--src/complex/catanf.c28
-rw-r--r--src/complex/catanl.c24
-rw-r--r--src/conf/sysconf.c9
-rw-r--r--src/dirent/posix_getdents.c11
-rw-r--r--src/errno/__strerror.h2
-rw-r--r--src/exit/atexit.c12
-rw-r--r--src/exit/exit.c14
-rw-r--r--src/fenv/loongarch64/fenv.S78
-rw-r--r--src/fenv/riscv32/fenv-sf.c3
-rw-r--r--src/fenv/riscv32/fenv.S56
-rw-r--r--src/internal/atomic.h2
-rw-r--r--src/internal/dynlink.h4
-rw-r--r--src/internal/emulate_wait4.c55
-rw-r--r--src/internal/fork_impl.h2
-rw-r--r--src/internal/syscall.h23
-rw-r--r--src/ldso/loongarch64/dlsym.s7
-rw-r--r--src/ldso/loongarch64/tlsdesc.s37
-rw-r--r--src/ldso/riscv32/dlsym.s6
-rw-r--r--src/ldso/riscv64/tlsdesc.s32
-rw-r--r--src/ldso/sh/dlsym.s2
-rw-r--r--src/legacy/getusershell.c6
-rw-r--r--src/linux/cache.c3
-rw-r--r--src/linux/clone.c56
-rw-r--r--src/linux/preadv2.c17
-rw-r--r--src/linux/pwritev2.c17
-rw-r--r--src/linux/renameat2.c11
-rw-r--r--src/linux/statx.c44
-rw-r--r--src/linux/wait4.c2
-rw-r--r--src/locale/bind_textdomain_codeset.c6
-rw-r--r--src/locale/codepages.h11
-rw-r--r--src/locale/iconv.c17
-rw-r--r--src/math/acoshl.c10
-rw-r--r--src/math/fma.c2
-rw-r--r--src/math/powl.c42
-rw-r--r--src/math/riscv32/copysign.c15
-rw-r--r--src/math/riscv32/copysignf.c15
-rw-r--r--src/math/riscv32/fabs.c15
-rw-r--r--src/math/riscv32/fabsf.c15
-rw-r--r--src/math/riscv32/fma.c15
-rw-r--r--src/math/riscv32/fmaf.c15
-rw-r--r--src/math/riscv32/fmax.c15
-rw-r--r--src/math/riscv32/fmaxf.c15
-rw-r--r--src/math/riscv32/fmin.c15
-rw-r--r--src/math/riscv32/fminf.c15
-rw-r--r--src/math/riscv32/sqrt.c15
-rw-r--r--src/math/riscv32/sqrtf.c15
-rw-r--r--src/math/sqrtl.c4
-rw-r--r--src/misc/initgroups.c26
-rw-r--r--src/misc/mntent.c56
-rw-r--r--src/misc/syslog.c3
-rw-r--r--src/mq/x32/mq_open.c22
-rw-r--r--src/mq/x32/mq_setattr.c14
-rw-r--r--src/multibyte/mbrtowc.c2
-rw-r--r--src/multibyte/mbsnrtowcs.c6
-rw-r--r--src/network/dns_parse.c5
-rw-r--r--src/network/getnameinfo.c4
-rw-r--r--src/network/inet_ntop.c7
-rw-r--r--src/network/lookup_name.c2
-rw-r--r--src/network/res_msend.c2
-rw-r--r--src/process/_Fork.c28
-rw-r--r--src/process/posix_spawn.c7
-rw-r--r--src/process/waitpid.c2
-rw-r--r--src/regex/glob.c2
-rw-r--r--src/select/ppoll.c (renamed from src/linux/ppoll.c)2
-rw-r--r--src/setjmp/loongarch64/longjmp.S32
-rw-r--r--src/setjmp/loongarch64/setjmp.S34
-rw-r--r--src/setjmp/riscv32/longjmp.S42
-rw-r--r--src/setjmp/riscv32/setjmp.S41
-rw-r--r--src/signal/loongarch64/restore.s10
-rw-r--r--src/signal/loongarch64/sigsetjmp.s25
-rw-r--r--src/signal/riscv32/restore.s10
-rw-r--r--src/signal/riscv32/sigsetjmp.s23
-rw-r--r--src/signal/riscv64/restore.s2
-rw-r--r--src/signal/sh/sigsetjmp.s2
-rw-r--r--src/signal/sigaltstack.c4
-rw-r--r--src/signal/siglongjmp.c5
-rw-r--r--src/signal/sigpause.c2
-rw-r--r--src/stat/fchmodat.c7
-rw-r--r--src/stat/fstatat.c1
-rw-r--r--src/stat/statvfs.c1
-rw-r--r--src/stdio/__stdio_write.c5
-rw-r--r--src/stdio/pclose.c2
-rw-r--r--src/stdio/vfprintf.c40
-rw-r--r--src/stdio/vfwprintf.c4
-rw-r--r--src/stdio/vsnprintf.c5
-rw-r--r--src/stdio/vswprintf.c3
-rw-r--r--src/stdlib/qsort.c2
-rw-r--r--src/string/strcasestr.c1
-rw-r--r--src/termios/cfgetospeed.c2
-rw-r--r--src/termios/cfsetospeed.c10
-rw-r--r--src/termios/cfsetspeed.c11
-rw-r--r--src/thread/aarch64/clone.s3
-rw-r--r--src/thread/arm/clone.s3
-rw-r--r--src/thread/loongarch64/__set_thread_area.s7
-rw-r--r--src/thread/loongarch64/__unmapself.s7
-rw-r--r--src/thread/loongarch64/clone.s30
-rw-r--r--src/thread/loongarch64/syscall_cp.s29
-rw-r--r--src/thread/m68k/clone.s3
-rw-r--r--src/thread/microblaze/clone.s3
-rw-r--r--src/thread/mips/clone.s3
-rw-r--r--src/thread/mips64/clone.s3
-rw-r--r--src/thread/mipsn32/clone.s3
-rw-r--r--src/thread/or1k/clone.s5
-rw-r--r--src/thread/riscv32/__set_thread_area.s6
-rw-r--r--src/thread/riscv32/__unmapself.s7
-rw-r--r--src/thread/riscv32/clone.s35
-rw-r--r--src/thread/riscv32/syscall_cp.s29
-rw-r--r--src/thread/riscv64/clone.s1
-rw-r--r--src/thread/s390x/__tls_get_offset.s20
-rw-r--r--src/thread/sem_post.c2
-rw-r--r--src/thread/synccall.c8
-rw-r--r--src/time/__tz.c1
-rw-r--r--src/time/__utc.c3
-rw-r--r--src/time/__year_to_secs.c4
-rw-r--r--src/time/strftime.c8
-rw-r--r--src/time/strptime.c66
-rw-r--r--src/time/timer_create.c31
-rw-r--r--src/unistd/faccessat.c2
-rw-r--r--src/unistd/isatty.c6
-rw-r--r--src/unistd/pause.c6
-rw-r--r--src/unistd/pwrite.c11
-rw-r--r--src/unistd/pwritev.c10
-rw-r--r--src/unistd/setxid.c2
125 files changed, 1492 insertions, 243 deletions
diff --git a/src/complex/cacosh.c b/src/complex/cacosh.c
index 76127f75..55b857ce 100644
--- a/src/complex/cacosh.c
+++ b/src/complex/cacosh.c
@@ -1,6 +1,6 @@
#include "complex_impl.h"
-/* acosh(z) = i acos(z) */
+/* acosh(z) = ±i acos(z) */
double complex cacosh(double complex z)
{
diff --git a/src/complex/catan.c b/src/complex/catan.c
index ccc2fb53..b4fe552a 100644
--- a/src/complex/catan.c
+++ b/src/complex/catan.c
@@ -60,29 +60,6 @@
#include "complex_impl.h"
-#define MAXNUM 1.0e308
-
-static const double DP1 = 3.14159265160560607910E0;
-static const double DP2 = 1.98418714791870343106E-9;
-static const double DP3 = 1.14423774522196636802E-17;
-
-static double _redupi(double x)
-{
- double t;
- long i;
-
- t = x/M_PI;
- if (t >= 0.0)
- t += 0.5;
- else
- t -= 0.5;
-
- i = t; /* the multiple */
- t = i;
- t = ((x - t * DP1) - t * DP2) - t * DP3;
- return t;
-}
-
double complex catan(double complex z)
{
double complex w;
@@ -95,7 +72,7 @@ double complex catan(double complex z)
a = 1.0 - x2 - (y * y);
t = 0.5 * atan2(2.0 * x, a);
- w = _redupi(t);
+ w = t;
t = y - 1.0;
a = x2 + (t * t);
diff --git a/src/complex/catanf.c b/src/complex/catanf.c
index 1d569f2d..faaa907a 100644
--- a/src/complex/catanf.c
+++ b/src/complex/catanf.c
@@ -55,32 +55,6 @@
#include "complex_impl.h"
-#define MAXNUMF 1.0e38F
-
-static const double DP1 = 3.140625;
-static const double DP2 = 9.67502593994140625E-4;
-static const double DP3 = 1.509957990978376432E-7;
-
-static const float float_pi = M_PI;
-
-static float _redupif(float xx)
-{
- float x, t;
- long i;
-
- x = xx;
- t = x/float_pi;
- if (t >= 0.0f)
- t += 0.5f;
- else
- t -= 0.5f;
-
- i = t; /* the multiple */
- t = i;
- t = ((x - t * DP1) - t * DP2) - t * DP3;
- return t;
-}
-
float complex catanf(float complex z)
{
float complex w;
@@ -93,7 +67,7 @@ float complex catanf(float complex z)
a = 1.0f - x2 - (y * y);
t = 0.5f * atan2f(2.0f * x, a);
- w = _redupif(t);
+ w = t;
t = y - 1.0f;
a = x2 + (t * t);
diff --git a/src/complex/catanl.c b/src/complex/catanl.c
index e62526c0..cd2d2b00 100644
--- a/src/complex/catanl.c
+++ b/src/complex/catanl.c
@@ -67,28 +67,6 @@ long double complex catanl(long double complex z)
return catan(z);
}
#else
-static const long double PIL = 3.141592653589793238462643383279502884197169L;
-static const long double DP1 = 3.14159265358979323829596852490908531763125L;
-static const long double DP2 = 1.6667485837041756656403424829301998703007e-19L;
-static const long double DP3 = 1.8830410776607851167459095484560349402753e-39L;
-
-static long double redupil(long double x)
-{
- long double t;
- long i;
-
- t = x / PIL;
- if (t >= 0.0L)
- t += 0.5L;
- else
- t -= 0.5L;
-
- i = t; /* the multiple */
- t = i;
- t = ((x - t * DP1) - t * DP2) - t * DP3;
- return t;
-}
-
long double complex catanl(long double complex z)
{
long double complex w;
@@ -101,7 +79,7 @@ long double complex catanl(long double complex z)
a = 1.0L - x2 - (y * y);
t = atan2l(2.0L * x, a) * 0.5L;
- w = redupil(t);
+ w = t;
t = y - 1.0L;
a = x2 + (t * t);
diff --git a/src/conf/sysconf.c b/src/conf/sysconf.c
index 60d3e745..8dd5c725 100644
--- a/src/conf/sysconf.c
+++ b/src/conf/sysconf.c
@@ -220,8 +220,13 @@ long sysconf(int name)
return (mem > LONG_MAX) ? LONG_MAX : mem;
case JT_MINSIGSTKSZ & 255:
case JT_SIGSTKSZ & 255: ;
- long val = __getauxval(AT_MINSIGSTKSZ);
- if (val < MINSIGSTKSZ) val = MINSIGSTKSZ;
+ /* Value from auxv/kernel is only sigfame size. Clamp it
+ * to at least 1k below arch's traditional MINSIGSTKSZ,
+ * then add 1k of working space for signal handler. */
+ unsigned long sigframe_sz = __getauxval(AT_MINSIGSTKSZ);
+ if (sigframe_sz < MINSIGSTKSZ - 1024)
+ sigframe_sz = MINSIGSTKSZ - 1024;
+ unsigned val = sigframe_sz + 1024;
if (values[name] == JT_SIGSTKSZ)
val += SIGSTKSZ - MINSIGSTKSZ;
return val;
diff --git a/src/dirent/posix_getdents.c b/src/dirent/posix_getdents.c
new file mode 100644
index 00000000..26c16ac6
--- /dev/null
+++ b/src/dirent/posix_getdents.c
@@ -0,0 +1,11 @@
+#include <dirent.h>
+#include <limits.h>
+#include <errno.h>
+#include "syscall.h"
+
+ssize_t posix_getdents(int fd, void *buf, size_t len, int flags)
+{
+ if (flags) return __syscall_ret(-EOPNOTSUPP);
+ if (len>INT_MAX) len = INT_MAX;
+ return syscall(SYS_getdents, fd, buf, len);
+}
diff --git a/src/errno/__strerror.h b/src/errno/__strerror.h
index 14925907..0398b5b6 100644
--- a/src/errno/__strerror.h
+++ b/src/errno/__strerror.h
@@ -97,6 +97,8 @@ E(ESHUTDOWN, "Cannot send after socket shutdown")
E(EALREADY, "Operation already in progress")
E(EINPROGRESS, "Operation in progress")
E(ESTALE, "Stale file handle")
+E(EUCLEAN, "Data consistency error")
+E(ENAVAIL, "Resource not available")
E(EREMOTEIO, "Remote I/O error")
E(EDQUOT, "Quota exceeded")
E(ENOMEDIUM, "No medium found")
diff --git a/src/exit/atexit.c b/src/exit/atexit.c
index 854e9fdd..92c91c9d 100644
--- a/src/exit/atexit.c
+++ b/src/exit/atexit.c
@@ -19,6 +19,7 @@ static struct fl
void *a[COUNT];
} builtin, *head;
+static int finished_atexit;
static int slot;
static volatile int lock[1];
volatile int *const __atexit_lockptr = lock;
@@ -34,6 +35,10 @@ void __funcs_on_exit()
func(arg);
LOCK(lock);
}
+ /* Unlock to prevent deadlock if a global dtor
+ * attempts to call atexit. */
+ finished_atexit = 1;
+ UNLOCK(lock);
}
void __cxa_finalize(void *dso)
@@ -44,6 +49,13 @@ int __cxa_atexit(void (*func)(void *), void *arg, void *dso)
{
LOCK(lock);
+ /* Prevent dtors from registering further atexit
+ * handlers that would never be run. */
+ if (finished_atexit) {
+ UNLOCK(lock);
+ return -1;
+ }
+
/* Defer initialization of head so it can be in BSS */
if (!head) head = &builtin;
diff --git a/src/exit/exit.c b/src/exit/exit.c
index a6869b37..17b33cc6 100644
--- a/src/exit/exit.c
+++ b/src/exit/exit.c
@@ -1,6 +1,9 @@
#include <stdlib.h>
#include <stdint.h>
#include "libc.h"
+#include "pthread_impl.h"
+#include "atomic.h"
+#include "syscall.h"
static void dummy()
{
@@ -26,6 +29,17 @@ weak_alias(libc_exit_fini, __libc_exit_fini);
_Noreturn void exit(int code)
{
+ /* Handle potentially concurrent or recursive calls to exit,
+ * whose behaviors have traditionally been undefined by the
+ * standards. Using a custom lock here avoids pulling in lock
+ * machinery and lets us trap recursive calls while supporting
+ * multiple threads contending to be the one to exit(). */
+ static volatile int exit_lock[1];
+ int tid = __pthread_self()->tid;
+ int prev = a_cas(exit_lock, 0, tid);
+ if (prev == tid) a_crash();
+ else if (prev) for (;;) __sys_pause();
+
__funcs_on_exit();
__libc_exit_fini();
__stdio_exit();
diff --git a/src/fenv/loongarch64/fenv.S b/src/fenv/loongarch64/fenv.S
new file mode 100644
index 00000000..9c38599e
--- /dev/null
+++ b/src/fenv/loongarch64/fenv.S
@@ -0,0 +1,78 @@
+#ifndef __loongarch_soft_float
+
+#ifdef BROKEN_LOONGARCH_FCSR_ASM
+#define FCSR $r0
+#else
+#define FCSR $fcsr0
+#endif
+
+.global feclearexcept
+.type feclearexcept,@function
+feclearexcept:
+ li.w $t0, 0x1f0000
+ and $a0, $a0, $t0
+ movfcsr2gr $t1, FCSR
+ andn $t1, $t1, $a0
+ movgr2fcsr FCSR, $t1
+ li.w $a0, 0
+ jr $ra
+
+.global feraiseexcept
+.type feraiseexcept,@function
+feraiseexcept:
+ li.w $t0, 0x1f0000
+ and $a0, $a0, $t0
+ movfcsr2gr $t1, FCSR
+ or $t1, $t1, $a0
+ movgr2fcsr FCSR, $t1
+ li.w $a0, 0
+ jr $ra
+
+.global fetestexcept
+.type fetestexcept,@function
+fetestexcept:
+ li.w $t0, 0x1f0000
+ and $a0, $a0, $t0
+ movfcsr2gr $t1, FCSR
+ and $a0, $t1, $a0
+ jr $ra
+
+.global fegetround
+.type fegetround,@function
+fegetround:
+ movfcsr2gr $t0, FCSR
+ andi $a0, $t0, 0x300
+ jr $ra
+
+.global __fesetround
+.hidden __fesetround
+.type __fesetround,@function
+__fesetround:
+ li.w $t0, 0x300
+ and $a0, $a0, $t0
+ movfcsr2gr $t1, FCSR
+ andn $t1, $t1, $t0
+ or $t1, $t1, $a0
+ movgr2fcsr FCSR, $t1
+ li.w $a0, 0
+ jr $ra
+
+.global fegetenv
+.type fegetenv,@function
+fegetenv:
+ movfcsr2gr $t0, FCSR
+ st.w $t0, $a0, 0
+ li.w $a0, 0
+ jr $ra
+
+.global fesetenv
+.type fesetenv,@function
+fesetenv:
+ addi.d $t0, $a0, 1
+ beq $t0, $r0, 1f
+ ld.w $t0, $a0, 0
+1: movgr2fcsr FCSR, $t0
+ li.w $a0, 0
+ jr $ra
+
+#endif
diff --git a/src/fenv/riscv32/fenv-sf.c b/src/fenv/riscv32/fenv-sf.c
new file mode 100644
index 00000000..ecd3cb5c
--- /dev/null
+++ b/src/fenv/riscv32/fenv-sf.c
@@ -0,0 +1,3 @@
+#ifndef __riscv_flen
+#include "../fenv.c"
+#endif
diff --git a/src/fenv/riscv32/fenv.S b/src/fenv/riscv32/fenv.S
new file mode 100644
index 00000000..0ea78bf9
--- /dev/null
+++ b/src/fenv/riscv32/fenv.S
@@ -0,0 +1,56 @@
+#ifdef __riscv_flen
+
+.global feclearexcept
+.type feclearexcept, %function
+feclearexcept:
+ csrc fflags, a0
+ li a0, 0
+ ret
+
+.global feraiseexcept
+.type feraiseexcept, %function
+feraiseexcept:
+ csrs fflags, a0
+ li a0, 0
+ ret
+
+.global fetestexcept
+.type fetestexcept, %function
+fetestexcept:
+ frflags t0
+ and a0, t0, a0
+ ret
+
+.global fegetround
+.type fegetround, %function
+fegetround:
+ frrm a0
+ ret
+
+.global __fesetround
+.type __fesetround, %function
+__fesetround:
+ fsrm t0, a0
+ li a0, 0
+ ret
+
+.global fegetenv
+.type fegetenv, %function
+fegetenv:
+ frcsr t0
+ sw t0, 0(a0)
+ li a0, 0
+ ret
+
+.global fesetenv
+.type fesetenv, %function
+fesetenv:
+ li t2, -1
+ li t1, 0
+ beq a0, t2, 1f
+ lw t1, 0(a0)
+1: fscsr t1
+ li a0, 0
+ ret
+
+#endif
diff --git a/src/internal/atomic.h b/src/internal/atomic.h
index 96c1552d..8f71c8cd 100644
--- a/src/internal/atomic.h
+++ b/src/internal/atomic.h
@@ -194,7 +194,7 @@ static inline void a_store(volatile int *p, int v)
#ifndef a_barrier
#define a_barrier a_barrier
-static void a_barrier()
+static inline void a_barrier()
{
volatile int tmp = 0;
a_cas(&tmp, 0, 0);
diff --git a/src/internal/dynlink.h b/src/internal/dynlink.h
index 06f41d09..40c743e2 100644
--- a/src/internal/dynlink.h
+++ b/src/internal/dynlink.h
@@ -73,6 +73,10 @@ struct fdpic_dummy_loadmap {
#define DL_NOMMU_SUPPORT 0
#endif
+#ifndef TLSDESC_BACKWARDS
+#define TLSDESC_BACKWARDS 0
+#endif
+
#if !DL_FDPIC
#define IS_RELATIVE(x,s) ( \
(R_TYPE(x) == REL_RELATIVE) || \
diff --git a/src/internal/emulate_wait4.c b/src/internal/emulate_wait4.c
new file mode 100644
index 00000000..f6303412
--- /dev/null
+++ b/src/internal/emulate_wait4.c
@@ -0,0 +1,55 @@
+#include <sys/wait.h>
+#include "syscall.h"
+
+#ifndef SYS_wait4
+hidden long __emulate_wait4(int pid, int *status, int options, void *kru, int cp)
+{
+ idtype_t t;
+ int r;
+ siginfo_t info;
+
+ info.si_pid = 0;
+ if (pid < -1) {
+ t = P_PGID;
+ pid = -pid;
+ } else if (pid == -1) {
+ t = P_ALL;
+ } else if (pid == 0) {
+ t = P_PGID;
+ } else {
+ t = P_PID;
+ }
+
+ if (cp) r = __syscall_cp(SYS_waitid, t, pid, &info, options|WEXITED, kru);
+ else r = __syscall(SYS_waitid, t, pid, &info, options|WEXITED, kru);
+
+ if (r<0) return r;
+
+ if (info.si_pid && status) {
+ int sw=0;
+ switch (info.si_code) {
+ case CLD_CONTINUED:
+ sw = 0xffff;
+ break;
+ case CLD_DUMPED:
+ sw = info.si_status&0x7f | 0x80;
+ break;
+ case CLD_EXITED:
+ sw = (info.si_status&0xff) << 8;
+ break;
+ case CLD_KILLED:
+ sw = info.si_status&0x7f;
+ break;
+ case CLD_STOPPED:
+ case CLD_TRAPPED:
+ /* see ptrace(2); the high bits of si_status can contain */
+ /* PTRACE_EVENT_ values which must be preserved */
+ sw = (info.si_status << 8) + 0x7f;
+ break;
+ }
+ *status = sw;
+ }
+
+ return info.si_pid;
+}
+#endif
diff --git a/src/internal/fork_impl.h b/src/internal/fork_impl.h
index 354e733b..f995fce2 100644
--- a/src/internal/fork_impl.h
+++ b/src/internal/fork_impl.h
@@ -17,3 +17,5 @@ extern hidden volatile int *const __vmlock_lockptr;
hidden void __malloc_atfork(int);
hidden void __ldso_atfork(int);
hidden void __pthread_key_atfork(int);
+
+hidden void __post_Fork(int);
diff --git a/src/internal/syscall.h b/src/internal/syscall.h
index 4a446157..2d8a5c13 100644
--- a/src/internal/syscall.h
+++ b/src/internal/syscall.h
@@ -391,6 +391,29 @@ static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a,
#define __sys_open_cp(...) __SYSCALL_DISP(__sys_open_cp,,__VA_ARGS__)
#define sys_open_cp(...) __syscall_ret(__sys_open_cp(__VA_ARGS__))
+#ifdef SYS_pause
+#define __sys_pause() __syscall(SYS_pause)
+#define __sys_pause_cp() __syscall_cp(SYS_pause)
+#else
+#define __sys_pause() __syscall(SYS_ppoll, 0, 0, 0, 0)
+#define __sys_pause_cp() __syscall_cp(SYS_ppoll, 0, 0, 0, 0)
+#endif
+
+#define sys_pause() __syscall_ret(__sys_pause())
+#define sys_pause_cp() __syscall_ret(__sys_pause_cp())
+
+#ifdef SYS_wait4
+#define __sys_wait4(a,b,c,d) __syscall(SYS_wait4,a,b,c,d)
+#define __sys_wait4_cp(a,b,c,d) __syscall_cp(SYS_wait4,a,b,c,d)
+#else
+hidden long __emulate_wait4(int, int *, int, void *, int);
+#define __sys_wait4(a,b,c,d) __emulate_wait4(a,b,c,d,0)
+#define __sys_wait4_cp(a,b,c,d) __emulate_wait4(a,b,c,d,1)
+#endif
+
+#define sys_wait4(a,b,c,d) __syscall_ret(__sys_wait4(a,b,c,d))
+#define sys_wait4_cp(a,b,c,d) __syscall_ret(__sys_wait4_cp(a,b,c,d))
+
hidden void __procfdname(char __buf[static 15+3*sizeof(int)], unsigned);
hidden void *__vdsosym(const char *, const char *);
diff --git a/src/ldso/loongarch64/dlsym.s b/src/ldso/loongarch64/dlsym.s
new file mode 100644
index 00000000..26fabcdb
--- /dev/null
+++ b/src/ldso/loongarch64/dlsym.s
@@ -0,0 +1,7 @@
+.global dlsym
+.hidden __dlsym
+.type dlsym,@function
+dlsym:
+ move $a2, $ra
+ la.global $t0, __dlsym
+ jr $t0
diff --git a/src/ldso/loongarch64/tlsdesc.s b/src/ldso/loongarch64/tlsdesc.s
new file mode 100644
index 00000000..4b6ea0e5
--- /dev/null
+++ b/src/ldso/loongarch64/tlsdesc.s
@@ -0,0 +1,37 @@
+.text
+.global __tlsdesc_static
+.hidden __tlsdesc_static
+.type __tlsdesc_static,%function
+__tlsdesc_static:
+ ld.d $a0, $a0, 8
+ jr $ra
+# size_t __tlsdesc_dynamic(size_t *a)
+# {
+# struct {size_t modidx,off;} *p = (void*)a[1];
+# size_t *dtv = *(size_t**)(tp - 8);
+# return dtv[p->modidx] + p->off - tp;
+# }
+.global __tlsdesc_dynamic
+.hidden __tlsdesc_dynamic
+.type __tlsdesc_dynamic,%function
+__tlsdesc_dynamic:
+ addi.d $sp, $sp, -16
+ st.d $t1, $sp, 0
+ st.d $t2, $sp, 8
+
+ ld.d $t2, $tp, -8 # t2=dtv
+
+ ld.d $a0, $a0, 8 # a0=&{modidx,off}
+ ld.d $t1, $a0, 8 # t1=off
+ ld.d $a0, $a0, 0 # a0=modidx
+ slli.d $a0, $a0, 3 # a0=8*modidx
+
+ add.d $a0, $a0, $t2 # a0=dtv+8*modidx
+ ld.d $a0, $a0, 0 # a0=dtv[modidx]
+ add.d $a0, $a0, $t1 # a0=dtv[modidx]+off
+ sub.d $a0, $a0, $tp # a0=dtv[modidx]+off-tp
+
+ ld.d $t1, $sp, 0
+ ld.d $t2, $sp, 8
+ addi.d $sp, $sp, 16
+ jr $ra
diff --git a/src/ldso/riscv32/dlsym.s b/src/ldso/riscv32/dlsym.s
new file mode 100644
index 00000000..2bafd72d
--- /dev/null
+++ b/src/ldso/riscv32/dlsym.s
@@ -0,0 +1,6 @@
+.global dlsym
+.hidden __dlsym
+.type dlsym, %function
+dlsym:
+ mv a2, ra
+ tail __dlsym
diff --git a/src/ldso/riscv64/tlsdesc.s b/src/ldso/riscv64/tlsdesc.s
new file mode 100644
index 00000000..bef8b322
--- /dev/null
+++ b/src/ldso/riscv64/tlsdesc.s
@@ -0,0 +1,32 @@
+.text
+.global __tlsdesc_static
+.hidden __tlsdesc_static
+.type __tlsdesc_static,%function
+__tlsdesc_static:
+ ld a0,8(a0)
+ jr t0
+
+.global __tlsdesc_dynamic
+.hidden __tlsdesc_dynamic
+.type __tlsdesc_dynamic,%function
+__tlsdesc_dynamic:
+ add sp,sp,-16
+ sd t1,(sp)
+ sd t2,8(sp)
+
+ ld t2,-8(tp) # t2=dtv
+
+ ld a0,8(a0) # a0=&{modidx,off}
+ ld t1,8(a0) # t1=off
+ ld a0,(a0) # a0=modidx
+ sll a0,a0,3 # a0=8*modidx
+
+ add a0,a0,t2 # a0=dtv+8*modidx
+ ld a0,(a0) # a0=dtv[modidx]
+ add a0,a0,t1 # a0=dtv[modidx]+off
+ sub a0,a0,tp # a0=dtv[modidx]+off-tp
+
+ ld t1,(sp)
+ ld t2,8(sp)
+ add sp,sp,16
+ jr t0
diff --git a/src/ldso/sh/dlsym.s b/src/ldso/sh/dlsym.s
index 11a6fff5..34f3c35c 100644
--- a/src/ldso/sh/dlsym.s
+++ b/src/ldso/sh/dlsym.s
@@ -5,7 +5,7 @@
dlsym:
mov.l L1, r0
1: braf r0
- mov.l @r15, r6
+ sts pr, r6
.align 2
L1: .long __dlsym@PLT-(1b+4-.)
diff --git a/src/legacy/getusershell.c b/src/legacy/getusershell.c
index 5fecdec2..1c5d98ec 100644
--- a/src/legacy/getusershell.c
+++ b/src/legacy/getusershell.c
@@ -25,8 +25,10 @@ char *getusershell(void)
ssize_t l;
if (!f) setusershell();
if (!f) return 0;
- l = getline(&line, &linesize, f);
- if (l <= 0) return 0;
+ do {
+ l = getline(&line, &linesize, f);
+ if (l <= 0) return 0;
+ } while (line[0] == '#' || line[0] == '\n');
if (line[l-1]=='\n') line[l-1]=0;
return line;
}
diff --git a/src/linux/cache.c b/src/linux/cache.c
index 0eb051c2..e76f7812 100644
--- a/src/linux/cache.c
+++ b/src/linux/cache.c
@@ -21,7 +21,7 @@ weak_alias(__cachectl, cachectl);
#ifdef SYS_riscv_flush_icache
#define VDSO_FLUSH_ICACHE_SYM "__vdso_flush_icache"
-#define VDSO_FLUSH_ICACHE_VER "LINUX_4.5"
+#define VDSO_FLUSH_ICACHE_VER "LINUX_4.15"
static void *volatile vdso_func;
@@ -45,6 +45,7 @@ int __riscv_flush_icache(void *start, void *end, unsigned long int flags)
if (!r) return r;
if (r != -ENOSYS) return __syscall_ret(r);
}
+ return syscall(SYS_riscv_flush_icache, start, end, flags);
}
weak_alias(__riscv_flush_icache, riscv_flush_icache);
#endif
diff --git a/src/linux/clone.c b/src/linux/clone.c
index 8c1af7d3..257c1cec 100644
--- a/src/linux/clone.c
+++ b/src/linux/clone.c
@@ -4,18 +4,62 @@
#include <sched.h>
#include "pthread_impl.h"
#include "syscall.h"
+#include "lock.h"
+#include "fork_impl.h"
+
+struct clone_start_args {
+ int (*func)(void *);
+ void *arg;
+ sigset_t sigmask;
+};
+
+static int clone_start(void *arg)
+{
+ struct clone_start_args *csa = arg;
+ __post_Fork(0);
+ __restore_sigs(&csa->sigmask);
+ return csa->func(csa->arg);
+}
int clone(int (*func)(void *), void *stack, int flags, void *arg, ...)
{
+ struct clone_start_args csa;
va_list ap;
- pid_t *ptid, *ctid;
- void *tls;
+ pid_t *ptid = 0, *ctid = 0;
+ void *tls = 0;
+
+ /* Flags that produce an invalid thread/TLS state are disallowed. */
+ int badflags = CLONE_THREAD | CLONE_SETTLS | CLONE_CHILD_CLEARTID;
+
+ if ((flags & badflags) || !stack)
+ return __syscall_ret(-EINVAL);
va_start(ap, arg);
- ptid = va_arg(ap, pid_t *);
- tls = va_arg(ap, void *);
- ctid = va_arg(ap, pid_t *);
+ if (flags & (CLONE_PIDFD | CLONE_PARENT_SETTID | CLONE_CHILD_SETTID))
+ ptid = va_arg(ap, pid_t *);
+ if (flags & CLONE_CHILD_SETTID) {
+ tls = va_arg(ap, void *);
+ ctid = va_arg(ap, pid_t *);
+ }
va_end(ap);
- return __syscall_ret(__clone(func, stack, flags, arg, ptid, tls, ctid));
+ /* If CLONE_VM is used, it's impossible to give the child a consistent
+ * thread structure. In this case, the best we can do is assume the
+ * caller is content with an extremely restrictive execution context
+ * like the one vfork() would provide. */
+ if (flags & CLONE_VM) return __syscall_ret(
+ __clone(func, stack, flags, arg, ptid, tls, ctid));
+
+ __block_all_sigs(&csa.sigmask);
+ LOCK(__abort_lock);
+
+ /* Setup the a wrapper start function for the child process to do
+ * mimic _Fork in producing a consistent execution state. */
+ csa.func = func;
+ csa.arg = arg;
+ int ret = __clone(clone_start, stack, flags, &csa, ptid, tls, ctid);
+
+ __post_Fork(ret);
+ __restore_sigs(&csa.sigmask);
+ return __syscall_ret(ret);
}
diff --git a/src/linux/preadv2.c b/src/linux/preadv2.c
new file mode 100644
index 00000000..5e7ab70f
--- /dev/null
+++ b/src/linux/preadv2.c
@@ -0,0 +1,17 @@
+#define _GNU_SOURCE
+#include <sys/uio.h>
+#include <unistd.h>
+#include "syscall.h"
+
+ssize_t preadv2(int fd, const struct iovec *iov, int count, off_t ofs, int flags)
+{
+#ifdef SYS_preadv
+ if (!flags) {
+ if (ofs==-1) return readv(fd, iov, count);
+ return syscall_cp(SYS_preadv, fd, iov, count,
+ (long)(ofs), (long)(ofs>>32));
+ }
+#endif
+ return syscall_cp(SYS_preadv2, fd, iov, count,
+ (long)(ofs), (long)(ofs>>32), flags);
+}
diff --git a/src/linux/pwritev2.c b/src/linux/pwritev2.c
new file mode 100644
index 00000000..ece90d7c
--- /dev/null
+++ b/src/linux/pwritev2.c
@@ -0,0 +1,17 @@
+#define _GNU_SOURCE
+#include <sys/uio.h>
+#include <unistd.h>
+#include "syscall.h"
+
+ssize_t pwritev2(int fd, const struct iovec *iov, int count, off_t ofs, int flags)
+{
+#ifdef SYS_pwritev
+ if (!flags) {
+ if (ofs==-1) return writev(fd, iov, count);
+ return syscall_cp(SYS_pwritev, fd, iov, count,
+ (long)(ofs), (long)(ofs>>32));
+ }
+#endif
+ return syscall_cp(SYS_pwritev2, fd, iov, count,
+ (long)(ofs), (long)(ofs>>32), flags);
+}
diff --git a/src/linux/renameat2.c b/src/linux/renameat2.c
new file mode 100644
index 00000000..b8060388
--- /dev/null
+++ b/src/linux/renameat2.c
@@ -0,0 +1,11 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include "syscall.h"
+
+int renameat2(int oldfd, const char *old, int newfd, const char *new, unsigned flags)
+{
+#ifdef SYS_renameat
+ if (!flags) return syscall(SYS_renameat, oldfd, old, newfd, new);
+#endif
+ return syscall(SYS_renameat2, oldfd, old, newfd, new, flags);
+}
diff --git a/src/linux/statx.c b/src/linux/statx.c
new file mode 100644
index 00000000..4fb96e4b
--- /dev/null
+++ b/src/linux/statx.c
@@ -0,0 +1,44 @@
+#define _GNU_SOURCE
+#include <sys/stat.h>
+#include <string.h>
+#include <syscall.h>
+#include <sys/sysmacros.h>
+#include <errno.h>
+
+int statx(int dirfd, const char *restrict path, int flags, unsigned mask, struct statx *restrict stx)
+{
+ int ret = __syscall(SYS_statx, dirfd, path, flags, mask, stx);
+
+#ifndef SYS_fstatat
+ return __syscall_ret(ret);
+#endif
+
+ if (ret != -ENOSYS) return __syscall_ret(ret);
+
+ struct stat st;
+ ret = fstatat(dirfd, path, &st, flags);
+ if (ret) return ret;
+
+ *stx = (struct statx){0};
+ stx->stx_dev_major = major(st.st_dev);
+ stx->stx_dev_minor = minor(st.st_dev);
+ stx->stx_rdev_major = major(st.st_rdev);
+ stx->stx_rdev_minor = minor(st.st_rdev);
+ stx->stx_ino = st.st_ino;
+ stx->stx_mode = st.st_mode;
+ stx->stx_nlink = st.st_nlink;
+ stx->stx_uid = st.st_uid;
+ stx->stx_gid = st.st_gid;
+ stx->stx_size = st.st_size;
+ stx->stx_blksize = st.st_blksize;
+ stx->stx_blocks = st.st_blocks;
+ stx->stx_atime.tv_sec = st.st_atim.tv_sec;
+ stx->stx_atime.tv_nsec = st.st_atim.tv_nsec;
+ stx->stx_mtime.tv_sec = st.st_mtim.tv_sec;
+ stx->stx_mtime.tv_nsec = st.st_mtim.tv_nsec;
+ stx->stx_ctime.tv_sec = st.st_ctim.tv_sec;
+ stx->stx_ctime.tv_nsec = st.st_ctim.tv_nsec;
+ stx->stx_mask = STATX_BASIC_STATS;
+
+ return 0;
+}
diff --git a/src/linux/wait4.c b/src/linux/wait4.c
index ff2e3e66..fb08c0d0 100644
--- a/src/linux/wait4.c
+++ b/src/linux/wait4.c
@@ -26,7 +26,7 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru)
}
#endif
char *dest = ru ? (char *)&ru->ru_maxrss - 4*sizeof(long) : 0;
- r = __syscall(SYS_wait4, pid, status, options, dest);
+ r = __sys_wait4(pid, status, options, dest);
if (r>0 && ru && sizeof(time_t) > sizeof(long)) {
long kru[4];
memcpy(kru, dest, 4*sizeof(long));
diff --git a/src/locale/bind_textdomain_codeset.c b/src/locale/bind_textdomain_codeset.c
index 5ebfd5e8..240e83ed 100644
--- a/src/locale/bind_textdomain_codeset.c
+++ b/src/locale/bind_textdomain_codeset.c
@@ -5,7 +5,9 @@
char *bind_textdomain_codeset(const char *domainname, const char *codeset)
{
- if (codeset && strcasecmp(codeset, "UTF-8"))
+ if (codeset && strcasecmp(codeset, "UTF-8")) {
errno = EINVAL;
- return NULL;
+ return 0;
+ }
+ return "UTF-8";
}
diff --git a/src/locale/codepages.h b/src/locale/codepages.h
index 4e236ef3..a254f0f5 100644
--- a/src/locale/codepages.h
+++ b/src/locale/codepages.h
@@ -286,6 +286,17 @@
"\323\174\103\215\64\365\124\123\213\77\336\150\263\115\66\375\164\363\12\55"
"\255\304\42\261\57\266\234\162\17\56\260\240\162\113\56\263\310\62\66\50"
+"cp858\0"
+"\0\40"
+"\307\360\223\216\70\344\200\123\316\71\352\254\203\316\73\356\260\103\114\61"
+"\311\230\143\14\75\366\310\263\117\76\377\130\303\15\76\243\140\163\15\135"
+"\341\264\63\217\76\361\104\243\212\56\277\270\302\112\57\274\204\262\312\56"
+"\140\207\55\66\315\72\7\43\14\60\251\104\375\163\321\113\213\122\212\315"
+"\67\363\274\163\316\63\367\74\316\60\110\13\175\65\325\116\373\254\65\51"
+"\360\100\243\314\62\310\220\334\214\63\317\340\134\163\327\134\233\302\314\326"
+"\323\174\103\215\64\365\124\123\213\77\336\150\263\115\66\375\164\363\12\55"
+"\255\304\42\261\57\266\234\162\17\56\260\240\162\113\56\263\310\62\66\50"
+
"cp866\0"
"\0\40"
"\337\201\27\236\170\343\221\127\236\171\347\241\227\236\172"
diff --git a/src/locale/iconv.c b/src/locale/iconv.c
index 3047c27b..52178950 100644
--- a/src/locale/iconv.c
+++ b/src/locale/iconv.c
@@ -49,10 +49,10 @@ static const unsigned char charmaps[] =
"ucs4\0utf32\0\0\313"
"ucs2\0\0\314"
"eucjp\0\0\320"
-"shiftjis\0sjis\0\0\321"
+"shiftjis\0sjis\0cp932\0\0\321"
"iso2022jp\0\0\322"
"gb18030\0\0\330"
-"gbk\0\0\331"
+"gbk\0cp936\0windows936\0\0\331"
"gb2312\0\0\332"
"big5\0bigfive\0cp950\0big5hkscs\0\0\340"
"euckr\0ksc5601\0ksx1001\0cp949\0\0\350"
@@ -339,7 +339,10 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
} else if (d-159 <= 252-159) {
c++;
d -= 159;
+ } else {
+ goto ilseq;
}
+ if (c>=84) goto ilseq;
c = jis0208[c][d];
if (!c) goto ilseq;
break;
@@ -403,6 +406,10 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
if (c < 128) break;
if (c < 0xa1) goto ilseq;
case GBK:
+ if (c == 128) {
+ c = 0x20ac;
+ break;
+ }
case GB18030:
if (c < 128) break;
c -= 0x81;
@@ -495,7 +502,7 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
if (c >= 93 || d >= 94) {
c += (0xa1-0x81);
d += 0xa1;
- if (c >= 93 || c>=0xc6-0x81 && d>0x52)
+ if (c > 0xc6-0x81 || c==0xc6-0x81 && d>0x52)
goto ilseq;
if (d-'A'<26) d = d-'A';
else if (d-'a'<26) d = d-'a'+26;
@@ -538,6 +545,10 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
if (*outb < k) goto toobig;
memcpy(*out, tmp, k);
} else k = wctomb_utf8(*out, c);
+ /* This failure condition should be unreachable, but
+ * is included to prevent decoder bugs from translating
+ * into advancement outside the output buffer range. */
+ if (k>4) goto ilseq;
*out += k;
*outb -= k;
break;
diff --git a/src/math/acoshl.c b/src/math/acoshl.c
index 8d4b43f6..943cec17 100644
--- a/src/math/acoshl.c
+++ b/src/math/acoshl.c
@@ -10,14 +10,18 @@ long double acoshl(long double x)
long double acoshl(long double x)
{
union ldshape u = {x};
- int e = u.i.se & 0x7fff;
+ int e = u.i.se;
if (e < 0x3fff + 1)
- /* |x| < 2, invalid if x < 1 or nan */
+ /* 0 <= x < 2, invalid if x < 1 */
return log1pl(x-1 + sqrtl((x-1)*(x-1)+2*(x-1)));
if (e < 0x3fff + 32)
- /* |x| < 0x1p32 */
+ /* 2 <= x < 0x1p32 */
return logl(2*x - 1/(x+sqrtl(x*x-1)));
+ if (e & 0x8000)
+ /* x < 0 or x = -0, invalid */
+ return (x - x) / (x - x);
+ /* 0x1p32 <= x or nan */
return logl(x) + 0.693147180559945309417232121458176568L;
}
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
diff --git a/src/math/fma.c b/src/math/fma.c
index 0c6f90c9..adfadca8 100644
--- a/src/math/fma.c
+++ b/src/math/fma.c
@@ -53,7 +53,7 @@ double fma(double x, double y, double z)
return x*y + z;
if (nz.e >= ZEROINFNAN) {
if (nz.e > ZEROINFNAN) /* z==0 */
- return x*y + z;
+ return x*y;
return z;
}
diff --git a/src/math/powl.c b/src/math/powl.c
index 5b6da07b..9eb22162 100644
--- a/src/math/powl.c
+++ b/src/math/powl.c
@@ -57,14 +57,6 @@
* IEEE 0,8700 60000 6.5e-18 1.0e-18
* 0.99 < x < 1.01, 0 < y < 8700, uniformly distributed.
*
- *
- * ERROR MESSAGES:
- *
- * message condition value returned
- * pow overflow x**y > MAXNUM INFINITY
- * pow underflow x**y < 1/MAXNUM 0.0
- * pow domain x<0 and y noninteger 0.0
- *
*/
#include "libm.h"
@@ -212,25 +204,33 @@ long double powl(long double x, long double y)
}
if (x == 1.0)
return 1.0; /* 1**y = 1, even if y is nan */
- if (x == -1.0 && !isfinite(y))
- return 1.0; /* -1**inf = 1 */
if (y == 0.0)
return 1.0; /* x**0 = 1, even if x is nan */
if (y == 1.0)
return x;
- if (y >= LDBL_MAX) {
- if (x > 1.0 || x < -1.0)
- return INFINITY;
- if (x != 0.0)
- return 0.0;
- }
- if (y <= -LDBL_MAX) {
- if (x > 1.0 || x < -1.0)
+ /* if y*log2(x) < log2(LDBL_TRUE_MIN)-1 then x^y uflows to 0
+ if y*log2(x) > -log2(LDBL_TRUE_MIN)+1 > LDBL_MAX_EXP then x^y oflows
+ if |x|!=1 then |log2(x)| > |log(x)| > LDBL_EPSILON/2 so
+ x^y oflows/uflows if |y|*LDBL_EPSILON/2 > -log2(LDBL_TRUE_MIN)+1 */
+ if (fabsl(y) > 2*(-LDBL_MIN_EXP+LDBL_MANT_DIG+1)/LDBL_EPSILON) {
+ /* y is not an odd int */
+ if (x == -1.0)
+ return 1.0;
+ if (y == INFINITY) {
+ if (x > 1.0 || x < -1.0)
+ return INFINITY;
return 0.0;
- if (x != 0.0 || y == -INFINITY)
+ }
+ if (y == -INFINITY) {
+ if (x > 1.0 || x < -1.0)
+ return 0.0;
return INFINITY;
+ }
+ if ((x > 1.0 || x < -1.0) == (y > 0))
+ return huge * huge;
+ return twom10000 * twom10000;
}
- if (x >= LDBL_MAX) {
+ if (x == INFINITY) {
if (y > 0.0)
return INFINITY;
return 0.0;
@@ -253,7 +253,7 @@ long double powl(long double x, long double y)
yoddint = 1;
}
- if (x <= -LDBL_MAX) {
+ if (x == -INFINITY) {
if (y > 0.0) {
if (yoddint)
return -INFINITY;
diff --git a/src/math/riscv32/copysign.c b/src/math/riscv32/copysign.c
new file mode 100644
index 00000000..c7854178
--- /dev/null
+++ b/src/math/riscv32/copysign.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double copysign(double x, double y)
+{
+ __asm__ ("fsgnj.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../copysign.c"
+
+#endif
diff --git a/src/math/riscv32/copysignf.c b/src/math/riscv32/copysignf.c
new file mode 100644
index 00000000..a125611a
--- /dev/null
+++ b/src/math/riscv32/copysignf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float copysignf(float x, float y)
+{
+ __asm__ ("fsgnj.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../copysignf.c"
+
+#endif
diff --git a/src/math/riscv32/fabs.c b/src/math/riscv32/fabs.c
new file mode 100644
index 00000000..5290b6f0
--- /dev/null
+++ b/src/math/riscv32/fabs.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fabs(double x)
+{
+ __asm__ ("fabs.d %0, %1" : "=f"(x) : "f"(x));
+ return x;
+}
+
+#else
+
+#include "../fabs.c"
+
+#endif
diff --git a/src/math/riscv32/fabsf.c b/src/math/riscv32/fabsf.c
new file mode 100644
index 00000000..f5032e35
--- /dev/null
+++ b/src/math/riscv32/fabsf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fabsf(float x)
+{
+ __asm__ ("fabs.s %0, %1" : "=f"(x) : "f"(x));
+ return x;
+}
+
+#else
+
+#include "../fabsf.c"
+
+#endif
diff --git a/src/math/riscv32/fma.c b/src/math/riscv32/fma.c
new file mode 100644
index 00000000..99b05713
--- /dev/null
+++ b/src/math/riscv32/fma.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fma(double x, double y, double z)
+{
+ __asm__ ("fmadd.d %0, %1, %2, %3" : "=f"(x) : "f"(x), "f"(y), "f"(z));
+ return x;
+}
+
+#else
+
+#include "../fma.c"
+
+#endif
diff --git a/src/math/riscv32/fmaf.c b/src/math/riscv32/fmaf.c
new file mode 100644
index 00000000..f9dc47ed
--- /dev/null
+++ b/src/math/riscv32/fmaf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fmaf(float x, float y, float z)
+{
+ __asm__ ("fmadd.s %0, %1, %2, %3" : "=f"(x) : "f"(x), "f"(y), "f"(z));
+ return x;
+}
+
+#else
+
+#include "../fmaf.c"
+
+#endif
diff --git a/src/math/riscv32/fmax.c b/src/math/riscv32/fmax.c
new file mode 100644
index 00000000..023709cd
--- /dev/null
+++ b/src/math/riscv32/fmax.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fmax(double x, double y)
+{
+ __asm__ ("fmax.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../fmax.c"
+
+#endif
diff --git a/src/math/riscv32/fmaxf.c b/src/math/riscv32/fmaxf.c
new file mode 100644
index 00000000..863d2bd1
--- /dev/null
+++ b/src/math/riscv32/fmaxf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fmaxf(float x, float y)
+{
+ __asm__ ("fmax.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../fmaxf.c"
+
+#endif
diff --git a/src/math/riscv32/fmin.c b/src/math/riscv32/fmin.c
new file mode 100644
index 00000000..a4e3b067
--- /dev/null
+++ b/src/math/riscv32/fmin.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double fmin(double x, double y)
+{
+ __asm__ ("fmin.d %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../fmin.c"
+
+#endif
diff --git a/src/math/riscv32/fminf.c b/src/math/riscv32/fminf.c
new file mode 100644
index 00000000..32156e80
--- /dev/null
+++ b/src/math/riscv32/fminf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float fminf(float x, float y)
+{
+ __asm__ ("fmin.s %0, %1, %2" : "=f"(x) : "f"(x), "f"(y));
+ return x;
+}
+
+#else
+
+#include "../fminf.c"
+
+#endif
diff --git a/src/math/riscv32/sqrt.c b/src/math/riscv32/sqrt.c
new file mode 100644
index 00000000..867a504c
--- /dev/null
+++ b/src/math/riscv32/sqrt.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 64
+
+double sqrt(double x)
+{
+ __asm__ ("fsqrt.d %0, %1" : "=f"(x) : "f"(x));
+ return x;
+}
+
+#else
+
+#include "../sqrt.c"
+
+#endif
diff --git a/src/math/riscv32/sqrtf.c b/src/math/riscv32/sqrtf.c
new file mode 100644
index 00000000..610c2cf8
--- /dev/null
+++ b/src/math/riscv32/sqrtf.c
@@ -0,0 +1,15 @@
+#include <math.h>
+
+#if __riscv_flen >= 32
+
+float sqrtf(float x)
+{
+ __asm__ ("fsqrt.s %0, %1" : "=f"(x) : "f"(x));
+ return x;
+}
+
+#else
+
+#include "../sqrtf.c"
+
+#endif
diff --git a/src/math/sqrtl.c b/src/math/sqrtl.c
index 1b9f19c7..a231b3f2 100644
--- a/src/math/sqrtl.c
+++ b/src/math/sqrtl.c
@@ -205,7 +205,7 @@ long double sqrtl(long double x)
top = (top + 0x3fff) >> 1;
/* r ~ 1/sqrt(m) */
- static const uint64_t three = 0xc0000000;
+ const uint64_t three = 0xc0000000;
uint64_t r, s, d, u, i;
i = (ix.hi >> 42) % 128;
r = (uint32_t)__rsqrt_tab[i] << 16;
@@ -227,7 +227,7 @@ long double sqrtl(long double x)
r = mul64(u, r) << 1;
/* |r sqrt(m) - 1| < 0x1.c001p-59, switch to 128bit */
- static const u128 threel = {.hi=three<<32, .lo=0};
+ const u128 threel = {.hi=three<<32, .lo=0};
u128 rl, sl, dl, ul;
rl.hi = r;
rl.lo = 0;
diff --git a/src/misc/initgroups.c b/src/misc/initgroups.c
index 922a9581..101f5c7b 100644
--- a/src/misc/initgroups.c
+++ b/src/misc/initgroups.c
@@ -1,11 +1,29 @@
#define _GNU_SOURCE
#include <grp.h>
#include <limits.h>
+#include <stdlib.h>
int initgroups(const char *user, gid_t gid)
{
- gid_t groups[NGROUPS_MAX];
- int count = NGROUPS_MAX;
- if (getgrouplist(user, gid, groups, &count) < 0) return -1;
- return setgroups(count, groups);
+ gid_t buf[32], *groups = buf;
+ int count = sizeof buf / sizeof *buf, prev_count = count;
+ while (getgrouplist(user, gid, groups, &count) < 0) {
+ if (groups != buf) free(groups);
+
+ /* Return if failure isn't buffer size */
+ if (count <= prev_count)
+ return -1;
+
+ /* Always increase by at least 50% to limit to
+ * logarithmically many retries on TOCTOU races. */
+ if (count < prev_count + (prev_count>>1))
+ count = prev_count + (prev_count>>1);
+
+ groups = calloc(count, sizeof *groups);
+ if (!groups) return -1;
+ prev_count = count;
+ }
+ int ret = setgroups(count, groups);
+ if (groups != buf) free(groups);
+ return ret;
}
diff --git a/src/misc/mntent.c b/src/misc/mntent.c
index d404fbe3..76f9c162 100644
--- a/src/misc/mntent.c
+++ b/src/misc/mntent.c
@@ -20,6 +20,42 @@ int endmntent(FILE *f)
return 1;
}
+static char *unescape_ent(char *beg)
+{
+ char *dest = beg;
+ const char *src = beg;
+ while (*src) {
+ const char *val;
+ unsigned char cval = 0;
+ if (*src != '\\') {
+ *dest++ = *src++;
+ continue;
+ }
+ if (src[1] == '\\') {
+ ++src;
+ *dest++ = *src++;
+ continue;
+ }
+ val = src + 1;
+ for (int i = 0; i < 3; ++i) {
+ if (*val >= '0' && *val <= '7') {
+ cval <<= 3;
+ cval += *val++ - '0';
+ } else {
+ break;
+ }
+ }
+ if (cval) {
+ *dest++ = cval;
+ src = val;
+ } else {
+ *dest++ = *src++;
+ }
+ }
+ *dest = 0;
+ return beg;
+}
+
struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen)
{
int n[8], use_internal = (linebuf == SENTINEL);
@@ -45,7 +81,7 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle
len = strlen(linebuf);
if (len > INT_MAX) continue;
for (i = 0; i < sizeof n / sizeof *n; i++) n[i] = len;
- sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d",
+ sscanf(linebuf, " %n%*[^ \t\n]%n %n%*[^ \t\n]%n %n%*[^ \t\n]%n %n%*[^ \t\n]%n %d %d",
n, n+1, n+2, n+3, n+4, n+5, n+6, n+7,
&mnt->mnt_freq, &mnt->mnt_passno);
} while (linebuf[n[0]] == '#' || n[1]==len);
@@ -55,10 +91,10 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle
linebuf[n[5]] = 0;
linebuf[n[7]] = 0;
- mnt->mnt_fsname = linebuf+n[0];
- mnt->mnt_dir = linebuf+n[2];
- mnt->mnt_type = linebuf+n[4];
- mnt->mnt_opts = linebuf+n[6];
+ mnt->mnt_fsname = unescape_ent(linebuf+n[0]);
+ mnt->mnt_dir = unescape_ent(linebuf+n[2]);
+ mnt->mnt_type = unescape_ent(linebuf+n[4]);
+ mnt->mnt_opts = unescape_ent(linebuf+n[6]);
return mnt;
}
@@ -79,5 +115,13 @@ int addmntent(FILE *f, const struct mntent *mnt)
char *hasmntopt(const struct mntent *mnt, const char *opt)
{
- return strstr(mnt->mnt_opts, opt);
+ size_t l = strlen(opt);
+ char *p = mnt->mnt_opts;
+ for (;;) {
+ if (!strncmp(p, opt, l) && (!p[l] || p[l]==',' || p[l]=='='))
+ return p;
+ p = strchr(p, ',');
+ if (!p) return 0;
+ p++;
+ }
}
diff --git a/src/misc/syslog.c b/src/misc/syslog.c
index 7dc0c1be..710202f9 100644
--- a/src/misc/syslog.c
+++ b/src/misc/syslog.c
@@ -11,6 +11,7 @@
#include <fcntl.h>
#include "lock.h"
#include "fork_impl.h"
+#include "locale_impl.h"
static volatile int lock[1];
static char log_ident[32];
@@ -99,7 +100,7 @@ static void _vsyslog(int priority, const char *message, va_list ap)
now = time(NULL);
gmtime_r(&now, &tm);
- strftime(timebuf, sizeof timebuf, "%b %e %T", &tm);
+ strftime_l(timebuf, sizeof timebuf, "%b %e %T", &tm, C_LOCALE);
pid = (log_opt & LOG_PID) ? getpid() : 0;
l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ",
diff --git a/src/mq/x32/mq_open.c b/src/mq/x32/mq_open.c
new file mode 100644
index 00000000..23481959
--- /dev/null
+++ b/src/mq/x32/mq_open.c
@@ -0,0 +1,22 @@
+#include <mqueue.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include "syscall.h"
+
+mqd_t mq_open(const char *name, int flags, ...)
+{
+ mode_t mode = 0;
+ struct mq_attr *attr = 0;
+ long long attrbuf[8];
+ if (*name == '/') name++;
+ if (flags & O_CREAT) {
+ va_list ap;
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ attr = va_arg(ap, struct mq_attr *);
+ if (attr) for (int i=0; i<8; i++)
+ attrbuf[i] = *(long *)((char *)attr + i*sizeof(long));
+ va_end(ap);
+ }
+ return syscall(SYS_mq_open, name, flags, mode, attr?attrbuf:0);
+}
diff --git a/src/mq/x32/mq_setattr.c b/src/mq/x32/mq_setattr.c
new file mode 100644
index 00000000..0c631175
--- /dev/null
+++ b/src/mq/x32/mq_setattr.c
@@ -0,0 +1,14 @@
+#include <mqueue.h>
+#include "syscall.h"
+
+int mq_setattr(mqd_t mqd, const struct mq_attr *restrict new, struct mq_attr *restrict old)
+{
+ long long attr[8];
+ if (new) for (int i=0; i<8; i++)
+ attr[i] = *(long *)((char *)new + i*sizeof(long));
+ int ret = __syscall(SYS_mq_getsetattr, mqd, new?attr:0, old?attr:0);
+ if (ret < 0) return __syscall_ret(ret);
+ if (old) for (int i=0; i<8; i++)
+ *(long *)((char *)old + i*sizeof(long)) = attr[i];
+ return 0;
+}
diff --git a/src/multibyte/mbrtowc.c b/src/multibyte/mbrtowc.c
index c94819e7..7824997e 100644
--- a/src/multibyte/mbrtowc.c
+++ b/src/multibyte/mbrtowc.c
@@ -8,7 +8,7 @@ size_t mbrtowc(wchar_t *restrict wc, const char *restrict src, size_t n, mbstate
static unsigned internal_state;
unsigned c;
const unsigned char *s = (const void *)src;
- const unsigned N = n;
+ const size_t N = n;
wchar_t dummy;
if (!st) st = (void *)&internal_state;
diff --git a/src/multibyte/mbsnrtowcs.c b/src/multibyte/mbsnrtowcs.c
index 931192e2..47cbdc00 100644
--- a/src/multibyte/mbsnrtowcs.c
+++ b/src/multibyte/mbsnrtowcs.c
@@ -2,11 +2,13 @@
size_t mbsnrtowcs(wchar_t *restrict wcs, const char **restrict src, size_t n, size_t wn, mbstate_t *restrict st)
{
+ static unsigned internal_state;
size_t l, cnt=0, n2;
wchar_t *ws, wbuf[256];
const char *s = *src;
const char *tmp_s;
+ if (!st) st = (void *)&internal_state;
if (!wcs) ws = wbuf, wn = sizeof wbuf / sizeof *wbuf;
else ws = wcs;
@@ -41,8 +43,8 @@ size_t mbsnrtowcs(wchar_t *restrict wcs, const char **restrict src, size_t n, si
s = 0;
break;
}
- /* have to roll back partial character */
- *(unsigned *)st = 0;
+ s += n;
+ n -= n;
break;
}
s += l; n -= l;
diff --git a/src/network/dns_parse.c b/src/network/dns_parse.c
index 7f83e791..09813112 100644
--- a/src/network/dns_parse.c
+++ b/src/network/dns_parse.c
@@ -12,16 +12,15 @@ int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, c
p = r+12;
qdcount = r[4]*256 + r[5];
ancount = r[6]*256 + r[7];
- if (qdcount+ancount > 64) return -1;
while (qdcount--) {
while (p-r < rlen && *p-1U < 127) p++;
- if (p>r+rlen-6 || *p>193 || (*p==193 && p[1]>254))
+ if (p>r+rlen-6)
return -1;
p += 5 + !!*p;
}
while (ancount--) {
while (p-r < rlen && *p-1U < 127) p++;
- if (p>r+rlen-12 || *p>193 || (*p==193 && p[1]>254))
+ if (p>r+rlen-12)
return -1;
p += 1 + !!*p;
len = p[8]*256 + p[9];
diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c
index 7abe0fa9..133c15b3 100644
--- a/src/network/getnameinfo.c
+++ b/src/network/getnameinfo.c
@@ -162,8 +162,10 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl,
query[3] = 0; /* don't need AD flag */
int rlen = __res_send(query, qlen, reply, sizeof reply);
buf[0] = 0;
- if (rlen > 0)
+ if (rlen > 0) {
+ if (rlen > sizeof reply) rlen = sizeof reply;
__dns_parse(reply, rlen, dns_parse_callback, buf);
+ }
}
if (!*buf) {
if (flags & NI_NAMEREQD) return EAI_NONAME;
diff --git a/src/network/inet_ntop.c b/src/network/inet_ntop.c
index 4bfef2c5..f442f47d 100644
--- a/src/network/inet_ntop.c
+++ b/src/network/inet_ntop.c
@@ -34,7 +34,12 @@ const char *inet_ntop(int af, const void *restrict a0, char *restrict s, socklen
for (i=best=0, max=2; buf[i]; i++) {
if (i && buf[i] != ':') continue;
j = strspn(buf+i, ":0");
- if (j>max) best=i, max=j;
+ /* The leading sequence of zeros (best==0) is
+ * disadvantaged compared to sequences elsewhere
+ * as it doesn't have a leading colon. One extra
+ * character is required for another sequence to
+ * beat it fairly. */
+ if (j>max+(best==0)) best=i, max=j;
}
if (max>3) {
buf[best] = buf[best+1] = ':';
diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c
index 4281482e..35218185 100644
--- a/src/network/lookup_name.c
+++ b/src/network/lookup_name.c
@@ -109,7 +109,7 @@ struct dpc_ctx {
#define RR_CNAME 5
#define RR_AAAA 28
-#define ABUF_SIZE 768
+#define ABUF_SIZE 4800
static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)
{
diff --git a/src/network/res_msend.c b/src/network/res_msend.c
index 86c2fcf4..fcb52513 100644
--- a/src/network/res_msend.c
+++ b/src/network/res_msend.c
@@ -83,8 +83,8 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries,
int fd;
int timeout, attempts, retry_interval, servfail_retry;
union {
- struct sockaddr_in sin;
struct sockaddr_in6 sin6;
+ struct sockaddr_in sin;
} sa = {0}, ns[MAXNS] = {{0}};
socklen_t sl = sizeof sa.sin;
int nns = 0;
diff --git a/src/process/_Fork.c b/src/process/_Fork.c
index fb0fdc2c..9c07792d 100644
--- a/src/process/_Fork.c
+++ b/src/process/_Fork.c
@@ -5,24 +5,16 @@
#include "lock.h"
#include "pthread_impl.h"
#include "aio_impl.h"
+#include "fork_impl.h"
static void dummy(int x) { }
weak_alias(dummy, __aio_atfork);
-pid_t _Fork(void)
+void __post_Fork(int ret)
{
- pid_t ret;
- sigset_t set;
- __block_all_sigs(&set);
- LOCK(__abort_lock);
-#ifdef SYS_fork
- ret = __syscall(SYS_fork);
-#else
- ret = __syscall(SYS_clone, SIGCHLD, 0);
-#endif
if (!ret) {
pthread_t self = __pthread_self();
- self->tid = __syscall(SYS_gettid);
+ self->tid = __syscall(SYS_set_tid_address, &__thread_list_lock);
self->robust_list.off = 0;
self->robust_list.pending = 0;
self->next = self->prev = self;
@@ -32,6 +24,20 @@ pid_t _Fork(void)
}
UNLOCK(__abort_lock);
if (!ret) __aio_atfork(1);
+}
+
+pid_t _Fork(void)
+{
+ pid_t ret;
+ sigset_t set;
+ __block_all_sigs(&set);
+ LOCK(__abort_lock);
+#ifdef SYS_fork
+ ret = __syscall(SYS_fork);
+#else
+ ret = __syscall(SYS_clone, SIGCHLD, 0);
+#endif
+ __post_Fork(ret);
__restore_sigs(&set);
return __syscall_ret(ret);
}
diff --git a/src/process/posix_spawn.c b/src/process/posix_spawn.c
index 728551b3..8294598b 100644
--- a/src/process/posix_spawn.c
+++ b/src/process/posix_spawn.c
@@ -4,6 +4,7 @@
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
+#include <errno.h>
#include <sys/wait.h>
#include "syscall.h"
#include "lock.h"
@@ -156,7 +157,11 @@ static int child(void *args_vp)
fail:
/* Since sizeof errno < PIPE_BUF, the write is atomic. */
ret = -ret;
- if (ret) while (__syscall(SYS_write, p, &ret, sizeof ret) < 0);
+ if (ret) {
+ int r;
+ do r = __syscall(SYS_write, p, &ret, sizeof ret);
+ while (r<0 && r!=-EPIPE);
+ }
_exit(127);
}
diff --git a/src/process/waitpid.c b/src/process/waitpid.c
index 1b65bf05..80231862 100644
--- a/src/process/waitpid.c
+++ b/src/process/waitpid.c
@@ -3,5 +3,5 @@
pid_t waitpid(pid_t pid, int *status, int options)
{
- return syscall_cp(SYS_wait4, pid, status, options, 0);
+ return sys_wait4_cp(pid, status, options, 0);
}
diff --git a/src/regex/glob.c b/src/regex/glob.c
index a4906446..87bae084 100644
--- a/src/regex/glob.c
+++ b/src/regex/glob.c
@@ -265,7 +265,7 @@ int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, i
if (append(&tail, pat, strlen(pat), 0))
return GLOB_NOSPACE;
cnt++;
- } else
+ } else if (!error)
return GLOB_NOMATCH;
}
diff --git a/src/linux/ppoll.c b/src/select/ppoll.c
index e614600a..9a0bf929 100644
--- a/src/linux/ppoll.c
+++ b/src/select/ppoll.c
@@ -1,4 +1,4 @@
-#define _GNU_SOURCE
+#define _BSD_SOURCE
#include <poll.h>
#include <signal.h>
#include <errno.h>
diff --git a/src/setjmp/loongarch64/longjmp.S b/src/setjmp/loongarch64/longjmp.S
new file mode 100644
index 00000000..896d2e26
--- /dev/null
+++ b/src/setjmp/loongarch64/longjmp.S
@@ -0,0 +1,32 @@
+.global _longjmp
+.global longjmp
+.type _longjmp,@function
+.type longjmp,@function
+_longjmp:
+longjmp:
+ ld.d $ra, $a0, 0
+ ld.d $sp, $a0, 8
+ ld.d $r21,$a0, 16
+ ld.d $fp, $a0, 24
+ ld.d $s0, $a0, 32
+ ld.d $s1, $a0, 40
+ ld.d $s2, $a0, 48
+ ld.d $s3, $a0, 56
+ ld.d $s4, $a0, 64
+ ld.d $s5, $a0, 72
+ ld.d $s6, $a0, 80
+ ld.d $s7, $a0, 88
+ ld.d $s8, $a0, 96
+#ifndef __loongarch_soft_float
+ fld.d $fs0, $a0, 104
+ fld.d $fs1, $a0, 112
+ fld.d $fs2, $a0, 120
+ fld.d $fs3, $a0, 128
+ fld.d $fs4, $a0, 136
+ fld.d $fs5, $a0, 144
+ fld.d $fs6, $a0, 152
+ fld.d $fs7, $a0, 160
+#endif
+ sltui $a0, $a1, 1
+ add.d $a0, $a0, $a1
+ jr $ra
diff --git a/src/setjmp/loongarch64/setjmp.S b/src/setjmp/loongarch64/setjmp.S
new file mode 100644
index 00000000..d158a3d2
--- /dev/null
+++ b/src/setjmp/loongarch64/setjmp.S
@@ -0,0 +1,34 @@
+.global __setjmp
+.global _setjmp
+.global setjmp
+.type __setjmp,@function
+.type _setjmp,@function
+.type setjmp,@function
+__setjmp:
+_setjmp:
+setjmp:
+ st.d $ra, $a0, 0
+ st.d $sp, $a0, 8
+ st.d $r21,$a0, 16
+ st.d $fp, $a0, 24
+ st.d $s0, $a0, 32
+ st.d $s1, $a0, 40
+ st.d $s2, $a0, 48
+ st.d $s3, $a0, 56
+ st.d $s4, $a0, 64
+ st.d $s5, $a0, 72
+ st.d $s6, $a0, 80
+ st.d $s7, $a0, 88
+ st.d $s8, $a0, 96
+#ifndef __loongarch_soft_float
+ fst.d $fs0, $a0, 104
+ fst.d $fs1, $a0, 112
+ fst.d $fs2, $a0, 120
+ fst.d $fs3, $a0, 128
+ fst.d $fs4, $a0, 136
+ fst.d $fs5, $a0, 144
+ fst.d $fs6, $a0, 152
+ fst.d $fs7, $a0, 160
+#endif
+ move $a0, $zero
+ jr $ra
diff --git a/src/setjmp/riscv32/longjmp.S b/src/setjmp/riscv32/longjmp.S
new file mode 100644
index 00000000..f9cb3318
--- /dev/null
+++ b/src/setjmp/riscv32/longjmp.S
@@ -0,0 +1,42 @@
+.global __longjmp
+.global _longjmp
+.global longjmp
+.type __longjmp, %function
+.type _longjmp, %function
+.type longjmp, %function
+__longjmp:
+_longjmp:
+longjmp:
+ lw s0, 0(a0)
+ lw s1, 4(a0)
+ lw s2, 8(a0)
+ lw s3, 12(a0)
+ lw s4, 16(a0)
+ lw s5, 20(a0)
+ lw s6, 24(a0)
+ lw s7, 28(a0)
+ lw s8, 32(a0)
+ lw s9, 36(a0)
+ lw s10, 40(a0)
+ lw s11, 44(a0)
+ lw sp, 48(a0)
+ lw ra, 52(a0)
+
+#ifndef __riscv_float_abi_soft
+ fld fs0, 56(a0)
+ fld fs1, 64(a0)
+ fld fs2, 72(a0)
+ fld fs3, 80(a0)
+ fld fs4, 88(a0)
+ fld fs5, 96(a0)
+ fld fs6, 104(a0)
+ fld fs7, 112(a0)
+ fld fs8, 120(a0)
+ fld fs9, 128(a0)
+ fld fs10, 136(a0)
+ fld fs11, 144(a0)
+#endif
+
+ seqz a0, a1
+ add a0, a0, a1
+ ret
diff --git a/src/setjmp/riscv32/setjmp.S b/src/setjmp/riscv32/setjmp.S
new file mode 100644
index 00000000..8a75cf55
--- /dev/null
+++ b/src/setjmp/riscv32/setjmp.S
@@ -0,0 +1,41 @@
+.global __setjmp
+.global _setjmp
+.global setjmp
+.type __setjmp, %function
+.type _setjmp, %function
+.type setjmp, %function
+__setjmp:
+_setjmp:
+setjmp:
+ sw s0, 0(a0)
+ sw s1, 4(a0)
+ sw s2, 8(a0)
+ sw s3, 12(a0)
+ sw s4, 16(a0)
+ sw s5, 20(a0)
+ sw s6, 24(a0)
+ sw s7, 28(a0)
+ sw s8, 32(a0)
+ sw s9, 36(a0)
+ sw s10, 40(a0)
+ sw s11, 44(a0)
+ sw sp, 48(a0)
+ sw ra, 52(a0)
+
+#ifndef __riscv_float_abi_soft
+ fsd fs0, 56(a0)
+ fsd fs1, 64(a0)
+ fsd fs2, 72(a0)
+ fsd fs3, 80(a0)
+ fsd fs4, 88(a0)
+ fsd fs5, 96(a0)
+ fsd fs6, 104(a0)
+ fsd fs7, 112(a0)
+ fsd fs8, 120(a0)
+ fsd fs9, 128(a0)
+ fsd fs10, 136(a0)
+ fsd fs11, 144(a0)
+#endif
+
+ li a0, 0
+ ret
diff --git a/src/signal/loongarch64/restore.s b/src/signal/loongarch64/restore.s
new file mode 100644
index 00000000..d90a8ebb
--- /dev/null
+++ b/src/signal/loongarch64/restore.s
@@ -0,0 +1,10 @@
+.global __restore_rt
+.global __restore
+.hidden __restore_rt
+.hidden __restore
+.type __restore_rt,@function
+.type __restore,@function
+__restore_rt:
+__restore:
+ li.w $a7, 139
+ syscall 0
diff --git a/src/signal/loongarch64/sigsetjmp.s b/src/signal/loongarch64/sigsetjmp.s
new file mode 100644
index 00000000..9c0e3ae2
--- /dev/null
+++ b/src/signal/loongarch64/sigsetjmp.s
@@ -0,0 +1,25 @@
+.global sigsetjmp
+.global __sigsetjmp
+.type sigsetjmp,@function
+.type __sigsetjmp,@function
+sigsetjmp:
+__sigsetjmp:
+ beq $a1, $zero, 1f
+ st.d $ra, $a0, 184
+ st.d $s0, $a0, 200 #184+8+8
+ move $s0, $a0
+
+ la.global $t0, setjmp
+ jirl $ra, $t0, 0
+
+ move $a1, $a0 # Return from 'setjmp' or 'longjmp'
+ move $a0, $s0
+ ld.d $ra, $a0, 184
+ ld.d $s0, $a0, 200 #184+8+8
+
+.hidden __sigsetjmp_tail
+ la.global $t0, __sigsetjmp_tail
+ jr $t0
+1:
+ la.global $t0, setjmp
+ jr $t0
diff --git a/src/signal/riscv32/restore.s b/src/signal/riscv32/restore.s
new file mode 100644
index 00000000..5a0af695
--- /dev/null
+++ b/src/signal/riscv32/restore.s
@@ -0,0 +1,10 @@
+.global __restore
+.hidden __restore
+.type __restore, %function
+__restore:
+.global __restore_rt
+.hidden __restore_rt
+.type __restore_rt, %function
+__restore_rt:
+ li a7, 139 # SYS_rt_sigreturn
+ ecall
diff --git a/src/signal/riscv32/sigsetjmp.s b/src/signal/riscv32/sigsetjmp.s
new file mode 100644
index 00000000..c1caeab1
--- /dev/null
+++ b/src/signal/riscv32/sigsetjmp.s
@@ -0,0 +1,23 @@
+.global sigsetjmp
+.global __sigsetjmp
+.type sigsetjmp, %function
+.type __sigsetjmp, %function
+sigsetjmp:
+__sigsetjmp:
+ bnez a1, 1f
+ tail setjmp
+1:
+
+ sw ra, 152(a0)
+ sw s0, 164(a0)
+ mv s0, a0
+
+ call setjmp
+
+ mv a1, a0
+ mv a0, s0
+ lw s0, 164(a0)
+ lw ra, 152(a0)
+
+.hidden __sigsetjmp_tail
+ tail __sigsetjmp_tail
diff --git a/src/signal/riscv64/restore.s b/src/signal/riscv64/restore.s
index 40012c75..5a0af695 100644
--- a/src/signal/riscv64/restore.s
+++ b/src/signal/riscv64/restore.s
@@ -1,7 +1,9 @@
.global __restore
+.hidden __restore
.type __restore, %function
__restore:
.global __restore_rt
+.hidden __restore_rt
.type __restore_rt, %function
__restore_rt:
li a7, 139 # SYS_rt_sigreturn
diff --git a/src/signal/sh/sigsetjmp.s b/src/signal/sh/sigsetjmp.s
index 1e2270be..f0f604e2 100644
--- a/src/signal/sh/sigsetjmp.s
+++ b/src/signal/sh/sigsetjmp.s
@@ -27,7 +27,7 @@ __sigsetjmp:
mov.l 3f, r0
4: braf r0
- mov.l @(4+8,r4), r8
+ mov.l @(4+8,r6), r8
9: mov.l 5f, r0
6: braf r0
diff --git a/src/signal/sigaltstack.c b/src/signal/sigaltstack.c
index d3a6e821..616625c5 100644
--- a/src/signal/sigaltstack.c
+++ b/src/signal/sigaltstack.c
@@ -1,11 +1,13 @@
#include <signal.h>
#include <errno.h>
+#include <unistd.h>
#include "syscall.h"
int sigaltstack(const stack_t *restrict ss, stack_t *restrict old)
{
if (ss) {
- if (!(ss->ss_flags & SS_DISABLE) && ss->ss_size < MINSIGSTKSZ) {
+ size_t min = sysconf(_SC_MINSIGSTKSZ);
+ if (!(ss->ss_flags & SS_DISABLE) && ss->ss_size < min) {
errno = ENOMEM;
return -1;
}
diff --git a/src/signal/siglongjmp.c b/src/signal/siglongjmp.c
index bc317acc..53789b23 100644
--- a/src/signal/siglongjmp.c
+++ b/src/signal/siglongjmp.c
@@ -5,5 +5,10 @@
_Noreturn void siglongjmp(sigjmp_buf buf, int ret)
{
+ /* If sigsetjmp was called with nonzero savemask flag, the address
+ * longjmp will return to is inside of sigsetjmp. The signal mask
+ * will then be restored in the returned-to context instead of here,
+ * which matters if the context we are returning from may not have
+ * sufficient stack space for signal delivery. */
longjmp(buf, ret);
}
diff --git a/src/signal/sigpause.c b/src/signal/sigpause.c
index 363d2fec..1587c391 100644
--- a/src/signal/sigpause.c
+++ b/src/signal/sigpause.c
@@ -4,6 +4,6 @@ int sigpause(int sig)
{
sigset_t mask;
sigprocmask(0, 0, &mask);
- sigdelset(&mask, sig);
+ if (sigdelset(&mask, sig)) return -1;
return sigsuspend(&mask);
}
diff --git a/src/stat/fchmodat.c b/src/stat/fchmodat.c
index bc581050..92c9d1b0 100644
--- a/src/stat/fchmodat.c
+++ b/src/stat/fchmodat.c
@@ -5,13 +5,16 @@
int fchmodat(int fd, const char *path, mode_t mode, int flag)
{
- if (!flag) return syscall(SYS_fchmodat, fd, path, mode, flag);
+ if (!flag) return syscall(SYS_fchmodat, fd, path, mode);
+
+ int ret = __syscall(SYS_fchmodat2, fd, path, mode, flag);
+ if (ret != -ENOSYS) return __syscall_ret(ret);
if (flag != AT_SYMLINK_NOFOLLOW)
return __syscall_ret(-EINVAL);
struct stat st;
- int ret, fd2;
+ int fd2;
char proc[15+3*sizeof(int)];
if (fstatat(fd, path, &st, flag))
diff --git a/src/stat/fstatat.c b/src/stat/fstatat.c
index 04506375..9eed063b 100644
--- a/src/stat/fstatat.c
+++ b/src/stat/fstatat.c
@@ -36,6 +36,7 @@ static int fstatat_statx(int fd, const char *restrict path, struct stat *restric
{
struct statx stx;
+ flag |= AT_NO_AUTOMOUNT;
int ret = __syscall(SYS_statx, fd, path, flag, 0x7ff, &stx);
if (ret) return ret;
diff --git a/src/stat/statvfs.c b/src/stat/statvfs.c
index bfbb5fee..bc12da8b 100644
--- a/src/stat/statvfs.c
+++ b/src/stat/statvfs.c
@@ -39,6 +39,7 @@ static void fixup(struct statvfs *out, const struct statfs *in)
out->f_fsid = in->f_fsid.__val[0];
out->f_flag = in->f_flags;
out->f_namemax = in->f_namelen;
+ out->f_type = in->f_type;
}
int statvfs(const char *restrict path, struct statvfs *restrict buf)
diff --git a/src/stdio/__stdio_write.c b/src/stdio/__stdio_write.c
index d2d89475..5356553d 100644
--- a/src/stdio/__stdio_write.c
+++ b/src/stdio/__stdio_write.c
@@ -11,6 +11,11 @@ size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len)
size_t rem = iov[0].iov_len + iov[1].iov_len;
int iovcnt = 2;
ssize_t cnt;
+
+ if (!iov->iov_len) {
+ iov++;
+ iovcnt--;
+ }
for (;;) {
cnt = syscall(SYS_writev, f->fd, iov, iovcnt);
if (cnt == rem) {
diff --git a/src/stdio/pclose.c b/src/stdio/pclose.c
index 080a4262..c64da405 100644
--- a/src/stdio/pclose.c
+++ b/src/stdio/pclose.c
@@ -7,7 +7,7 @@ int pclose(FILE *f)
int status, r;
pid_t pid = f->pipe_pid;
fclose(f);
- while ((r=__syscall(SYS_wait4, pid, &status, 0, 0)) == -EINTR);
+ while ((r=__sys_wait4(pid, &status, 0, 0)) == -EINTR);
if (r<0) return __syscall_ret(r);
return status;
}
diff --git a/src/stdio/vfprintf.c b/src/stdio/vfprintf.c
index a712d80f..76733997 100644
--- a/src/stdio/vfprintf.c
+++ b/src/stdio/vfprintf.c
@@ -52,7 +52,7 @@ static const unsigned char states[]['z'-'A'+1] = {
S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
- S('c') = CHAR, S('C') = INT,
+ S('c') = INT, S('C') = UINT,
S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
S('m') = NOARG,
S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
@@ -62,7 +62,7 @@ static const unsigned char states[]['z'-'A'+1] = {
S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
- S('c') = INT, S('s') = PTR, S('n') = PTR,
+ S('c') = UINT, S('s') = PTR, S('n') = PTR,
S('l') = LLPRE,
}, { /* 2: ll-prefixed */
S('d') = LLONG, S('i') = LLONG,
@@ -166,7 +166,8 @@ static char *fmt_u(uintmax_t x, char *s)
{
unsigned long y;
for ( ; x>ULONG_MAX; x/=10) *--s = '0' + x%10;
- for (y=x; y; y/=10) *--s = '0' + y%10;
+ for (y=x; y>=10; y/=10) *--s = '0' + y%10;
+ if (y) *--s = '0' + y;
return s;
}
@@ -177,10 +178,14 @@ static char *fmt_u(uintmax_t x, char *s)
typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)];
#endif
-static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
+static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t, int ps)
{
- uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion
- + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion
+ int bufsize = (ps==BIGLPRE)
+ ? (LDBL_MANT_DIG+28)/29 + 1 + // mantissa expansion
+ (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9 // exponent expansion
+ : (DBL_MANT_DIG+28)/29 + 1 +
+ (DBL_MAX_EXP+DBL_MANT_DIG+28+8)/9;
+ uint32_t big[bufsize];
uint32_t *a, *d, *r, *z;
int e2=0, e, i, j, l;
char buf[9+LDBL_MANT_DIG/4], *s;
@@ -211,18 +216,11 @@ static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t)
if (y) e2--;
if ((t|32)=='a') {
- long double round = 8.0;
- int re;
-
if (t&32) prefix += 9;
pl += 2;
- if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0;
- else re=LDBL_MANT_DIG/4-1-p;
-
- if (re) {
- round *= 1<<(LDBL_MANT_DIG%4);
- while (re--) round*=16;
+ if (p>=0 && p<(LDBL_MANT_DIG-1+3)/4) {
+ double round = scalbn(1, LDBL_MANT_DIG-1-(p*4));
if (*prefix=='-') {
y=-y;
y-=round;
@@ -437,7 +435,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
unsigned st, ps;
int cnt=0, l=0;
size_t i;
- char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4];
+ char buf[sizeof(uintmax_t)*3];
const char *prefix;
int t, pl;
wchar_t wc[2], *ws;
@@ -563,11 +561,11 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
case 'x': case 'X':
a = fmt_x(arg.i, z, t&32);
if (arg.i && (fl & ALT_FORM)) prefix+=(t>>4), pl=2;
- if (0) {
+ goto ifmt_tail;
case 'o':
a = fmt_o(arg.i, z);
if ((fl&ALT_FORM) && p<z-a+1) p=z-a+1;
- } if (0) {
+ goto ifmt_tail;
case 'd': case 'i':
pl=1;
if (arg.i>INTMAX_MAX) {
@@ -579,7 +577,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
} else pl=0;
case 'u':
a = fmt_u(arg.i, z);
- }
+ ifmt_tail:
if (xp && p<0) goto overflow;
if (xp) fl &= ~ZERO_PAD;
if (!arg.i && !p) {
@@ -588,6 +586,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
}
p = MAX(p, z-a + !arg.i);
break;
+ narrow_c:
case 'c':
*(a=z-(p=1))=arg.i;
fl &= ~ZERO_PAD;
@@ -602,6 +601,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
fl &= ~ZERO_PAD;
break;
case 'C':
+ if (!arg.i) goto narrow_c;
wc[0] = arg.i;
wc[1] = 0;
arg.p = wc;
@@ -622,7 +622,7 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg,
case 'e': case 'f': case 'g': case 'a':
case 'E': case 'F': case 'G': case 'A':
if (xp && p<0) goto overflow;
- l = fmt_fp(f, arg.f, w, p, fl, t);
+ l = fmt_fp(f, arg.f, w, p, fl, t, ps);
if (l<0) goto overflow;
continue;
}
diff --git a/src/stdio/vfwprintf.c b/src/stdio/vfwprintf.c
index 53697701..59d5471b 100644
--- a/src/stdio/vfwprintf.c
+++ b/src/stdio/vfwprintf.c
@@ -45,7 +45,7 @@ static const unsigned char states[]['z'-'A'+1] = {
S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
- S('c') = CHAR, S('C') = INT,
+ S('c') = INT, S('C') = UINT,
S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
S('m') = NOARG,
S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
@@ -55,7 +55,7 @@ static const unsigned char states[]['z'-'A'+1] = {
S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
- S('c') = INT, S('s') = PTR, S('n') = PTR,
+ S('c') = UINT, S('s') = PTR, S('n') = PTR,
S('l') = LLPRE,
}, { /* 2: ll-prefixed */
S('d') = LLONG, S('i') = LLONG,
diff --git a/src/stdio/vsnprintf.c b/src/stdio/vsnprintf.c
index b3510a63..409b9c85 100644
--- a/src/stdio/vsnprintf.c
+++ b/src/stdio/vsnprintf.c
@@ -45,11 +45,6 @@ int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap)
.cookie = &c,
};
- if (n > INT_MAX) {
- errno = EOVERFLOW;
- return -1;
- }
-
*c.s = 0;
return vfprintf(&f, fmt, ap);
}
diff --git a/src/stdio/vswprintf.c b/src/stdio/vswprintf.c
index fc223cf2..5e9a4dad 100644
--- a/src/stdio/vswprintf.c
+++ b/src/stdio/vswprintf.c
@@ -51,9 +51,6 @@ int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_lis
if (!n) {
return -1;
- } else if (n > INT_MAX) {
- errno = EOVERFLOW;
- return -1;
}
r = vfwprintf(&f, fmt, ap);
sw_write(&f, 0, 0);
diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c
index 314ddc29..ab79dc6f 100644
--- a/src/stdlib/qsort.c
+++ b/src/stdlib/qsort.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011 by Valentin Ochs
+/* Copyright (C) 2011 by Lynn Ochs
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
diff --git a/src/string/strcasestr.c b/src/string/strcasestr.c
index af109f36..dc598bc3 100644
--- a/src/string/strcasestr.c
+++ b/src/string/strcasestr.c
@@ -4,6 +4,7 @@
char *strcasestr(const char *h, const char *n)
{
size_t l = strlen(n);
+ if (!l) return (char *)h;
for (; *h; h++) if (!strncasecmp(h, n, l)) return (char *)h;
return 0;
}
diff --git a/src/termios/cfgetospeed.c b/src/termios/cfgetospeed.c
index 55fa6f55..de46a1d8 100644
--- a/src/termios/cfgetospeed.c
+++ b/src/termios/cfgetospeed.c
@@ -9,5 +9,5 @@ speed_t cfgetospeed(const struct termios *tio)
speed_t cfgetispeed(const struct termios *tio)
{
- return cfgetospeed(tio);
+ return (tio->c_cflag & CIBAUD) / (CIBAUD/CBAUD);
}
diff --git a/src/termios/cfsetospeed.c b/src/termios/cfsetospeed.c
index c9cbdd9d..3eab092a 100644
--- a/src/termios/cfsetospeed.c
+++ b/src/termios/cfsetospeed.c
@@ -16,7 +16,11 @@ int cfsetospeed(struct termios *tio, speed_t speed)
int cfsetispeed(struct termios *tio, speed_t speed)
{
- return speed ? cfsetospeed(tio, speed) : 0;
+ if (speed & ~CBAUD) {
+ errno = EINVAL;
+ return -1;
+ }
+ tio->c_cflag &= ~CIBAUD;
+ tio->c_cflag |= speed * (CIBAUD/CBAUD);
+ return 0;
}
-
-weak_alias(cfsetospeed, cfsetspeed);
diff --git a/src/termios/cfsetspeed.c b/src/termios/cfsetspeed.c
new file mode 100644
index 00000000..2c369db9
--- /dev/null
+++ b/src/termios/cfsetspeed.c
@@ -0,0 +1,11 @@
+#define _BSD_SOURCE
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+int cfsetspeed(struct termios *tio, speed_t speed)
+{
+ int r = cfsetospeed(tio, speed);
+ if (!r) cfsetispeed(tio, 0);
+ return r;
+}
diff --git a/src/thread/aarch64/clone.s b/src/thread/aarch64/clone.s
index e3c83395..9ac272bd 100644
--- a/src/thread/aarch64/clone.s
+++ b/src/thread/aarch64/clone.s
@@ -24,7 +24,8 @@ __clone:
// parent
ret
// child
-1: ldp x1,x0,[sp],#16
+1: mov fp, 0
+ ldp x1,x0,[sp],#16
blr x1
mov x8,#93 // SYS_exit
svc #0
diff --git a/src/thread/arm/clone.s b/src/thread/arm/clone.s
index bb0965da..4ff0c0e8 100644
--- a/src/thread/arm/clone.s
+++ b/src/thread/arm/clone.s
@@ -19,7 +19,8 @@ __clone:
ldmfd sp!,{r4,r5,r6,r7}
bx lr
-1: mov r0,r6
+1: mov fp,#0
+ mov r0,r6
bl 3f
2: mov r7,#1
svc 0
diff --git a/src/thread/loongarch64/__set_thread_area.s b/src/thread/loongarch64/__set_thread_area.s
new file mode 100644
index 00000000..021307fc
--- /dev/null
+++ b/src/thread/loongarch64/__set_thread_area.s
@@ -0,0 +1,7 @@
+.global __set_thread_area
+.hidden __set_thread_area
+.type __set_thread_area,@function
+__set_thread_area:
+ move $tp, $a0
+ move $a0, $zero
+ jr $ra
diff --git a/src/thread/loongarch64/__unmapself.s b/src/thread/loongarch64/__unmapself.s
new file mode 100644
index 00000000..719ad056
--- /dev/null
+++ b/src/thread/loongarch64/__unmapself.s
@@ -0,0 +1,7 @@
+.global __unmapself
+.type __unmapself, @function
+__unmapself:
+ li.d $a7, 215 # call munmap
+ syscall 0
+ li.d $a7, 93 # call exit
+ syscall 0
diff --git a/src/thread/loongarch64/clone.s b/src/thread/loongarch64/clone.s
new file mode 100644
index 00000000..cb4aacfc
--- /dev/null
+++ b/src/thread/loongarch64/clone.s
@@ -0,0 +1,30 @@
+#__clone(func, stack, flags, arg, ptid, tls, ctid)
+# a0, a1, a2, a3, a4, a5, a6
+# sys_clone(flags, stack, ptid, ctid, tls)
+# a0, a1, a2, a3, a4
+
+.global __clone
+.hidden __clone
+.type __clone,@function
+__clone:
+ bstrins.d $a1, $zero, 3, 0 #stack to 16 align
+ # Save function pointer and argument pointer on new thread stack
+ addi.d $a1, $a1, -16
+ st.d $a0, $a1, 0 # save function pointer
+ st.d $a3, $a1, 8 # save argument pointer
+ or $a0, $a2, $zero
+ or $a2, $a4, $zero
+ or $a3, $a6, $zero
+ or $a4, $a5, $zero
+ ori $a7, $zero, 220
+ syscall 0 # call clone
+
+ beqz $a0, 1f # whether child process
+ jirl $zero, $ra, 0 # parent process return
+1:
+ move $fp, $zero
+ ld.d $t8, $sp, 0 # function pointer
+ ld.d $a0, $sp, 8 # argument pointer
+ jirl $ra, $t8, 0 # call the user's function
+ ori $a7, $zero, 93
+ syscall 0 # child process exit
diff --git a/src/thread/loongarch64/syscall_cp.s b/src/thread/loongarch64/syscall_cp.s
new file mode 100644
index 00000000..c057a97b
--- /dev/null
+++ b/src/thread/loongarch64/syscall_cp.s
@@ -0,0 +1,29 @@
+.global __cp_begin
+.hidden __cp_begin
+.global __cp_end
+.hidden __cp_end
+.global __cp_cancel
+.hidden __cp_cancel
+.hidden __cancel
+.global __syscall_cp_asm
+.hidden __syscall_cp_asm
+.type __syscall_cp_asm,@function
+
+__syscall_cp_asm:
+__cp_begin:
+ ld.w $a0, $a0, 0
+ bnez $a0, __cp_cancel
+ move $t8, $a1 # reserve system call number
+ move $a0, $a2
+ move $a1, $a3
+ move $a2, $a4
+ move $a3, $a5
+ move $a4, $a6
+ move $a5, $a7
+ move $a7, $t8
+ syscall 0
+__cp_end:
+ jr $ra
+__cp_cancel:
+ la.local $t8, __cancel
+ jr $t8
diff --git a/src/thread/m68k/clone.s b/src/thread/m68k/clone.s
index f6dfa06f..0134cf4e 100644
--- a/src/thread/m68k/clone.s
+++ b/src/thread/m68k/clone.s
@@ -18,7 +18,8 @@ __clone:
beq 1f
movem.l (%sp)+,%d2-%d5
rts
-1: move.l %a1,-(%sp)
+1: suba.l %fp,%fp
+ move.l %a1,-(%sp)
jsr (%a0)
move.l #1,%d0
trap #0
diff --git a/src/thread/microblaze/clone.s b/src/thread/microblaze/clone.s
index b68cc5fc..64e3f074 100644
--- a/src/thread/microblaze/clone.s
+++ b/src/thread/microblaze/clone.s
@@ -22,7 +22,8 @@ __clone:
rtsd r15, 8
nop
-1: lwi r3, r1, 0
+1: add r19, r0, r0
+ lwi r3, r1, 0
lwi r5, r1, 4
brald r15, r3
nop
diff --git a/src/thread/mips/clone.s b/src/thread/mips/clone.s
index 04463385..229b987e 100644
--- a/src/thread/mips/clone.s
+++ b/src/thread/mips/clone.s
@@ -27,7 +27,8 @@ __clone:
addu $sp, $sp, 16
jr $ra
nop
-1: lw $25, 0($sp)
+1: move $fp, $0
+ lw $25, 0($sp)
lw $4, 4($sp)
jalr $25
nop
diff --git a/src/thread/mips64/clone.s b/src/thread/mips64/clone.s
index 2d86899a..8de3db6c 100644
--- a/src/thread/mips64/clone.s
+++ b/src/thread/mips64/clone.s
@@ -25,7 +25,8 @@ __clone:
nop
jr $ra
nop
-1: ld $25, 0($sp) # function pointer
+1: move $fp, $0
+ ld $25, 0($sp) # function pointer
ld $4, 8($sp) # argument pointer
jalr $25 # call the user's function
nop
diff --git a/src/thread/mipsn32/clone.s b/src/thread/mipsn32/clone.s
index 4d3c8c7a..9571231a 100644
--- a/src/thread/mipsn32/clone.s
+++ b/src/thread/mipsn32/clone.s
@@ -25,7 +25,8 @@ __clone:
nop
jr $ra
nop
-1: lw $25, 0($sp) # function pointer
+1: move $fp, $0
+ lw $25, 0($sp) # function pointer
lw $4, 4($sp) # argument pointer
jalr $25 # call the user's function
nop
diff --git a/src/thread/or1k/clone.s b/src/thread/or1k/clone.s
index 2473ac20..b41488a2 100644
--- a/src/thread/or1k/clone.s
+++ b/src/thread/or1k/clone.s
@@ -6,6 +6,8 @@
.hidden __clone
.type __clone,@function
__clone:
+ l.xori r11, r0, -4
+ l.and r4, r4, r11
l.addi r4, r4, -8
l.sw 0(r4), r3
l.sw 4(r4), r6
@@ -23,7 +25,8 @@ __clone:
l.jr r9
l.nop
-1: l.lwz r11, 0(r1)
+1: l.ori r2, r0, 0
+ l.lwz r11, 0(r1)
l.jalr r11
l.lwz r3, 4(r1)
diff --git a/src/thread/riscv32/__set_thread_area.s b/src/thread/riscv32/__set_thread_area.s
new file mode 100644
index 00000000..828154d2
--- /dev/null
+++ b/src/thread/riscv32/__set_thread_area.s
@@ -0,0 +1,6 @@
+.global __set_thread_area
+.type __set_thread_area, %function
+__set_thread_area:
+ mv tp, a0
+ li a0, 0
+ ret
diff --git a/src/thread/riscv32/__unmapself.s b/src/thread/riscv32/__unmapself.s
new file mode 100644
index 00000000..2849119c
--- /dev/null
+++ b/src/thread/riscv32/__unmapself.s
@@ -0,0 +1,7 @@
+.global __unmapself
+.type __unmapself, %function
+__unmapself:
+ li a7, 215 # SYS_munmap
+ ecall
+ li a7, 93 # SYS_exit
+ ecall
diff --git a/src/thread/riscv32/clone.s b/src/thread/riscv32/clone.s
new file mode 100644
index 00000000..e2116e33
--- /dev/null
+++ b/src/thread/riscv32/clone.s
@@ -0,0 +1,35 @@
+# __clone(func, stack, flags, arg, ptid, tls, ctid)
+# a0, a1, a2, a3, a4, a5, a6
+
+# syscall(SYS_clone, flags, stack, ptid, tls, ctid)
+# a7 a0, a1, a2, a3, a4
+
+.global __clone
+.type __clone, %function
+__clone:
+ # Save func and arg to stack
+ andi a1, a1, -16
+ addi a1, a1, -16
+ sw a0, 0(a1)
+ sw a3, 4(a1)
+
+ # Call SYS_clone
+ mv a0, a2
+ mv a2, a4
+ mv a3, a5
+ mv a4, a6
+ li a7, 220 # SYS_clone
+ ecall
+
+ beqz a0, 1f
+ # Parent
+ ret
+
+ # Child
+1: lw a1, 0(sp)
+ lw a0, 4(sp)
+ jalr a1
+
+ # Exit
+ li a7, 93 # SYS_exit
+ ecall
diff --git a/src/thread/riscv32/syscall_cp.s b/src/thread/riscv32/syscall_cp.s
new file mode 100644
index 00000000..079d1ba0
--- /dev/null
+++ b/src/thread/riscv32/syscall_cp.s
@@ -0,0 +1,29 @@
+.global __cp_begin
+.hidden __cp_begin
+.global __cp_end
+.hidden __cp_end
+.global __cp_cancel
+.hidden __cp_cancel
+.hidden __cancel
+.global __syscall_cp_asm
+.hidden __syscall_cp_asm
+.type __syscall_cp_asm, %function
+__syscall_cp_asm:
+__cp_begin:
+ lw t0, 0(a0)
+ bnez t0, __cp_cancel
+
+ mv t0, a1
+ mv a0, a2
+ mv a1, a3
+ mv a2, a4
+ mv a3, a5
+ mv a4, a6
+ mv a5, a7
+ lw a6, 0(sp)
+ mv a7, t0
+ ecall
+__cp_end:
+ ret
+__cp_cancel:
+ tail __cancel
diff --git a/src/thread/riscv64/clone.s b/src/thread/riscv64/clone.s
index db908248..0e6f41a8 100644
--- a/src/thread/riscv64/clone.s
+++ b/src/thread/riscv64/clone.s
@@ -8,6 +8,7 @@
.type __clone, %function
__clone:
# Save func and arg to stack
+ andi a1, a1, -16
addi a1, a1, -16
sd a0, 0(a1)
sd a3, 8(a1)
diff --git a/src/thread/s390x/__tls_get_offset.s b/src/thread/s390x/__tls_get_offset.s
index 8ee92de8..405f118b 100644
--- a/src/thread/s390x/__tls_get_offset.s
+++ b/src/thread/s390x/__tls_get_offset.s
@@ -1,17 +1,17 @@
.global __tls_get_offset
.type __tls_get_offset,%function
__tls_get_offset:
- stmg %r14, %r15, 112(%r15)
- aghi %r15, -160
+ ear %r0, %a0
+ sllg %r0, %r0, 32
+ ear %r0, %a1
- la %r2, 0(%r2, %r12)
- brasl %r14, __tls_get_addr
+ la %r1, 0(%r2, %r12)
- ear %r1, %a0
- sllg %r1, %r1, 32
- ear %r1, %a1
+ lg %r3, 0(%r1)
+ sllg %r4, %r3, 3
+ lg %r5, 8(%r0)
+ lg %r2, 0(%r4, %r5)
+ ag %r2, 8(%r1)
+ sgr %r2, %r0
- sgr %r2, %r1
-
- lmg %r14, %r15, 272(%r15)
br %r14
diff --git a/src/thread/sem_post.c b/src/thread/sem_post.c
index 5c2517f2..1c8f763c 100644
--- a/src/thread/sem_post.c
+++ b/src/thread/sem_post.c
@@ -16,6 +16,6 @@ int sem_post(sem_t *sem)
if (waiters <= 1)
new &= ~0x80000000;
} while (a_cas(sem->__val, val, new) != val);
- if (val<0) __wake(sem->__val, waiters>1 ? 1 : -1, priv);
+ if (val<0 || waiters) __wake(sem->__val, waiters>1 ? 1 : -1, priv);
return 0;
}
diff --git a/src/thread/synccall.c b/src/thread/synccall.c
index a6b177c0..38597254 100644
--- a/src/thread/synccall.c
+++ b/src/thread/synccall.c
@@ -11,7 +11,7 @@ weak_alias(dummy_0, __tl_unlock);
static int target_tid;
static void (*callback)(void *), *context;
-static sem_t target_sem, caller_sem;
+static sem_t target_sem, caller_sem, exit_sem;
static void dummy(void *p)
{
@@ -33,7 +33,7 @@ static void handler(int sig)
/* Inform caller we've complered the callback and wait
* for the caller to release us to return. */
sem_post(&caller_sem);
- sem_wait(&target_sem);
+ sem_wait(&exit_sem);
/* Inform caller we are returning and state is destroyable. */
sem_post(&caller_sem);
@@ -62,6 +62,7 @@ void __synccall(void (*func)(void *), void *ctx)
sem_init(&target_sem, 0, 0);
sem_init(&caller_sem, 0, 0);
+ sem_init(&exit_sem, 0, 0);
if (!libc.threads_minus_1 || __syscall(SYS_gettid) != self->tid)
goto single_threaded;
@@ -107,12 +108,13 @@ single_threaded:
/* Only release the caught threads once all threads, including the
* caller, have returned from the callback function. */
for (i=0; i<count; i++)
- sem_post(&target_sem);
+ sem_post(&exit_sem);
for (i=0; i<count; i++)
sem_wait(&caller_sem);
sem_destroy(&caller_sem);
sem_destroy(&target_sem);
+ sem_destroy(&exit_sem);
pthread_setcancelstate(cs, 0);
__tl_unlock();
diff --git a/src/time/__tz.c b/src/time/__tz.c
index c34b3eb7..54ed4cf6 100644
--- a/src/time/__tz.c
+++ b/src/time/__tz.c
@@ -24,7 +24,6 @@ weak_alias(__tzname, tzname);
static char std_name[TZNAME_MAX+1];
static char dst_name[TZNAME_MAX+1];
-const char __utc[] = "UTC";
static int dst_off;
static int r0[5], r1[5];
diff --git a/src/time/__utc.c b/src/time/__utc.c
new file mode 100644
index 00000000..9e8bfc58
--- /dev/null
+++ b/src/time/__utc.c
@@ -0,0 +1,3 @@
+#include "time_impl.h"
+
+const char __utc[] = "UTC";
diff --git a/src/time/__year_to_secs.c b/src/time/__year_to_secs.c
index 2824ec6d..b42f5a6d 100644
--- a/src/time/__year_to_secs.c
+++ b/src/time/__year_to_secs.c
@@ -10,9 +10,9 @@ long long __year_to_secs(long long year, int *is_leap)
return 31536000*(y-70) + 86400*leaps;
}
- int cycles, centuries, leaps, rem;
+ int cycles, centuries, leaps, rem, dummy;
- if (!is_leap) is_leap = &(int){0};
+ if (!is_leap) is_leap = &dummy;
cycles = (year-100) / 400;
rem = (year-100) % 400;
if (rem < 0) {
diff --git a/src/time/strftime.c b/src/time/strftime.c
index cc53d536..c40246db 100644
--- a/src/time/strftime.c
+++ b/src/time/strftime.c
@@ -3,6 +3,7 @@
#include <string.h>
#include <langinfo.h>
#include <locale.h>
+#include <ctype.h>
#include <time.h>
#include <limits.h>
#include "locale_impl.h"
@@ -233,7 +234,12 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
pad = 0;
if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
if ((plus = (*f == '+'))) f++;
- width = strtoul(f, &p, 10);
+ if (isdigit(*f)) {
+ width = strtoul(f, &p, 10);
+ } else {
+ width = 0;
+ p = (void *)f;
+ }
if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
if (!width && p!=f) width = 1;
} else {
diff --git a/src/time/strptime.c b/src/time/strptime.c
index c54a0d8c..b1147242 100644
--- a/src/time/strptime.c
+++ b/src/time/strptime.c
@@ -59,6 +59,22 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
s = strptime(s, "%m/%d/%y", tm);
if (!s) return 0;
break;
+ case 'F':
+ /* Use temp buffer to implement the odd requirement
+ * that entire field be width-limited but the year
+ * subfield not itself be limited. */
+ i = 0;
+ char tmp[20];
+ if (*s == '-' || *s == '+') tmp[i++] = *s++;
+ while (*s=='0' && isdigit(s[1])) s++;
+ for (; *s && i<(size_t)w && i+1<sizeof tmp; i++) {
+ tmp[i] = *s++;
+ }
+ tmp[i] = 0;
+ char *p = strptime(tmp, "%12Y-%m-%d", tm);
+ if (!p) return 0;
+ s -= tmp+i-p;
+ break;
case 'H':
dest = &tm->tm_hour;
min = 0;
@@ -114,6 +130,13 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
s = strptime(s, "%H:%M", tm);
if (!s) return 0;
break;
+ case 's':
+ /* Parse only. Effect on tm is unspecified
+ * and presently no effect is implemented.. */
+ if (*s == '-') s++;
+ if (!isdigit(*s)) return 0;
+ while (isdigit(*s)) s++;
+ break;
case 'S':
dest = &tm->tm_sec;
min = 0;
@@ -125,11 +148,30 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
break;
case 'U':
case 'W':
- /* Throw away result, for now. (FIXME?) */
+ /* Throw away result of %U, %V, %W, %g, and %G. Effect
+ * is unspecified and there is no clear right choice. */
dest = &dummy;
min = 0;
range = 54;
goto numeric_range;
+ case 'V':
+ dest = &dummy;
+ min = 1;
+ range = 53;
+ goto numeric_range;
+ case 'g':
+ dest = &dummy;
+ w = 2;
+ goto numeric_digits;
+ case 'G':
+ dest = &dummy;
+ if (w<0) w=4;
+ goto numeric_digits;
+ case 'u':
+ dest = &tm->tm_wday;
+ min = 1;
+ range = 7;
+ goto numeric_range;
case 'w':
dest = &tm->tm_wday;
min = 0;
@@ -154,6 +196,28 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
adj = 1900;
want_century = 0;
goto numeric_digits;
+ case 'z':
+ if (*s == '+') neg = 0;
+ else if (*s == '-') neg = 1;
+ else return 0;
+ for (i=0; i<4; i++) if (!isdigit(s[1+i])) return 0;
+ tm->__tm_gmtoff = (s[1]-'0')*36000+(s[2]-'0')*3600
+ + (s[3]-'0')*600 + (s[4]-'0')*60;
+ if (neg) tm->__tm_gmtoff = -tm->__tm_gmtoff;
+ s += 5;
+ break;
+ case 'Z':
+ if (!strncmp(s, tzname[0], len = strlen(tzname[0]))) {
+ tm->tm_isdst = 0;
+ s += len;
+ } else if (!strncmp(s, tzname[1], len=strlen(tzname[1]))) {
+ tm->tm_isdst = 1;
+ s += len;
+ } else {
+ /* FIXME: is this supposed to be an error? */
+ while ((*s|32)-'a' <= 'z'-'a') s++;
+ }
+ break;
case '%':
if (*s++ != '%') return 0;
break;
diff --git a/src/time/timer_create.c b/src/time/timer_create.c
index cd32c945..cc6c2236 100644
--- a/src/time/timer_create.c
+++ b/src/time/timer_create.c
@@ -1,6 +1,7 @@
#include <time.h>
#include <setjmp.h>
#include <limits.h>
+#include <semaphore.h>
#include "pthread_impl.h"
#include "atomic.h"
@@ -12,7 +13,7 @@ struct ksigevent {
};
struct start_args {
- pthread_barrier_t b;
+ sem_t sem1, sem2;
struct sigevent *sev;
};
@@ -21,10 +22,16 @@ static void dummy_0()
}
weak_alias(dummy_0, __pthread_tsd_run_dtors);
+static void timer_handler(int sig, siginfo_t *si, void *ctx)
+{
+}
+
static void cleanup_fromsig(void *p)
{
pthread_t self = __pthread_self();
__pthread_tsd_run_dtors();
+ __block_app_sigs(0);
+ __syscall(SYS_rt_sigprocmask, SIG_BLOCK, SIGTIMER_SET, 0, _NSIG/8);
self->cancel = 0;
self->cancelbuf = 0;
self->canceldisable = 0;
@@ -42,7 +49,14 @@ static void *start(void *arg)
void (*notify)(union sigval) = args->sev->sigev_notify_function;
union sigval val = args->sev->sigev_value;
- pthread_barrier_wait(&args->b);
+ /* The two-way semaphore synchronization ensures that we see
+ * self->cancel set by the parent if timer creation failed or
+ * self->timer_id if it succeeded, and informs the parent that
+ * we are done accessing the arguments so that the parent can
+ * proceed past their block lifetime. */
+ while (sem_wait(&args->sem1));
+ sem_post(&args->sem2);
+
if (self->cancel)
return 0;
for (;;) {
@@ -61,7 +75,7 @@ static void *start(void *arg)
int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict res)
{
- volatile static int init = 0;
+ static volatile int init = 0;
pthread_t td;
pthread_attr_t attr;
int r;
@@ -90,7 +104,10 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict
break;
case SIGEV_THREAD:
if (!init) {
- struct sigaction sa = { .sa_handler = SIG_DFL };
+ struct sigaction sa = {
+ .sa_sigaction = timer_handler,
+ .sa_flags = SA_SIGINFO | SA_RESTART
+ };
__libc_sigaction(SIGTIMER, &sa, 0);
a_store(&init, 1);
}
@@ -99,7 +116,8 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict
else
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_barrier_init(&args.b, 0, 2);
+ sem_init(&args.sem1, 0, 0);
+ sem_init(&args.sem2, 0, 0);
args.sev = evp;
__block_app_sigs(&set);
@@ -120,7 +138,8 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict
td->cancel = 1;
}
td->timer_id = timerid;
- pthread_barrier_wait(&args.b);
+ sem_post(&args.sem1);
+ while (sem_wait(&args.sem2));
if (timerid < 0) return -1;
*res = (void *)(INTPTR_MIN | (uintptr_t)td>>1);
break;
diff --git a/src/unistd/faccessat.c b/src/unistd/faccessat.c
index 557503eb..43052dd7 100644
--- a/src/unistd/faccessat.c
+++ b/src/unistd/faccessat.c
@@ -53,7 +53,7 @@ int faccessat(int fd, const char *filename, int amode, int flag)
if (pid<0 || __syscall(SYS_read, p[0], &ret, sizeof ret) != sizeof(ret))
ret = -EBUSY;
__syscall(SYS_close, p[0]);
- __syscall(SYS_wait4, pid, &status, __WCLONE, 0);
+ __sys_wait4(pid, &status, __WCLONE, 0);
__restore_sigs(&set);
diff --git a/src/unistd/isatty.c b/src/unistd/isatty.c
index 75a9c186..21222eda 100644
--- a/src/unistd/isatty.c
+++ b/src/unistd/isatty.c
@@ -6,8 +6,6 @@
int isatty(int fd)
{
struct winsize wsz;
- unsigned long r = syscall(SYS_ioctl, fd, TIOCGWINSZ, &wsz);
- if (r == 0) return 1;
- if (errno != EBADF) errno = ENOTTY;
- return 0;
+ /* +1 converts from error status (0/-1) to boolean (1/0) */
+ return syscall(SYS_ioctl, fd, TIOCGWINSZ, &wsz) + 1;
}
diff --git a/src/unistd/pause.c b/src/unistd/pause.c
index 90bbf4ca..90cc8db5 100644
--- a/src/unistd/pause.c
+++ b/src/unistd/pause.c
@@ -3,9 +3,5 @@
int pause(void)
{
-#ifdef SYS_pause
- return syscall_cp(SYS_pause);
-#else
- return syscall_cp(SYS_ppoll, 0, 0, 0, 0);
-#endif
+ return sys_pause_cp();
}
diff --git a/src/unistd/pwrite.c b/src/unistd/pwrite.c
index 869b69f0..a008b3ec 100644
--- a/src/unistd/pwrite.c
+++ b/src/unistd/pwrite.c
@@ -1,7 +1,18 @@
+#define _GNU_SOURCE
#include <unistd.h>
+#include <sys/uio.h>
+#include <fcntl.h>
#include "syscall.h"
ssize_t pwrite(int fd, const void *buf, size_t size, off_t ofs)
{
+ if (ofs == -1) ofs--;
+ int r = __syscall_cp(SYS_pwritev2, fd,
+ (&(struct iovec){ .iov_base = (void *)buf, .iov_len = size }),
+ 1, (long)(ofs), (long)(ofs>>32), RWF_NOAPPEND);
+ if (r != -EOPNOTSUPP && r != -ENOSYS)
+ return __syscall_ret(r);
+ if (fcntl(fd, F_GETFL) & O_APPEND)
+ return __syscall_ret(-EOPNOTSUPP);
return syscall_cp(SYS_pwrite, fd, buf, size, __SYSCALL_LL_PRW(ofs));
}
diff --git a/src/unistd/pwritev.c b/src/unistd/pwritev.c
index becf9deb..44a53d85 100644
--- a/src/unistd/pwritev.c
+++ b/src/unistd/pwritev.c
@@ -1,10 +1,18 @@
-#define _BSD_SOURCE
+#define _GNU_SOURCE
#include <sys/uio.h>
#include <unistd.h>
+#include <fcntl.h>
#include "syscall.h"
ssize_t pwritev(int fd, const struct iovec *iov, int count, off_t ofs)
{
+ if (ofs == -1) ofs--;
+ int r = __syscall_cp(SYS_pwritev2, fd, iov, count,
+ (long)(ofs), (long)(ofs>>32), RWF_NOAPPEND);
+ if (r != -EOPNOTSUPP && r != -ENOSYS)
+ return __syscall_ret(r);
+ if (fcntl(fd, F_GETFL) & O_APPEND)
+ return __syscall_ret(-EOPNOTSUPP);
return syscall_cp(SYS_pwritev, fd, iov, count,
(long)(ofs), (long)(ofs>>32));
}
diff --git a/src/unistd/setxid.c b/src/unistd/setxid.c
index 487c1a16..a629ed4b 100644
--- a/src/unistd/setxid.c
+++ b/src/unistd/setxid.c
@@ -30,5 +30,5 @@ int __setxid(int nr, int id, int eid, int sid)
* trigger the safety kill above. */
struct ctx c = { .nr = nr, .id = id, .eid = eid, .sid = sid, .ret = 1 };
__synccall(do_setxid, &c);
- return __syscall_ret(c.ret);
+ return __syscall_ret(c.ret > 0 ? -EAGAIN : c.ret);
}