svn commit: r320043 - in head: contrib/netbsd-tests/kernel/kqueue lib/libc/include lib/libc/sys sys/compat/freebsd32 sys/kern sys/sys tests/sys/kqueue/libkqueue usr.bin/truss

Konstantin Belousov kib at FreeBSD.org
Sat Jun 17 00:57:28 UTC 2017


Author: kib
Date: Sat Jun 17 00:57:26 2017
New Revision: 320043
URL: https://svnweb.freebsd.org/changeset/base/320043

Log:
  Add abstime kqueue(2) timers and expand struct kevent members.
  
  This change implements NOTE_ABSTIME flag for EVFILT_TIMER, which
  specifies that the data field contains absolute time to fire the
  event.
  
  To make this useful, data member of the struct kevent must be extended
  to 64bit.  Using the opportunity, I also added ext members.  This
  changes struct kevent almost to Apple struct kevent64, except I did
  not changed type of ident and udata, the later would cause serious API
  incompatibilities.
  
  The type of ident was kept uintptr_t since EVFILT_AIO returns a
  pointer in this field, and e.g. CHERI is sensitive to the type
  (discussed with brooks, jhb).
  
  Unlike Apple kevent64, symbol versioning allows us to claim ABI
  compatibility and still name the new syscall kevent(2).  Compat shims
  are provided for both host native and compat32.
  
  Requested by:	bapt
  Reviewed by:	bapt, brooks, ngie (previous version)
  Sponsored by:	The FreeBSD Foundation
  Differential revision:	https://reviews.freebsd.org/D11025

Modified:
  head/contrib/netbsd-tests/kernel/kqueue/t_proc1.c
  head/contrib/netbsd-tests/kernel/kqueue/t_sig.c
  head/lib/libc/include/compat.h
  head/lib/libc/sys/Symbol.map
  head/lib/libc/sys/kqueue.2
  head/sys/compat/freebsd32/freebsd32.h
  head/sys/compat/freebsd32/freebsd32_misc.c
  head/sys/compat/freebsd32/syscalls.master
  head/sys/kern/kern_event.c
  head/sys/kern/syscalls.master
  head/sys/kern/vfs_aio.c
  head/sys/sys/event.h
  head/tests/sys/kqueue/libkqueue/main.c
  head/tests/sys/kqueue/libkqueue/timer.c
  head/usr.bin/truss/syscalls.c

Modified: head/contrib/netbsd-tests/kernel/kqueue/t_proc1.c
==============================================================================
--- head/contrib/netbsd-tests/kernel/kqueue/t_proc1.c	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/contrib/netbsd-tests/kernel/kqueue/t_proc1.c	Sat Jun 17 00:57:26 2017	(r320043)
@@ -139,11 +139,7 @@ ATF_TC_BODY(proc1, tc)
 			printf(" NOTE_FORK");
 		}
 		if (event[0].fflags & NOTE_CHILD)
-#ifdef __FreeBSD__
-			printf(" NOTE_CHILD, parent = %" PRIdPTR, event[0].data);
-#else
 			printf(" NOTE_CHILD, parent = %" PRId64, event[0].data);
-#endif
 
 		printf("\n");
 	}

Modified: head/contrib/netbsd-tests/kernel/kqueue/t_sig.c
==============================================================================
--- head/contrib/netbsd-tests/kernel/kqueue/t_sig.c	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/contrib/netbsd-tests/kernel/kqueue/t_sig.c	Sat Jun 17 00:57:26 2017	(r320043)
@@ -127,11 +127,7 @@ ATF_TC_BODY(sig, tc)
 		if (n == 0)
 			continue;
 
-#ifdef __FreeBSD__
-		(void)printf("sig: kevent flags: 0x%x, data: %" PRIdPTR " (# "
-#else
 		(void)printf("sig: kevent flags: 0x%x, data: %" PRId64 " (# "
-#endif
 		    "times signal posted)\n", event[0].flags, event[0].data);
 	}
 

Modified: head/lib/libc/include/compat.h
==============================================================================
--- head/lib/libc/include/compat.h	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/lib/libc/include/compat.h	Sat Jun 17 00:57:26 2017	(r320043)
@@ -65,6 +65,8 @@ __sym_compat(statfs, freebsd11_statfs, FBSD_1.0);
 __sym_compat(mknod, freebsd11_mknod, FBSD_1.0);
 __sym_compat(mknodat, freebsd11_mknodat, FBSD_1.1);
 
+__sym_compat(kevent, freebsd11_kevent, FBSD_1.0);
+
 #undef __sym_compat
 
 #define	__weak_reference(sym,alias)	\

