[klibc] Support for pselect, ppoll, sync_file_range, splice, tee

New system call bonanza.  Defined splice() and tee() in <sys/splice.h>;
sync_file_range() in <unistd.h>, pselect() in <sys/select.h> (per POSIX)
and ppoll in <sys/poll.h>.  Make <poll.h> -> <sys/poll.h>.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
diff --git a/include/poll.h b/include/poll.h
index 8710d92..06fb41a 100644
--- a/include/poll.h
+++ b/include/poll.h
@@ -1,16 +1 @@
-/*
- * poll.h
- */
-
-#ifndef _POLL_H
-#define _POLL_H
-
-#include <klibc/extern.h>
-#include <linux/poll.h>
-
-/* POSIX specifies "int" for the timeout, Linux seems to use long... */
-
-typedef unsigned int nfds_t;
-__extern int poll(struct pollfd *, nfds_t, long);
-
-#endif /* _POLL_H */
+#include <sys/poll.h>
diff --git a/include/sys/poll.h b/include/sys/poll.h
new file mode 100644
index 0000000..56feade
--- /dev/null
+++ b/include/sys/poll.h
@@ -0,0 +1,20 @@
+/*
+ * poll.h
+ */
+
+#ifndef _POLL_H
+#define _POLL_H
+
+#include <klibc/extern.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <linux/poll.h>
+
+/* POSIX specifies "int" for the timeout, Linux seems to use long... */
+
+typedef unsigned int nfds_t;
+__extern int poll(struct pollfd *, nfds_t, long);
+__extern int ppoll(struct pollfd *, nfds_t, struct timespec *,
+		   const sigset_t *);
+
+#endif /* _POLL_H */
diff --git a/include/sys/select.h b/include/sys/select.h
index 361a1a5..5a7dcf7 100644
--- a/include/sys/select.h
+++ b/include/sys/select.h
@@ -8,7 +8,10 @@
 #include <klibc/extern.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <signal.h>
 
 __extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+__extern int pselect(int, fd_set *, fd_set *, fd_set *,
+		     const struct timespec *, const sigset_t *);
 
 #endif /* _SYS_SELECT_H */
diff --git a/include/sys/splice.h b/include/sys/splice.h
new file mode 100644
index 0000000..5f30982
--- /dev/null
+++ b/include/sys/splice.h
@@ -0,0 +1,19 @@
+/*
+ * sys/splice.h
+ */
+
+#ifndef _SYS_SPLICE_H
+#define _SYS_SPLICE_H
+
+/* move pages instead of copying */
+#define SPLICE_F_MOVE		1
+/* don't block on the pipe splicing (but we may still block on the fd
+   we splice from/to, of course */
+#define SPLICE_F_NONBLOCK	2
+/* expect more data */
+#define SPLICE_F_MORE		4
+
+__extern int splice(int, off_t *, int, off_t *, size_t, unsigned int);
+__extern int tee(int, int, size_t, unsigned int);
+
+#endif /* _SYS_SPLICE_H */
diff --git a/include/unistd.h b/include/unistd.h
index d0f9392..ceb97fc 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -81,8 +81,6 @@
 __extern int lchown(const char *, uid_t, gid_t);
 __extern char *getcwd(char *, size_t);
 
-__extern int sync(void);
-
 /* Also in <fcntl.h> */
 #ifndef _KLIBC_IN_OPEN_C
 __extern int open(const char *, int, ...);
@@ -105,9 +103,19 @@
 __extern int fcntl(int, int, ...);
 __extern int ioctl(int, int, void *);
 __extern int flock(int, int);
+__extern int ftruncate(int, off_t);
+
+/*
+ * Macros for sync_file_range()
+ */
+#define SYNC_FILE_RANGE_WAIT_BEFORE     1
+#define SYNC_FILE_RANGE_WRITE           2
+#define SYNC_FILE_RANGE_WAIT_AFTER      4
+
+__extern int sync(void);
 __extern int fsync(int);
 __extern int fdatasync(int);
-__extern int ftruncate(int, off_t);
+__extern int sync_file_range(int, off_t, off_t, unsigned int);
 
 __extern int pause(void);
 __extern unsigned int alarm(unsigned int);
diff --git a/klibc/Kbuild b/klibc/Kbuild
index fb50a1c..c324909 100644
--- a/klibc/Kbuild
+++ b/klibc/Kbuild
@@ -25,6 +25,7 @@
 	  __signal.o sysv_signal.o bsd_signal.o siglist.o sigabbrev.o \
 	  siglongjmp.o \
 	  sigaction.o sigpending.o sigprocmask.o sigsuspend.o \
