about summary refs log tree commit diff
path: root/src/linux
diff options
context:
space:
mode:
Diffstat (limited to 'src/linux')
-rw-r--r--src/linux/cache.c3
-rw-r--r--src/linux/clone.c56
-rw-r--r--src/linux/epoll.c1
-rw-r--r--src/linux/fallocate.c3
-rw-r--r--src/linux/getdents.c2
-rw-r--r--src/linux/membarrier.c2
-rw-r--r--src/linux/ppoll.c26
-rw-r--r--src/linux/preadv2.c17
-rw-r--r--src/linux/prlimit.c3
-rw-r--r--src/linux/pwritev2.c17
-rw-r--r--src/linux/sendfile.c2
-rw-r--r--src/linux/statx.c42
-rw-r--r--src/linux/wait4.c4
13 files changed, 132 insertions, 46 deletions
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/epoll.c b/src/linux/epoll.c
index 93baa814..e56e8f4c 100644
--- a/src/linux/epoll.c
+++ b/src/linux/epoll.c
@@ -5,6 +5,7 @@
 
 int epoll_create(int size)
 {
+	if (size<=0) return __syscall_ret(-EINVAL);
 	return epoll_create1(0);
 }
 
diff --git a/src/linux/fallocate.c b/src/linux/fallocate.c
index 7d68bc8f..9146350e 100644
--- a/src/linux/fallocate.c
+++ b/src/linux/fallocate.c
@@ -7,6 +7,3 @@ int fallocate(int fd, int mode, off_t base, off_t len)
 	return syscall(SYS_fallocate, fd, mode, __SYSCALL_LL_E(base),
 		__SYSCALL_LL_E(len));
 }
-
-#undef fallocate64
-weak_alias(fallocate, fallocate64);
diff --git a/src/linux/getdents.c b/src/linux/getdents.c
index 796c1e5c..97f76e14 100644
--- a/src/linux/getdents.c
+++ b/src/linux/getdents.c
@@ -8,5 +8,3 @@ int getdents(int fd, struct dirent *buf, size_t len)
 	if (len>INT_MAX) len = INT_MAX;
 	return syscall(SYS_getdents, fd, buf, len);
 }
-
-weak_alias(getdents, getdents64);
diff --git a/src/linux/membarrier.c b/src/linux/membarrier.c
index 343f7360..f64fe7e1 100644
--- a/src/linux/membarrier.c
+++ b/src/linux/membarrier.c
@@ -35,7 +35,7 @@ int __membarrier(int cmd, int flags)
 		__tl_lock();
 		sem_init(&barrier_sem, 0, 0);
 		struct sigaction sa = {
-			.sa_flags = SA_RESTART,
+			.sa_flags = SA_RESTART | SA_ONSTACK,
 			.sa_handler = bcast_barrier
 		};
 		memset(&sa.sa_mask, -1, sizeof sa.sa_mask);
diff --git a/src/linux/ppoll.c b/src/linux/ppoll.c
deleted file mode 100644
index e614600a..00000000
--- a/src/linux/ppoll.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#define _GNU_SOURCE
-#include <poll.h>
-#include <signal.h>
-#include <errno.h>
-#include "syscall.h"
-
-#define IS32BIT(x) !((x)+0x80000000ULL>>32)
-#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
-
-int ppoll(struct pollfd *fds, nfds_t n, const struct timespec *to, const sigset_t *mask)
-{
-	time_t s = to ? to->tv_sec : 0;
-	long ns = to ? to->tv_nsec : 0;
-#ifdef SYS_ppoll_time64
-	int r = -ENOSYS;
-	if (SYS_ppoll == SYS_ppoll_time64 || !IS32BIT(s))
-		r = __syscall_cp(SYS_ppoll_time64, fds, n,
-			to ? ((long long[]){s, ns}) : 0,
-			mask, _NSIG/8);
-	if (SYS_ppoll == SYS_ppoll_time64 || r != -ENOSYS)
-		return __syscall_ret(r);
-	s = CLAMP(s);
-#endif
-	return syscall_cp(SYS_ppoll, fds, n,
-		to ? ((long[]){s, ns}) : 0, mask, _NSIG/8);
-}
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/prlimit.c b/src/linux/prlimit.c
index 3df9ffba..fcf45aab 100644
--- a/src/linux/prlimit.c
+++ b/src/linux/prlimit.c
@@ -21,6 +21,3 @@ int prlimit(pid_t pid, int resource, const struct rlimit *new_limit, struct rlim
 	}
 	return r;
 }
-
-#undef prlimit64
-weak_alias(prlimit, prlimit64);
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/sendfile.c b/src/linux/sendfile.c
index 9afe6dd6..fc1577d3 100644
--- a/src/linux/sendfile.c
+++ b/src/linux/sendfile.c
@@ -5,5 +5,3 @@ ssize_t sendfile(int out_fd, int in_fd, off_t *ofs, size_t count)
 {
 	return syscall(SYS_sendfile, out_fd, in_fd, ofs, count);
 }
-
-weak_alias(sendfile, sendfile64);
diff --git a/src/linux/statx.c b/src/linux/statx.c
new file mode 100644
index 00000000..4616bff4
--- /dev/null
+++ b/src/linux/statx.c
@@ -0,0 +1,42 @@
+#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->stx_dev_major = major(st.st_dev);
+	stx->stx_dev_minor = minor(st.st_dev);
+	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_btime = (struct statx_timestamp){.tv_sec=0, .tv_nsec=0};
+	stx->stx_mask = STATX_BASIC_STATS;
+
+	return 0;
+}
diff --git a/src/linux/wait4.c b/src/linux/wait4.c
index 83650e34..fb08c0d0 100644
--- a/src/linux/wait4.c
+++ b/src/linux/wait4.c
@@ -12,7 +12,7 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru)
 	if (ru) {
 		long long kru64[18];
 		r = __syscall(SYS_wait4_time64, pid, status, options, kru64);
-		if (!r) {
+		if (r > 0) {
 			ru->ru_utime = (struct timeval)
 				{ .tv_sec = kru64[0], .tv_usec = kru64[1] };
 			ru->ru_stime = (struct timeval)
@@ -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));