Skip to content

Commit

Permalink
Add abstime kqueue(2) timers and expand struct kevent members.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
kostikbel committed Jun 17, 2017
1 parent f2eb97b commit 2b34e84
Show file tree
Hide file tree
Showing 15 changed files with 385 additions and 61 deletions.
4 changes: 0 additions & 4 deletions contrib/netbsd-tests/kernel/kqueue/t_proc1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
4 changes: 0 additions & 4 deletions contrib/netbsd-tests/kernel/kqueue/t_sig.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
2 changes: 2 additions & 0 deletions lib/libc/include/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
2 changes: 1 addition & 1 deletion lib/libc/sys/Symbol.map
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ FBSD_1.0 {
jail;
jail_attach;
kenv;
kevent;
kill;
kldfind;
kldfirstmod;
Expand Down Expand Up @@ -393,6 +392,7 @@ FBSD_1.5 {
getdents;
getdirentries;
getfsstat;
kevent;
lstat;
mknod;
mknodat;
Expand Down
39 changes: 33 additions & 6 deletions lib/libc/sys/kqueue.2
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd April 18, 2017
.Dd June 17, 2017
.Dt KQUEUE 2
.Os
.Sh NAME
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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
Expand Down
7 changes: 4 additions & 3 deletions sys/compat/freebsd32/freebsd32.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
133 changes: 128 additions & 5 deletions sys/compat/freebsd32/freebsd32_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down Expand Up @@ -622,7 +622,8 @@ freebsd32_kevent_copyout(void *arg, struct kevent *kevp, int count)
{
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;
Expand All @@ -632,8 +633,24 @@ freebsd32_kevent_copyout(void *arg, struct kevent *kevp, int count)
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)
Expand All @@ -649,7 +666,8 @@ freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count)
{
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;
Expand All @@ -664,8 +682,20 @@ freebsd32_kevent_copyin(void *arg, struct kevent *kevp, int count)
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);
Expand All @@ -683,6 +713,98 @@ freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap)
};
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));
Expand All @@ -697,6 +819,7 @@ freebsd32_kevent(struct thread *td, struct freebsd32_kevent_args *uap)
&k_ops, tsp);
return (error);
}
#endif

int
freebsd32_gettimeofday(struct thread *td,
Expand Down
14 changes: 11 additions & 3 deletions sys/compat/freebsd32/syscalls.master
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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); }

0 comments on commit 2b34e84

Please sign in to comment.