Modified: head/lib/libc/sys/Symbol.map
==============================================================================
--- head/lib/libc/sys/Symbol.map	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/lib/libc/sys/Symbol.map	Sat Jun 17 00:57:26 2017	(r320043)
@@ -121,7 +121,6 @@ FBSD_1.0 {
 	jail;
 	jail_attach;
 	kenv;
-	kevent;
 	kill;
 	kldfind;
 	kldfirstmod;
@@ -393,6 +392,7 @@ FBSD_1.5 {
 	getdents;
 	getdirentries;
 	getfsstat;
+	kevent;
 	lstat;
 	mknod;
 	mknodat;

Modified: head/lib/libc/sys/kqueue.2
==============================================================================
--- head/lib/libc/sys/kqueue.2	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/lib/libc/sys/kqueue.2	Sat Jun 17 00:57:26 2017	(r320043)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 18, 2017
+.Dd June 17, 2017
 .Dt KQUEUE 2
 .Os
 .Sh NAME
@@ -148,12 +148,13 @@ The
 structure is defined as:
 .Bd -literal
 struct kevent {
-	uintptr_t ident;	/* identifier for this event */
+	uintptr_t  ident;	/* identifier for this event */
 	short	  filter;	/* filter for event */
 	u_short	  flags;	/* action flags for kqueue */
 	u_int	  fflags;	/* filter flag value */
-	intptr_t  data;		/* filter data value */
+	int64_t   data;		/* filter data value */
 	void	  *udata;	/* opaque user data identifier */
+	uint64_t  ext[4];	/* extentions */
 };
 .Ed
 .Pp
@@ -177,6 +178,20 @@ Filter-specific flags.
 Filter-specific data value.
 .It Fa udata
 Opaque user-defined value passed through the kernel unchanged.
+.It Fa ext
+Extended data passed to and from kernel.
+The
+.Fa ext[0]
+and
+.Fa ext[1]
+members use is defined by the filter.
+If the filter does not use them, the members are copied unchanged.
+The
+.Fa ext[2]
+and
+.Fa ext[3]
+members are always passed throught the kernel as-is,
+making additional context available to application.
 .El
 .Pp
 The
@@ -515,16 +530,26 @@ Establishes an arbitrary timer identified by
 .Va ident .
 When adding a timer,
 .Va data
-specifies the timeout period.
+specifies the moment to fire the timer (for
+.Dv NOTE_ABSTIME )
+or the timeout period.
 The timer will be periodic unless
 .Dv EV_ONESHOT
+or
+.Dv NOTE_ABSTIME
 is specified.
 On return,
 .Va data
 contains the number of times the timeout has expired since the last call to
 .Fn kevent .
-This filter automatically sets the EV_CLEAR flag internally.
-.Bl -tag -width "Dv NOTE_USECONDS"
+For non-monotonic timers, this filter automatically sets the
+.Dv EV_CLEAR
+flag internally.
+.Pp
+The filter accepts the following flags in the
+.Va fflags
+argument:
+.Bl -tag -width "Dv NOTE_MSECONDS"
 .It Dv NOTE_SECONDS
 .Va data
 is in seconds.
@@ -537,6 +562,8 @@ is in microseconds.
 .It Dv NOTE_NSECONDS
 .Va data
 is in nanoseconds.
+.It Dv NOTE_ABSTIME
+The specified expiration time is absolute.
 .El
 .Pp
 If

Modified: head/sys/compat/freebsd32/freebsd32.h
==============================================================================
--- head/sys/compat/freebsd32/freebsd32.h	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/sys/compat/freebsd32/freebsd32.h	Sat Jun 17 00:57:26 2017	(r320043)
@@ -137,12 +137,13 @@ struct statfs32 {
 };
 
 struct kevent32 {
-	u_int32_t	ident;		/* identifier for this event */
+	uint32_t	ident;		/* identifier for this event */
 	short		filter;		/* filter for event */
 	u_short		flags;
 	u_int		fflags;
-	int32_t		data;
-	u_int32_t	udata;		/* opaque user data identifier */
+	int32_t		data1, data2;
+	uint32_t	udata;		/* opaque user data identifier */
+	uint32_t	ext64[8];
 };
 
 struct iovec32 {

Modified: head/sys/compat/freebsd32/freebsd32_misc.c
==============================================================================
--- head/sys/compat/freebsd32/freebsd32_misc.c	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/sys/compat/freebsd32/freebsd32_misc.c	Sat Jun 17 00:57:26 2017	(r320043)
@@ -119,7 +119,7 @@ CTASSERT(sizeof(struct statfs32) == 256);
 CTASSERT(sizeof(struct rusage32) == 72);
 #endif
 CTASSERT(sizeof(struct sigaltstack32) == 12);
-CTASSERT(sizeof(struct kevent32) == 20);
+CTASSERT(sizeof(struct kevent32) == 56);
 CTASSERT(sizeof(struct iovec32) == 8);
 CTASSERT(sizeof(struct msghdr32) == 28);
 #ifdef __amd64__
@@ -622,7 +622,8 @@ freebsd32_kevent_copyout(void *arg, struct kevent *kev
 {
 	struct freebsd32_kevent_args *uap;
 	struct kevent32	ks32[KQ_NEVENTS];
-	int i, error = 0;
+	uint64_t e;
+	int i, j, error;
 
 	KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
 	uap = (struct freebsd32_kevent_args *)arg;
@@ -632,8 +633,24 @@ freebsd32_kevent_copyout(void *arg, struct kevent *kev
 		CP(kevp[i], ks32[i], filter);
 		CP(kevp[i], ks32[i], flags);
 		CP(kevp[i], ks32[i], fflags);
-		CP(kevp[i], ks32[i], data);
+#if BYTE_ORDER == LITTLE_ENDIAN
+		ks32[i].data1 = kevp[i].data;
+		ks32[i].data2 = kevp[i].data >> 32;
+#else
+		ks32[i].data1 = kevp[i].data >> 32;
+		ks32[i].data2 = kevp[i].data;
+#endif
 		PTROUT_CP(kevp[i], ks32[i], udata);
+		for (j = 0; j < nitems(kevp->ext); j++) {
+			e = kevp[i].ext[j];
+#if BYTE_ORDER == LITTLE_ENDIAN
+			ks32[i].ext64[2 * j] = e;
+			ks32[i].ext64[2 * j + 1] = e >> 32;
+#else
+			ks32[i].ext64[2 * j] = e >> 32;
+			ks32[i].ext64[2 * j + 1] = e;
+#endif
+		}
 	}
 	error = copyout(ks32, uap->eventlist, count * sizeof *ks32);
 	if (error == 0)
@@ -649,7 +666,8 @@ freebsd32_kevent_copyin(void *arg, struct kevent *kevp
 {
 	struct freebsd32_kevent_args *uap;
 	struct kevent32	ks32[KQ_NEVENTS];
-	int i, error = 0;
+	uint64_t e;
+	int i, j, error;
 
 	KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
 	uap = (struct freebsd32_kevent_args *)arg;
@@ -664,8 +682,20 @@ freebsd32_kevent_copyin(void *arg, struct kevent *kevp
 		CP(ks32[i], kevp[i], filter);
 		CP(ks32[i], kevp[i], flags);
 		CP(ks32[i], kevp[i], fflags);
-		CP(ks32[i], kevp[i], data);
+		kevp[i].data = PAIR32TO64(uint64_t, ks32[i].data);
 		PTRIN_CP(ks32[i], kevp[i], udata);
+		for (j = 0; j < nitems(kevp->ext); j++) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+			e = ks32[i].ext64[2 * j + 1];
+			e <<= 32;
+			e += ks32[i].ext64[2 * j];
+#else
+			e = ks32[i].ext64[2 * j];
+			e <<= 32;
+			e += ks32[i].ext64[2 * j + 1];
+#endif
+			kevp[i].ext[j] = e;
+		}
 	}
 done:
 	return (error);
@@ -683,7 +713,99 @@ freebsd32_kevent(struct thread *td, struct freebsd32_k
 	};
 	int error;
 
+	if (uap->timeout) {
+		error = copyin(uap->timeout, &ts32, sizeof(ts32));
+		if (error)
+			return (error);
+		CP(ts32, ts, tv_sec);
+		CP(ts32, ts, tv_nsec);
+		tsp = &ts;
+	} else
+		tsp = NULL;
+	error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents,
+	    &k_ops, tsp);
+	return (error);
+}
 
+#ifdef COMPAT_FREEBSD11
+struct kevent32_freebsd11 {
+	u_int32_t	ident;		/* identifier for this event */
+	short		filter;		/* filter for event */
+	u_short		flags;
+	u_int		fflags;
+	int32_t		data;
+	u_int32_t	udata;		/* opaque user data identifier */
+};
+
+static int
+freebsd32_kevent11_copyout(void *arg, struct kevent *kevp, int count)
+{
+	struct freebsd11_freebsd32_kevent_args *uap;
+	struct kevent32_freebsd11 ks32[KQ_NEVENTS];
+	int i, error;
+
+	KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
+	uap = (struct freebsd11_freebsd32_kevent_args *)arg;
+
+	for (i = 0; i < count; i++) {
+		CP(kevp[i], ks32[i], ident);
+		CP(kevp[i], ks32[i], filter);
+		CP(kevp[i], ks32[i], flags);
+		CP(kevp[i], ks32[i], fflags);
+		CP(kevp[i], ks32[i], data);
+		PTROUT_CP(kevp[i], ks32[i], udata);
+	}
+	error = copyout(ks32, uap->eventlist, count * sizeof *ks32);
+	if (error == 0)
+		uap->eventlist += count;
+	return (error);
+}
+
+/*
+ * Copy 'count' items from the list pointed to by uap->changelist.
+ */
+static int
+freebsd32_kevent11_copyin(void *arg, struct kevent *kevp, int count)
+{
+	struct freebsd11_freebsd32_kevent_args *uap;
+	struct kevent32_freebsd11 ks32[KQ_NEVENTS];
+	int i, j, error;
+
+	KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
+	uap = (struct freebsd11_freebsd32_kevent_args *)arg;
+
+	error = copyin(uap->changelist, ks32, count * sizeof *ks32);
+	if (error)
+		goto done;
+	uap->changelist += count;
+
+	for (i = 0; i < count; i++) {
+		CP(ks32[i], kevp[i], ident);
+		CP(ks32[i], kevp[i], filter);
+		CP(ks32[i], kevp[i], flags);
+		CP(ks32[i], kevp[i], fflags);
+		CP(ks32[i], kevp[i], data);
+		PTRIN_CP(ks32[i], kevp[i], udata);
+		for (j = 0; j < nitems(kevp->ext); j++)
+			kevp[i].ext[j] = 0;
+	}
+done:
+	return (error);
+}
+
+int
+freebsd11_freebsd32_kevent(struct thread *td,
+    struct freebsd11_freebsd32_kevent_args *uap)
+{
+	struct timespec32 ts32;
+	struct timespec ts, *tsp;
+	struct kevent_copyops k_ops = {
+		.arg = uap,
+		.k_copyout = freebsd32_kevent11_copyout,
+		.k_copyin = freebsd32_kevent11_copyin,
+	};
+	int error;
+
 	if (uap->timeout) {
 		error = copyin(uap->timeout, &ts32, sizeof(ts32));
 		if (error)
@@ -697,6 +819,7 @@ freebsd32_kevent(struct thread *td, struct freebsd32_k
 	    &k_ops, tsp);
 	return (error);
 }
+#endif
 
 int
 freebsd32_gettimeofday(struct thread *td,

Modified: head/sys/compat/freebsd32/syscalls.master
==============================================================================
--- head/sys/compat/freebsd32/syscalls.master	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/sys/compat/freebsd32/syscalls.master	Sat Jun 17 00:57:26 2017	(r320043)
@@ -667,10 +667,12 @@
 361	AUE_GETRESGID	NOPROTO	{ int getresgid(gid_t *rgid, gid_t *egid, \
 				    gid_t *sgid); }
 362	AUE_KQUEUE	NOPROTO	{ int kqueue(void); }
-363	AUE_KEVENT	STD	{ int freebsd32_kevent(int fd, \
-				    const struct kevent32 *changelist, \
+363	AUE_KEVENT	COMPAT11 { int freebsd32_kevent(int fd, \
+				    const struct kevent32_freebsd11 * \
+				    changelist, \
 				    int nchanges, \
-				    struct kevent32 *eventlist, int nevents, \
+				    struct kevent32_freebsd11 *eventlist, \
+				    int nevents, \
 				    const struct timespec32 *timeout); }
 364	AUE_NULL	UNIMPL	__cap_get_proc
 365	AUE_NULL	UNIMPL	__cap_set_proc
@@ -1111,3 +1113,9 @@
 				    struct statfs32 *buf); }
 559	AUE_MKNODAT	NOPROTO	{ int mknodat(int fd, char *path, mode_t mode, \
 				    dev_t dev); }
+560	AUE_KEVENT	STD	{ int freebsd32_kevent(int fd, \
+				    const struct kevent32 *changelist, \
+				    int nchanges, \
+				    struct kevent32 *eventlist, \
+				    int nevents, \
+				    const struct timespec32 *timeout); }

Modified: head/sys/kern/kern_event.c
==============================================================================
--- head/sys/kern/kern_event.c	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/sys/kern/kern_event.c	Sat Jun 17 00:57:26 2017	(r320043)
@@ -29,6 +29,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_compat.h"
 #include "opt_ktrace.h"
 #include "opt_kqueue.h"
 
@@ -111,6 +112,10 @@ static int	kqueue_scan(struct kqueue *kq, int maxevent
 static void 	kqueue_wakeup(struct kqueue *kq);
 static struct filterops *kqueue_fo_find(int filt);
 static void	kqueue_fo_release(int filt);
+struct g_kevent_args;
+static int	kern_kevent_generic(struct thread *td,
+		    struct g_kevent_args *uap,
+		    struct kevent_copyops *k_ops);
 
 static fo_ioctl_t	kqueue_ioctl;
 static fo_poll_t	kqueue_poll;
@@ -663,7 +668,7 @@ timer2sbintime(intptr_t data, int flags)
 struct kq_timer_cb_data {
 	struct callout c;
 	sbintime_t next;	/* next timer event fires at */
-	sbintime_t to;		/* precalculated timer period */
+	sbintime_t to;		/* precalculated timer period, 0 for abs */
 };
 
 static void
@@ -678,8 +683,9 @@ filt_timerexpire(void *knx)
 
 	if ((kn->kn_flags & EV_ONESHOT) != 0)
 		return;
-
 	kc = kn->kn_ptr.p_v;
+	if (kc->to == 0)
+		return;
 	kc->next += kc->to;
 	callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
 	    PCPU_GET(cpuid), C_ABSOLUTE);
@@ -692,7 +698,8 @@ static int
 filt_timerattach(struct knote *kn)
 {
 	struct kq_timer_cb_data *kc;
-	sbintime_t to;
+	struct bintime bt;
+	sbintime_t to, sbt;
 	unsigned int ncallouts;
 
 	if (kn->kn_sdata < 0)
@@ -700,10 +707,15 @@ filt_timerattach(struct knote *kn)
 	if (kn->kn_sdata == 0 && (kn->kn_flags & EV_ONESHOT) == 0)
 		kn->kn_sdata = 1;
 	/* Only precision unit are supported in flags so far */
-	if ((kn->kn_sfflags & ~NOTE_TIMER_PRECMASK) != 0)
+	if ((kn->kn_sfflags & ~(NOTE_TIMER_PRECMASK | NOTE_ABSTIME)) != 0)
 		return (EINVAL);
 
 	to = timer2sbintime(kn->kn_sdata, kn->kn_sfflags);
+	if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) {
+		getboottimebin(&bt);
+		sbt = bttosbt(bt);
+		to -= sbt;
+	}
 	if (to < 0)
 		return (EINVAL);
 
@@ -713,12 +725,18 @@ filt_timerattach(struct knote *kn)
 			return (ENOMEM);
 	} while (!atomic_cmpset_int(&kq_ncallouts, ncallouts, ncallouts + 1));
 
-	kn->kn_flags |= EV_CLEAR;		/* automatically set */
+	if ((kn->kn_sfflags & NOTE_ABSTIME) == 0)
+		kn->kn_flags |= EV_CLEAR;	/* automatically set */
 	kn->kn_status &= ~KN_DETACHED;		/* knlist_add clears it */
 	kn->kn_ptr.p_v = kc = malloc(sizeof(*kc), M_KQUEUE, M_WAITOK);
 	callout_init(&kc->c, 1);
-	kc->next = to + sbinuptime();
-	kc->to = to;
+	if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) {
+		kc->next = to;
+		kc->to = 0;
+	} else {
+		kc->next = to + sbinuptime();
+		kc->to = to;
+	}
 	callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
 	    PCPU_GET(cpuid), C_ABSOLUTE);
 
@@ -890,34 +908,42 @@ kern_kqueue(struct thread *td, int flags, struct filec
 
 #ifdef KTRACE
 static size_t
-kev_iovlen(int n, u_int kgio)
+kev_iovlen(int n, u_int kgio, size_t kevent_size)
 {
 
-	if (n < 0 || n >= kgio / sizeof(struct kevent))
+	if (n < 0 || n >= kgio / kevent_size)
 		return (kgio);
-	return (n * sizeof(struct kevent));
+	return (n * kevent_size);
 }
 #endif
 
-#ifndef _SYS_SYSPROTO_H_
-struct kevent_args {
+struct g_kevent_args {
 	int	fd;
-	const struct kevent *changelist;
+	void	*changelist;
 	int	nchanges;
-	struct	kevent *eventlist;
+	void	*eventlist;
 	int	nevents;
 	const struct timespec *timeout;
 };
-#endif
+
 int
 sys_kevent(struct thread *td, struct kevent_args *uap)
 {
-	struct timespec ts, *tsp;
 	struct kevent_copyops k_ops = {
 		.arg = uap,
 		.k_copyout = kevent_copyout,
 		.k_copyin = kevent_copyin,
+		.kevent_size = sizeof(struct kevent),
 	};
+
+	return (kern_kevent_generic(td, (struct g_kevent_args *)uap, &k_ops));
+}
+
+static int
+kern_kevent_generic(struct thread *td, struct g_kevent_args *uap,
+    struct kevent_copyops *k_ops)
+{
+	struct timespec ts, *tsp;
 	int error;
 #ifdef KTRACE
 	struct uio ktruio;
@@ -939,26 +965,30 @@ sys_kevent(struct thread *td, struct kevent_args *uap)
 	if (KTRPOINT(td, KTR_GENIO)) {
 		kgio = ktr_geniosize;
 		ktriov.iov_base = uap->changelist;
-		ktriov.iov_len = kev_iovlen(uap->nchanges, kgio);
+		ktriov.iov_len = kev_iovlen(uap->nchanges, kgio,
+		    k_ops->kevent_size);
 		ktruio = (struct uio){ .uio_iov = &ktriov, .uio_iovcnt = 1,
 		    .uio_segflg = UIO_USERSPACE, .uio_rw = UIO_READ,
 		    .uio_td = td };
 		ktruioin = cloneuio(&ktruio);
 		ktriov.iov_base = uap->eventlist;
-		ktriov.iov_len = kev_iovlen(uap->nevents, kgio);
-		ktriov.iov_len = uap->nevents * sizeof(struct kevent);
+		ktriov.iov_len = kev_iovlen(uap->nevents, kgio,
+		    k_ops->kevent_size);
+		ktriov.iov_len = uap->nevents * k_ops->kevent_size;
 		ktruioout = cloneuio(&ktruio);
 	}
 #endif
 
 	error = kern_kevent(td, uap->fd, uap->nchanges, uap->nevents,
-	    &k_ops, tsp);
+	    k_ops, tsp);
 
 #ifdef KTRACE
 	if (ktruioin != NULL) {
-		ktruioin->uio_resid = kev_iovlen(uap->nchanges, kgio);
+		ktruioin->uio_resid = kev_iovlen(uap->nchanges, kgio,
+		    k_ops->kevent_size);
 		ktrgenio(uap->fd, UIO_WRITE, ktruioin, 0);
-		ktruioout->uio_resid = kev_iovlen(td->td_retval[0], kgio);
+		ktruioout->uio_resid = kev_iovlen(td->td_retval[0], kgio,
+		    k_ops->kevent_size);
 		ktrgenio(uap->fd, UIO_READ, ktruioout, error);
 	}
 #endif
@@ -1001,6 +1031,86 @@ kevent_copyin(void *arg, struct kevent *kevp, int coun
 		uap->changelist += count;
 	return (error);
 }
+
+#ifdef COMPAT_FREEBSD11
+struct kevent_freebsd11 {
+	__uintptr_t	ident;		/* identifier for this event */
+	short		filter;		/* filter for event */
+	unsigned short	flags;
+	unsigned int	fflags;
+	__intptr_t	data;
+	void		*udata;		/* opaque user data identifier */
+};
+
+static int
+kevent11_copyout(void *arg, struct kevent *kevp, int count)
+{
+	struct freebsd11_kevent_args *uap;
+	struct kevent_freebsd11 kev11;
+	int error, i;
+
+	KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
+	uap = (struct freebsd11_kevent_args *)arg;
+
+	for (i = 0; i < count; i++) {
+		kev11.ident = kevp->ident;
+		kev11.filter = kevp->filter;
+		kev11.flags = kevp->flags;
+		kev11.fflags = kevp->fflags;
+		kev11.data = kevp->data;
+		kev11.udata = kevp->udata;
+		error = copyout(&kev11, uap->eventlist, sizeof(kev11));
+		if (error != 0)
+			break;
+		uap->eventlist++;
+		kevp++;
+	}
+	return (error);
+}
+
+/*
+ * Copy 'count' items from the list pointed to by uap->changelist.
+ */
+static int
+kevent11_copyin(void *arg, struct kevent *kevp, int count)
+{
+	struct freebsd11_kevent_args *uap;
+	struct kevent_freebsd11 kev11;
+	int error, i;
+
+	KASSERT(count <= KQ_NEVENTS, ("count (%d) > KQ_NEVENTS", count));
+	uap = (struct freebsd11_kevent_args *)arg;
+
+	for (i = 0; i < count; i++) {
+		error = copyin(uap->changelist, &kev11, sizeof(kev11));
+		if (error != 0)
+			break;
+		kevp->ident = kev11.ident;
+		kevp->filter = kev11.filter;
+		kevp->flags = kev11.flags;
+		kevp->fflags = kev11.fflags;
+		kevp->data = (uintptr_t)kev11.data;
+		kevp->udata = kev11.udata;
+		bzero(&kevp->ext, sizeof(kevp->ext));
+		uap->changelist++;
+		kevp++;
+	}
+	return (error);
+}
+
+int
+freebsd11_kevent(struct thread *td, struct freebsd11_kevent_args *uap)
+{
+	struct kevent_copyops k_ops = {
+		.arg = uap,
+		.k_copyout = kevent11_copyout,
+		.k_copyin = kevent11_copyin,
+		.kevent_size = sizeof(struct kevent_freebsd11),
+	};
+
+	return (kern_kevent_generic(td, (struct g_kevent_args *)uap, &k_ops));
+}
+#endif
 
 int
 kern_kevent(struct thread *td, int fd, int nchanges, int nevents,

Modified: head/sys/kern/syscalls.master
==============================================================================
--- head/sys/kern/syscalls.master	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/sys/kern/syscalls.master	Sat Jun 17 00:57:26 2017	(r320043)
@@ -657,9 +657,11 @@
 361	AUE_GETRESGID	STD	{ int getresgid(gid_t *rgid, gid_t *egid, \
 				    gid_t *sgid); }
 362	AUE_KQUEUE	STD	{ int kqueue(void); }
-363	AUE_KEVENT	STD	{ int kevent(int fd, \
-				    struct kevent *changelist, int nchanges, \
-				    struct kevent *eventlist, int nevents, \
+363	AUE_KEVENT	COMPAT11 { int kevent(int fd, \
+				    struct kevent_freebsd11 *changelist, \
+				    int nchanges, \
+				    struct kevent_freebsd11 *eventlist, \
+				    int nevents, \
 				    const struct timespec *timeout); }
 364	AUE_NULL	UNIMPL	__cap_get_proc
 365	AUE_NULL	UNIMPL	__cap_set_proc
@@ -1017,6 +1019,10 @@
 				    struct statfs *buf); }
 559	AUE_MKNODAT	STD	{ int mknodat(int fd, char *path, mode_t mode, \
 				    dev_t dev); }
+560	AUE_KEVENT	STD	{ int kevent(int fd, \
+				    struct kevent *changelist, int nchanges, \
+				    struct kevent *eventlist, int nevents, \
+				    const struct timespec *timeout); }
 
 ; Please copy any additions and changes to the following compatability tables:
 ; sys/compat/freebsd32/syscalls.master

Modified: head/sys/kern/vfs_aio.c
==============================================================================
--- head/sys/kern/vfs_aio.c	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/sys/kern/vfs_aio.c	Sat Jun 17 00:57:26 2017	(r320043)
@@ -2491,8 +2491,10 @@ sys_aio_fsync(struct thread *td, struct aio_fsync_args
 static int
 filt_aioattach(struct knote *kn)
 {
-	struct kaiocb *job = (struct kaiocb *)kn->kn_sdata;
+	struct kaiocb *job;
 
+	job = (struct kaiocb *)(uintptr_t)kn->kn_sdata;
+
 	/*
 	 * The job pointer must be validated before using it, so
 	 * registration is restricted to the kernel; the user cannot
@@ -2539,7 +2541,9 @@ filt_aio(struct knote *kn, long hint)
 static int
 filt_lioattach(struct knote *kn)
 {
-	struct aioliojob * lj = (struct aioliojob *)kn->kn_sdata;
+	struct aioliojob *lj;
+
+	lj = (struct aioliojob *)(uintptr_t)kn->kn_sdata;
 
 	/*
 	 * The aioliojob pointer must be validated before using it, so

Modified: head/sys/sys/event.h
==============================================================================
--- head/sys/sys/event.h	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/sys/sys/event.h	Sat Jun 17 00:57:26 2017	(r320043)
@@ -55,6 +55,10 @@
 	(kevp)->fflags = (d);			\
 	(kevp)->data = (e);			\
 	(kevp)->udata = (f);			\
+	(kevp)->ext[0] = 0;			\
+	(kevp)->ext[1] = 0;			\
+	(kevp)->ext[2] = 0;			\
+	(kevp)->ext[3] = 0;			\
 } while(0)
 
 struct kevent {
@@ -62,8 +66,9 @@ struct kevent {
 	short		filter;		/* filter for event */
 	unsigned short	flags;
 	unsigned int	fflags;
-	__intptr_t	data;
+	__int64_t	data;
 	void		*udata;		/* opaque user data identifier */
+	__uint64_t	ext[4];
 };
 
 /* actions */
@@ -149,6 +154,7 @@ struct kevent {
 #define NOTE_MSECONDS		0x00000002	/* data is milliseconds */
 #define NOTE_USECONDS		0x00000004	/* data is microseconds */
 #define NOTE_NSECONDS		0x00000008	/* data is nanoseconds */
+#define	NOTE_ABSTIME		0x00000010	/* timeout is absolute */
 
 struct knote;
 SLIST_HEAD(klist, knote);
@@ -232,7 +238,7 @@ struct knote {
 #define	KN_SCAN		0x100			/* flux set in kqueue_scan() */
 	int			kn_influx;
 	int			kn_sfflags;	/* saved filter flags */
-	intptr_t		kn_sdata;	/* saved data field */
+	int64_t			kn_sdata;	/* saved data field */
 	union {
 		struct		file *p_fp;	/* file data pointer */
 		struct		proc *p_proc;	/* proc pointer */
@@ -253,6 +259,7 @@ struct kevent_copyops {
 	void	*arg;
 	int	(*k_copyout)(void *arg, struct kevent *kevp, int count);
 	int	(*k_copyin)(void *arg, struct kevent *kevp, int count);
+	size_t	kevent_size;
 };
 
 struct thread;

Modified: head/tests/sys/kqueue/libkqueue/main.c
==============================================================================
--- head/tests/sys/kqueue/libkqueue/main.c	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/tests/sys/kqueue/libkqueue/main.c	Sat Jun 17 00:57:26 2017	(r320043)
@@ -180,13 +180,18 @@ kevent_to_str(struct kevent *kev)
     char buf[512];
 
     snprintf(&buf[0], sizeof(buf), 
-            "[ident=%d, filter=%d, %s, %s, data=%d, udata=%p]",
-            (u_int) kev->ident,
+            "[ident=%ju, filter=%d, %s, %s, data=%jd, udata=%p, "
+	    "ext=[%jx %jx %jx %jx]",
+            (uintmax_t) kev->ident,
             kev->filter,
             kevent_flags_dump(kev),
             kevent_fflags_dump(kev),
-            (int) kev->data,
-            kev->udata);
+            (uintmax_t)kev->data,
+            kev->udata,
+	    (uintmax_t)kev->ext[0],
+	    (uintmax_t)kev->ext[1],
+	    (uintmax_t)kev->ext[2],
+	    (uintmax_t)kev->ext[3]);
 
     return (strdup(buf));
 }
@@ -218,7 +223,11 @@ kevent_cmp(struct kevent *k1, struct kevent *k2)
     if (k1->flags & EV_ADD)
         k2->flags |= EV_ADD;
 #endif
-    if (memcmp(k1, k2, sizeof(*k1)) != 0) {
+    if (k1->ident != k2->ident || k1->filter != k2->filter ||
+      k1->flags != k2->flags || k1->fflags != k2->fflags ||
+      k1->data != k2->data || k1->udata != k2->udata ||
+      k1->ext[0] != k2->ext[0] || k1->ext[1] != k2->ext[1] ||
+      k1->ext[0] != k2->ext[2] || k1->ext[0] != k2->ext[3]) {
         printf("kevent_cmp: mismatch:\n  %s !=\n  %s\n", 
               kevent_to_str(k1), kevent_to_str(k2));
         abort();

Modified: head/tests/sys/kqueue/libkqueue/timer.c
==============================================================================
--- head/tests/sys/kqueue/libkqueue/timer.c	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/tests/sys/kqueue/libkqueue/timer.c	Sat Jun 17 00:57:26 2017	(r320043)
@@ -17,6 +17,7 @@
  */
 
 #include "common.h"
+#include <sys/time.h>
 
 int kqfd;
 
@@ -164,6 +165,39 @@ disable_and_enable(void)
     success();
 }
 
+static void
+test_abstime(void)
+{
+    const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
+    struct kevent kev;
+    time_t when;
+    const int timeout = 3;
+
+    test_begin(test_id);
+
+    test_no_kevents();
+
+    when = time(NULL);
+    EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
+      NOTE_ABSTIME | NOTE_SECONDS, when + timeout, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    /* Retrieve the event */
+    kev.flags = EV_ADD | EV_ONESHOT;
+    kev.data = 1;
+    kev.fflags = 0;
+    kevent_cmp(&kev, kevent_get(kqfd));
+    if (time(NULL) < when + timeout)
+	err(1, "too early %jd %jd", time(), when + timeout);
+
+    /* Check if the event occurs again */
+    sleep(3);
+    test_no_kevents();
+
+    success();
+}
+
 void
 test_evfilt_timer()
 {
@@ -173,6 +207,7 @@ test_evfilt_timer()
     test_kevent_timer_get();
     test_oneshot();
     test_periodic();
+    test_abstime();
     disable_and_enable();
 	close(kqfd);
 }

Modified: head/usr.bin/truss/syscalls.c
==============================================================================
--- head/usr.bin/truss/syscalls.c	Sat Jun 17 00:14:54 2017	(r320042)
+++ head/usr.bin/truss/syscalls.c	Sat Jun 17 00:57:26 2017	(r320043)
@@ -1255,7 +1255,7 @@ print_kevent(FILE *fp, struct kevent *ke, int input)
 	default:
 		fprintf(fp, "%#x", ke->fflags);
 	}
-	fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
+	fprintf(fp, ",%#jx,%p", (uintmax_t)ke->data, ke->udata);
 }
 
 static void


More information about the svn-src-head mailing list