+	  pselect.o ppoll.o \
 	  brk.o sbrk.o malloc.o realloc.o calloc.o mmap.o \
 	  memcpy.o memcmp.o memset.o memccpy.o memmem.o memswap.o \
 	  memmove.o memchr.o memrchr.o \
diff --git a/klibc/SYSCALLS.def b/klibc/SYSCALLS.def
index b7d0daf..89c0550 100644
--- a/klibc/SYSCALLS.def
+++ b/klibc/SYSCALLS.def
@@ -155,7 +155,15 @@
 int ioctl(int, int, void *)
 int flock(int, int)
 int _newselect,select::select(int, fd_set *, fd_set *, fd_set *, struct timeval *)
+#if defined(__NR_pselect) && !_KLIBC_USE_RT_SIG
+int pselect(int, fd_set *, fd_set *, fd_set *, const struct timespec *, const sigset_t *)
+#elif defined(__NR_pselect7)
+int pselect7::__pselect7(int, fd_set *, fd_set *, fd_set *, struct timespec *, const sigset_t *, size_t)
+#elif defined(__NR_pselect6)
+int pselect6::__pselect6(int, fd_set *, fd_set *, fd_set *, struct timespec *, const struct __pselect6 *)
+#endif
 int poll(struct pollfd *, nfds_t, long)
+<?> int ppoll::__ppoll(struct pollfd *, nfds_t, struct timespec *, const sigset_t *, size_t)
 int fsync(int)
 int fdatasync,fsync::fdatasync(int)
 int readv(int, const struct iovec *, int)
@@ -163,6 +171,9 @@
 int ftruncate64,ftruncate::ftruncate(int, off_t)
 ssize_t pread64,pread::pread(int, void *, size_t, off_t)
 ssize_t pwrite64,pwrite::pwrite(int, void *, size_t, off_t)
+int sync_file_range,fdatasync,fsync::sync_file_range(int, off_t, off_t, unsigned int)
+<?> int splice(int, off_t *, int, off_t *, size_t, unsigned int)
+<?> int tee(int, int, size_t, unsigned int)
 
 ;
 ; Signal operations
diff --git a/klibc/ppoll.c b/klibc/ppoll.c
new file mode 100644
index 0000000..f314be6
--- /dev/null
+++ b/klibc/ppoll.c
@@ -0,0 +1,14 @@
+/*
+ * ppoll.c
+ */
+
+#include <sys/poll.h>
+
+__extern int __ppoll(struct pollfd *, nfds_t, struct timespec *,
+		     const sigset_t *, size_t);
+
+int ppoll(struct pollfd *ufds, nfds_t nfds, struct timespec *timeout,
+	  const sigset_t *sigmask)
+{
+  return __ppoll(ufds, nfds, timeout, sigmask, sizeof *sigmask);
+}
diff --git a/klibc/pselect.c b/klibc/pselect.c
new file mode 100644
index 0000000..5266501
--- /dev/null
+++ b/klibc/pselect.c
@@ -0,0 +1,40 @@
+/*
+ * pselect.c
+ */
+
+#include <sys/select.h>
+#include <sys/syscall.h>
+
+#if defined(__NR_pselect) && !_KLIBC_USE_RT_SIG
+
+/* Don't need to do anything here; use syscall stub directly */
+
+#elif defined(__NR_pselect7)
+
+__extern int __pselect7(int, fd_set *, fd_set *, fd_set *, const struct timespec *, const sigset_t *, size_t);
+
+int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+	    const struct timespec *timeout, const sigset_t *sigmask)
+{
+  return __pselect7(n, readfds, writefds, exceptfds,
+		    timeout, sigmask, sizeof *sigmask);
+}
+
+#else
+
+struct __pselect6 {
+  const sigset_t *sigmask;
+  size_t sigsize;
+};
+
+__extern int __pselect6(int, fd_set *, fd_set *, fd_set *, const struct timespec *, const struct __pselect6 *);
+
+int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+	    const struct timespec *timeout, const sigset_t *sigmask)
+{
+  struct __pselect6 extended_sigmask = { sigmask, sizeof *sigmask };
+  return __pselect6(n, readfds, writefds, exceptfds,
+		    timeout, &extended_sigmask);
+}
+
+#endif