diff options
author | Bryan Cantrill <bryan@joyent.com> | 2015-09-04 08:32:01 -0700 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2015-10-16 15:07:22 -0700 |
commit | 6a72db4a7fa12c3e0d1c1cf91a07390739fa0fbf (patch) | |
tree | 01b80bd94b70941b4bebdf46773bfff1bdbdab3e | |
parent | f3bb54f387fc03cf651e19bbee54cc88ee51bb29 (diff) | |
download | illumos-joyent-6a72db4a7fa12c3e0d1c1cf91a07390739fa0fbf.tar.gz |
6208 add support for timerfd
Reviewed by: Gordon Ross <gwr@nexenta.com>
Approved by: Dan McDonald <danmcd@omniti.com>
28 files changed, 1246 insertions, 20 deletions
diff --git a/usr/src/cmd/devfsadm/misc_link.c b/usr/src/cmd/devfsadm/misc_link.c index abb133bc6d..bf59fb5e6b 100644 --- a/usr/src/cmd/devfsadm/misc_link.c +++ b/usr/src/cmd/devfsadm/misc_link.c @@ -21,7 +21,7 @@ /* * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2011 Nexenta Systems, Inc. All rights reserved. - * Copyright (c) 2012, Joyent, Inc. All rights reserved. + * Copyright (c) 2015, Joyent, Inc. All rights reserved. */ #include <regex.h> @@ -126,6 +126,9 @@ static devfsadm_create_t misc_cbt[] = { "(^kdmouse$)|(^rootprop$)", TYPE_EXACT | DRV_RE, ILEVEL_0, node_name }, + { "pseudo", "ddi_pseudo", "timerfd", + TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name + }, { "pseudo", "ddi_pseudo", "tod", TYPE_EXACT | DRV_EXACT, ILEVEL_0, node_name }, diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile index b5e54b19fa..dbda6c0c31 100644 --- a/usr/src/lib/libc/amd64/Makefile +++ b/usr/src/lib/libc/amd64/Makefile @@ -909,6 +909,7 @@ PORTSYS= \ tasksys.o \ time.o \ time_util.o \ + timerfd.o \ ucontext.o \ unlink.o \ ustat.o \ diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com index d7e77502f2..25ba0a2743 100644 --- a/usr/src/lib/libc/i386/Makefile.com +++ b/usr/src/lib/libc/i386/Makefile.com @@ -949,6 +949,7 @@ PORTSYS= \ tasksys.o \ time.o \ time_util.o \ + timerfd.o \ ucontext.o \ unlink.o \ ustat.o \ diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers index 017c7c31bc..a0e21e250f 100644 --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -93,6 +93,13 @@ $if _x86 && _ELF64 $add amd64 $endif +SYMBOL_VERSION ILLUMOS_0.16 { # timerfd + protected: + timerfd_create; + timerfd_gettime; + timerfd_settime; +} ILLUMOS_0.15; + SYMBOL_VERSION ILLUMOS_0.15 { # epoll(3C) protected: epoll_create; diff --git a/usr/src/lib/libc/port/sys/timerfd.c b/usr/src/lib/libc/port/sys/timerfd.c new file mode 100644 index 0000000000..cb2e17adf7 --- /dev/null +++ b/usr/src/lib/libc/port/sys/timerfd.c @@ -0,0 +1,93 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2015, Joyent, Inc. All rights reserved. + */ + +#include <sys/timerfd.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +int +timerfd_create(int clockid, int flags) +{ + int oflags = O_RDWR; + int fd; + + if (flags & ~(TFD_NONBLOCK | TFD_CLOEXEC)) { + errno = EINVAL; + return (-1); + } + + if (flags & TFD_NONBLOCK) + oflags |= O_NONBLOCK; + + if (flags & TFD_CLOEXEC) + oflags |= O_CLOEXEC; + + if ((fd = open("/dev/timerfd", oflags)) < 0) + return (-1); + + if (ioctl(fd, TIMERFDIOC_CREATE, clockid) != 0) { + (void) close(fd); + return (-1); + } + + return (fd); +} + +int +timerfd_settime(int fd, int flags, const struct itimerspec *new_value, + struct itimerspec *old_value) +{ + timerfd_settime_t st; + int rval; + + if (flags & ~(TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET)) { + errno = EINVAL; + return (-1); + } + + st.tfd_settime_flags = flags; + st.tfd_settime_value = (uint64_t)(uintptr_t)new_value; + st.tfd_settime_ovalue = (uint64_t)(uintptr_t)old_value; + + rval = ioctl(fd, TIMERFDIOC_SETTIME, &st); + + if (rval == -1 && errno == ENOTTY) { + /* + * Linux has us return EINVAL when the file descriptor is valid + * but is not a timerfd file descriptor -- and LTP explicitly + * checks this case. + */ + errno = EINVAL; + } + + return (rval); +} + +int +timerfd_gettime(int fd, struct itimerspec *curr_value) +{ + int rval = ioctl(fd, TIMERFDIOC_GETTIME, curr_value); + + if (rval == -1 && errno == ENOTTY) { + /* + * See comment in timerfd_settime(), above. + */ + errno = EINVAL; + } + + return (rval); +} diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com index dc965fe6ac..94036d831e 100644 --- a/usr/src/lib/libc/sparc/Makefile.com +++ b/usr/src/lib/libc/sparc/Makefile.com @@ -983,6 +983,7 @@ PORTSYS= \ tasksys.o \ time.o \ time_util.o \ + timerfd.o \ ucontext.o \ unlink.o \ ustat.o \ diff --git a/usr/src/lib/libc/sparcv9/Makefile.com b/usr/src/lib/libc/sparcv9/Makefile.com index 415aaf2be2..2156bad20b 100644 --- a/usr/src/lib/libc/sparcv9/Makefile.com +++ b/usr/src/lib/libc/sparcv9/Makefile.com @@ -927,6 +927,7 @@ PORTSYS= \ tasksys.o \ time.o \ time_util.o \ + timerfd.o \ ucontext.o \ unlink.o \ ustat.o \ diff --git a/usr/src/man/man3c/Makefile b/usr/src/man/man3c/Makefile index f6cadebe95..c38d65a57a 100644 --- a/usr/src/man/man3c/Makefile +++ b/usr/src/man/man3c/Makefile @@ -473,6 +473,7 @@ MANFILES= __fbufsize.3c \ timer_delete.3c \ timer_settime.3c \ timeradd.3c \ + timerfd_create.3c \ tmpfile.3c \ tmpnam.3c \ toascii.3c \ @@ -1211,6 +1212,8 @@ MANLINKS= FD_CLR.3c \ timer_gettime.3c \ timerclear.3c \ timercmp.3c \ + timerfd_gettime.3c \ + timerfd_settime.3c \ timerisset.3c \ timersub.3c \ tmpnam_r.3c \ @@ -2250,6 +2253,9 @@ timercmp.3c := LINKSRC = timeradd.3c timerisset.3c := LINKSRC = timeradd.3c timersub.3c := LINKSRC = timeradd.3c +timerfd_gettime.3c := LINKSRC = timerfd_create.3c +timerfd_settime.3c := LINKSRC = timerfd_create.3c + tempnam.3c := LINKSRC = tmpnam.3c tmpnam_r.3c := LINKSRC = tmpnam.3c diff --git a/usr/src/man/man3c/timerfd_create.3c b/usr/src/man/man3c/timerfd_create.3c new file mode 100644 index 0000000000..84df47e245 --- /dev/null +++ b/usr/src/man/man3c/timerfd_create.3c @@ -0,0 +1,201 @@ +.\" +.\" This file and its contents are supplied under the terms of the +.\" Common Development and Distribution License ("CDDL"), version 1.0. +.\" You may only use this file in accordance with the terms of version +.\" 1.0 of the CDDL. +.\" +.\" A full copy of the text of the CDDL should have accompanied this +.\" source. A copy of the CDDL is also available via the Internet at +.\" http://www.illumos.org/license/CDDL. +.\" +.\" +.\" Copyright (c) 2015, Joyent, Inc. All Rights Reserved. +.\" +.Dd Feb 23, 2105 +.Dt TIMERFD 3C +.Os +.Sh NAME +.Nm timerfd_create , +.Nm timerfd_settime , +.Nm timerfd_gettime +.Nd create and manipulate timers via a file descriptor interface +.Sh SYNOPSIS +.In sys/timerfd.h +.Ft int +.Fo timerfd_create +.Fa "int clockid" +.Fa "int flags" +.Fc +.Ft int +.Fo timerfd_settime +.Fa "int fd" +.Fa "int flags" +.Fa "const struct itimerspec *restrict value" +.Fa "struct itimterspec *restrict ovalue" +.Fc +.Ft int +.Fo timerfd_gettime +.Fa "int fd" +.Fa "struct itimerspec *value" +.Fc +.Sh DESCRIPTION +These routines create and manipulate timers in which events are associated +with a file descriptor, allowing for timer-based events to be used +in file-descriptor based facilities like +.Xr poll 2 , +.Xr port_get 3C +or +.Xr epoll_wait 3C . +The +.Fn timerfd_create +function creates a timer with the clock +type specified by +.Fa clockid . +The +.Sy CLOCK_REALTIME +and +.Sy CLOCK_HIGHRES +clock types, as defined in +.Xr timer_create 3C , +are supported by +.Fn timerfd_create . +(Note that +.Sy CLOCK_MONOTONIC +may be used as an alias for +.Sy CLOCK_HIGHRES Ns .) +.Pp +The +.Fa flags +argument specifies additional parameters for the timer instance, and can have +any of the following values: +.Bl -hang -width Ds +.It Sy TFD_CLOEXEC +.Bd -filled -compact +Instance will be closed upon an +.Xr exec 2 ; +see +.Xr open 2 Ns 's +description of +.Sy O_CLOEXEC . +.Ed +.It Sy TFD_NONBLOCK +.Bd -filled -compact +Instance will be set to be non-blocking. A +.Xr read 2 +on a +.Sy timerfd +instance that has been initialized with +.Sy TFD_NONBLOCK +will return +.Sy EAGAIN +in lieu of blocking if the +timer has not expired since the last +.Fn timerfd_settime +or successful +.Fn read . +.Ed +.El +.Pp +The following operations can be performed upon a +.Sy timerfd +instance: +.Bl -hang -width Ds +.It Sy read(2) +.Bd -filled -compact +Atomically reads and clears the number of timer expirations since the +last successful +.Xr read 2 +or +.Fn timerfd_settime . +Upon success, +the number of expirations will be copied into the eight byte buffer +passed to the system call. If there have been no expirations of the +timer since the last successful +.Xr read 2 +or +.Fn timerfd_sttime , +.Xr read 2 +will block until at least the next expiration, +or return +.Sy EAGAIN +if the instance was created with +.Sy TFD_NONBLOCK . +Note that if multiple threads are blocked in +.Xr read 2 +for the same timer, only one of them will return upon +a single timer expiration. +.Pp +If the buffer specified to +.Xr read 2 +is less than +eight bytes in length, +.Sy EINAVL +will be returned. +.Ed +.It Sy poll(2), port_get(3C), epoll_wait(3C) +.Bd -filled -compact +Provide notification when the timer expires or has expired in the past without +a more recent +.Xr read 2 . +Note that threads being simultaneously +blocked in +.Xr read 2 +and +.Xr poll 2 +(or equivalents) for the same +timer constitute an application-level race; on a timer expiration, +the thread blocked in +.Xr poll 2 +may or may not return depending on how +it is scheduled with respect to the thread blocked in +.Xr read 2 . +.Ed +.It Sy timerfd_gettime() +.Bd -filled -compact +Returns the amount of time until the next timer expiration, with the +same functional signature and semantics as +.Xr timer_gettime 3C . +.Ed +.It Sy timerfd_settime() +.Bd -filled -compact +Sets or disarms the timer, with the +same functional signature and semantics as +.Xr timer_settime 3C . +.Ed +.El +.Sh RETURN VALUES +Upon succesful completion, a file descriptor associated with the instance +is returned. Otherwise, +.Sy -1 +is returned and errno is set to indicate the error. +.Sh ERRORS +The +.Fn timerfd_create() +function will fail if: +.Bl -tag -width Er +.It Er EINAL +The +.Fa flags +are invalid. +.It Er EMFILE +There are currently +.Pf { Sy OPEN_MAX Ns } +file descriptors open in the calling process. +.It Er EPERM +The +.Fa clock_id , +is +.Sy CLOCK_HIGHRES +and the +.Pf { Sy PRIV_PROC_CLOCK_HIGHRES Ns } +is not asserted in the effective set of the calling process. +.El +.Sh SEE ALSO +.Xr poll 2 , +.Xr port_get 3C , +.Xr epoll_wait 3C , +.Xr timer_create 3C , +.Xr timer_gettime 3C , +.Xr timer_settime 3C , +.Xr privileages 5 , +.Xr timerfd 5 diff --git a/usr/src/man/man5/Makefile b/usr/src/man/man5/Makefile index 4784603013..c30af8e1d1 100644 --- a/usr/src/man/man5/Makefile +++ b/usr/src/man/man5/Makefile @@ -14,6 +14,7 @@ # Copyright (c) 2012 by Delphix. All rights reserved. # Copyright 2014 Nexenta Systems, Inc. # Copyright 2014 Garrett D'Amore <garrett@damore.org> +# Copyright (c) 2015, Joyent, Inc. All rights reserved. # include $(SRC)/Makefile.master @@ -121,6 +122,7 @@ MANFILES= Intro.5 \ tecla.5 \ term.5 \ threads.5 \ + timerfd.5 \ trusted_extensions.5 \ vgrindefs.5 \ zones.5 \ diff --git a/usr/src/man/man5/timerfd.5 b/usr/src/man/man5/timerfd.5 new file mode 100644 index 0000000000..3229095b49 --- /dev/null +++ b/usr/src/man/man5/timerfd.5 @@ -0,0 +1,47 @@ +.\" +.\" This file and its contents are supplied under the terms of the +.\" Common Development and Distribution License ("CDDL"), version 1.0. +.\" You may only use this file in accordance with the terms of version +.\" 1.0 of the CDDL. +.\" +.\" A full copy of the text of the CDDL should have accompanied this +.\" source. A copy of the CDDL is also available via the Internet at +.\" http://www.illumos.org/license/CDDL. +.\" +.\" +.\" Copyright (c) 2015, Joyent, Inc. All Rights Reserved. +.\" +.Dd Feb 23, 2015 +.Dt TIMERFD 5 +.Os +.Sh NAME +.Nm timerfd +.Nd Linux-compatible timer notification facility +.Sh SYNOPSIS +.In sys/timerfd.h +.Sh DESCRIPTION +.Nm +is a Linux-borne facility for creating POSIX timers and +receiving their subsequent events via a file descriptor. +The facility itself is arguably unnecessary: +portable code can either use the timeout value present in +.Xr poll 2 / +.Xr port_get 3C +or -- if this is deemed of unacceptably poor resolution -- create a POSIX timer +via +.Xr timer_create 3C +and use the resulting signal to induce an +.Sy EINTR +to polling threads. (For code that need not be +portable, the +.Sy SIGEV_PORT +signal notification allows for explicit, event-oriented timer notification to be +sent to a specified port; see +.Xr signal.h 3HEAD +for details.) This facility therefore exists only to accommodate Linux-borne +applications and binaries; it is compatible with its Linux antecedent in both +binary interface and in semantics. +.Sh SEE ALSO +.Xr timerfd_create 3C , +.Xr timerfd_gettime 3C , +.Xr timerfd_settime 3C diff --git a/usr/src/pkg/manifests/SUNWcs.mf b/usr/src/pkg/manifests/SUNWcs.mf index 85285ae7cd..47923f1f78 100644 --- a/usr/src/pkg/manifests/SUNWcs.mf +++ b/usr/src/pkg/manifests/SUNWcs.mf @@ -323,6 +323,7 @@ driver name=logindmux driver name=ptm clone_perms="ptmx 0666 root sys" driver name=pts perms="* 0644 root sys" perms="0 0620 root tty" \ perms="1 0620 root tty" perms="2 0620 root tty" perms="3 0620 root tty" +driver name=timerfd perms="* 0666 root sys" file path=etc/.login group=sys preserve=renamenew file path=etc/cron.d/.proto group=sys mode=0744 file path=etc/cron.d/at.deny group=sys preserve=true @@ -868,6 +869,7 @@ file path=usr/kernel/drv/$(ARCH64)/ksyms group=sys file path=usr/kernel/drv/$(ARCH64)/logindmux group=sys file path=usr/kernel/drv/$(ARCH64)/ptm group=sys file path=usr/kernel/drv/$(ARCH64)/pts group=sys +file path=usr/kernel/drv/$(ARCH64)/timerfd group=sys $(i386_ONLY)file path=usr/kernel/drv/dump group=sys file path=usr/kernel/drv/dump.conf group=sys $(i386_ONLY)file path=usr/kernel/drv/eventfd group=sys @@ -884,6 +886,8 @@ $(i386_ONLY)file path=usr/kernel/drv/ptm group=sys file path=usr/kernel/drv/ptm.conf group=sys $(i386_ONLY)file path=usr/kernel/drv/pts group=sys file path=usr/kernel/drv/pts.conf group=sys +$(i386_ONLY)file path=usr/kernel/drv/timerfd group=sys +file path=usr/kernel/drv/timerfd.conf group=sys file path=usr/kernel/exec/$(ARCH64)/javaexec group=sys mode=0755 file path=usr/kernel/exec/$(ARCH64)/shbinexec group=sys mode=0755 $(i386_ONLY)file path=usr/kernel/exec/javaexec group=sys mode=0755 diff --git a/usr/src/pkg/manifests/system-header.mf b/usr/src/pkg/manifests/system-header.mf index b72d713cd8..08f0b19416 100644 --- a/usr/src/pkg/manifests/system-header.mf +++ b/usr/src/pkg/manifests/system-header.mf @@ -1516,6 +1516,7 @@ file path=usr/include/sys/time_impl.h file path=usr/include/sys/time_std_impl.h file path=usr/include/sys/timeb.h file path=usr/include/sys/timer.h +file path=usr/include/sys/timerfd.h file path=usr/include/sys/times.h file path=usr/include/sys/timex.h file path=usr/include/sys/timod.h diff --git a/usr/src/pkg/manifests/system-library.man3c.inc b/usr/src/pkg/manifests/system-library.man3c.inc index 27268505b3..ae061edac9 100644 --- a/usr/src/pkg/manifests/system-library.man3c.inc +++ b/usr/src/pkg/manifests/system-library.man3c.inc @@ -468,6 +468,7 @@ file path=usr/share/man/man3c/timer_create.3c file path=usr/share/man/man3c/timer_delete.3c file path=usr/share/man/man3c/timer_settime.3c file path=usr/share/man/man3c/timeradd.3c +file path=usr/share/man/man3c/timerfd_create.3c file path=usr/share/man/man3c/tmpfile.3c file path=usr/share/man/man3c/tmpnam.3c file path=usr/share/man/man3c/toascii.3c @@ -1281,6 +1282,8 @@ link path=usr/share/man/man3c/timer_getoverrun.3c target=timer_settime.3c link path=usr/share/man/man3c/timer_gettime.3c target=timer_settime.3c link path=usr/share/man/man3c/timerclear.3c target=timeradd.3c link path=usr/share/man/man3c/timercmp.3c target=timeradd.3c +link path=usr/share/man/man3c/timerfd_gettime.3c target=timerfd_create.3c +link path=usr/share/man/man3c/timerfd_settime.3c target=timerfd_create.3c link path=usr/share/man/man3c/timerisset.3c target=timeradd.3c link path=usr/share/man/man3c/timersub.3c target=timeradd.3c link path=usr/share/man/man3c/tmpnam_r.3c target=tmpnam.3c diff --git a/usr/src/pkg/manifests/system-library.man5.inc b/usr/src/pkg/manifests/system-library.man5.inc index fd222bcec4..63d883e984 100644 --- a/usr/src/pkg/manifests/system-library.man5.inc +++ b/usr/src/pkg/manifests/system-library.man5.inc @@ -61,6 +61,7 @@ file path=usr/share/man/man5/pkcs11_softtoken.5 file path=usr/share/man/man5/pkcs11_tpm.5 file path=usr/share/man/man5/regex.5 file path=usr/share/man/man5/regexp.5 +file path=usr/share/man/man5/timerfd.5 file path=usr/share/man/man5/threads.5 link path=usr/share/man/man5/advance.5 target=regexp.5 link path=usr/share/man/man5/compile.5 target=regexp.5 diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 3421b83719..cd9da11ac8 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -1032,6 +1032,8 @@ GEN_DRV_OBJS += gen_drv.o TCLIENT_OBJS += tclient.o +TIMERFD_OBJS += timerfd.o + TPHCI_OBJS += tphci.o TVHCI_OBJS += tvhci.o diff --git a/usr/src/uts/common/io/timerfd.c b/usr/src/uts/common/io/timerfd.c new file mode 100644 index 0000000000..29eea9b24a --- /dev/null +++ b/usr/src/uts/common/io/timerfd.c @@ -0,0 +1,586 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2015 Joyent, Inc. All rights reserved. + */ + +/* + * Support for the timerfd facility, a Linux-borne facility that allows + * POSIX.1b timers to be created and manipulated via a file descriptor + * interface. + */ + +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/timerfd.h> +#include <sys/conf.h> +#include <sys/vmem.h> +#include <sys/sysmacros.h> +#include <sys/filio.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/timer.h> + +struct timerfd_state; +typedef struct timerfd_state timerfd_state_t; + +struct timerfd_state { + kmutex_t tfd_lock; /* lock protecting state */ + kcondvar_t tfd_cv; /* condvar */ + pollhead_t tfd_pollhd; /* poll head */ + uint64_t tfd_fired; /* # of times fired */ + itimer_t tfd_itimer; /* underlying itimer */ + timerfd_state_t *tfd_next; /* next state on global list */ +}; + +/* + * Internal global variables. + */ +static kmutex_t timerfd_lock; /* lock protecting state */ +static dev_info_t *timerfd_devi; /* device info */ +static vmem_t *timerfd_minor; /* minor number arena */ +static void *timerfd_softstate; /* softstate pointer */ +static timerfd_state_t *timerfd_state; /* global list of state */ + +static itimer_t * +timerfd_itimer_lock(timerfd_state_t *state) +{ + itimer_t *it = &state->tfd_itimer; + + mutex_enter(&state->tfd_lock); + + while (it->it_lock & ITLK_LOCKED) { + it->it_blockers++; + cv_wait(&it->it_cv, &state->tfd_lock); + it->it_blockers--; + } + + it->it_lock |= ITLK_LOCKED; + + mutex_exit(&state->tfd_lock); + + return (it); +} + +static void +timerfd_itimer_unlock(timerfd_state_t *state, itimer_t *it) +{ + VERIFY(it == &state->tfd_itimer); + VERIFY(it->it_lock & ITLK_LOCKED); + + mutex_enter(&state->tfd_lock); + + it->it_lock &= ~ITLK_LOCKED; + + if (it->it_blockers) + cv_signal(&it->it_cv); + + mutex_exit(&state->tfd_lock); +} + +static void +timerfd_fire(itimer_t *it) +{ + timerfd_state_t *state = it->it_frontend; + uint64_t oval; + + mutex_enter(&state->tfd_lock); + oval = state->tfd_fired++; + mutex_exit(&state->tfd_lock); + + if (oval == 0) { + cv_broadcast(&state->tfd_cv); + pollwakeup(&state->tfd_pollhd, POLLRDNORM | POLLIN); + } +} + +/*ARGSUSED*/ +static int +timerfd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) +{ + timerfd_state_t *state; + major_t major = getemajor(*devp); + minor_t minor = getminor(*devp); + + if (minor != TIMERFDMNRN_TIMERFD) + return (ENXIO); + + mutex_enter(&timerfd_lock); + + minor = (minor_t)(uintptr_t)vmem_alloc(timerfd_minor, 1, + VM_BESTFIT | VM_SLEEP); + + if (ddi_soft_state_zalloc(timerfd_softstate, minor) != DDI_SUCCESS) { + vmem_free(timerfd_minor, (void *)(uintptr_t)minor, 1); + mutex_exit(&timerfd_lock); + return (NULL); + } + + state = ddi_get_soft_state(timerfd_softstate, minor); + *devp = makedevice(major, minor); + + state->tfd_next = timerfd_state; + timerfd_state = state; + + mutex_exit(&timerfd_lock); + + return (0); +} + +/*ARGSUSED*/ +static int +timerfd_read(dev_t dev, uio_t *uio, cred_t *cr) +{ + timerfd_state_t *state; + minor_t minor = getminor(dev); + uint64_t val; + int err; + + if (uio->uio_resid < sizeof (val)) + return (EINVAL); + + state = ddi_get_soft_state(timerfd_softstate, minor); + + mutex_enter(&state->tfd_lock); + + while (state->tfd_fired == 0) { + if (uio->uio_fmode & (FNDELAY|FNONBLOCK)) { + mutex_exit(&state->tfd_lock); + return (EAGAIN); + } + + if (!cv_wait_sig_swap(&state->tfd_cv, &state->tfd_lock)) { + mutex_exit(&state->tfd_lock); + return (EINTR); + } + } + + /* + * Our tfd_fired is non-zero; slurp its value and then clear it. + */ + val = state->tfd_fired; + state->tfd_fired = 0; + mutex_exit(&state->tfd_lock); + + err = uiomove(&val, sizeof (val), UIO_READ, uio); + + return (err); +} + +/*ARGSUSED*/ +static int +timerfd_poll(dev_t dev, short events, int anyyet, short *reventsp, + struct pollhead **phpp) +{ + timerfd_state_t *state; + minor_t minor = getminor(dev); + short revents = 0; + + state = ddi_get_soft_state(timerfd_softstate, minor); + + mutex_enter(&state->tfd_lock); + + if (state->tfd_fired > 0) + revents |= POLLRDNORM | POLLIN; + + if (!(*reventsp = revents & events) && !anyyet) + *phpp = &state->tfd_pollhd; + + mutex_exit(&state->tfd_lock); + + return (0); +} + +static int +timerfd_copyin(uintptr_t addr, itimerspec_t *dest) +{ + if (get_udatamodel() == DATAMODEL_NATIVE) { + if (copyin((void *)addr, dest, sizeof (itimerspec_t)) != 0) + return (EFAULT); + } else { + itimerspec32_t dest32; + + if (copyin((void *)addr, &dest32, sizeof (itimerspec32_t)) != 0) + return (EFAULT); + + ITIMERSPEC32_TO_ITIMERSPEC(dest, &dest32); + } + + if (itimerspecfix(&dest->it_value) || + (itimerspecfix(&dest->it_interval) && + timerspecisset(&dest->it_value))) { + return (EINVAL); + } + + return (0); +} + +static int +timerfd_copyout(itimerspec_t *src, uintptr_t addr) +{ + if (get_udatamodel() == DATAMODEL_NATIVE) { + if (copyout(src, (void *)addr, sizeof (itimerspec_t)) != 0) + return (EFAULT); + } else { + itimerspec32_t src32; + + if (ITIMERSPEC_OVERFLOW(src)) + return (EOVERFLOW); + + ITIMERSPEC_TO_ITIMERSPEC32(&src32, src); + + if (copyout(&src32, (void *)addr, sizeof (itimerspec32_t)) != 0) + return (EFAULT); + } + + return (0); +} + +/*ARGSUSED*/ +static int +timerfd_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv) +{ + itimerspec_t when, oval; + timerfd_state_t *state; + minor_t minor = getminor(dev); + int err; + itimer_t *it; + + state = ddi_get_soft_state(timerfd_softstate, minor); + + switch (cmd) { + case TIMERFDIOC_CREATE: { + if (arg == TIMERFD_MONOTONIC) + arg = CLOCK_MONOTONIC; + + it = timerfd_itimer_lock(state); + + if (it->it_backend != NULL) { + timerfd_itimer_unlock(state, it); + return (EEXIST); + } + + if ((it->it_backend = clock_get_backend(arg)) == NULL) { + timerfd_itimer_unlock(state, it); + return (EINVAL); + } + + /* + * We need to provide a proc structure only for purposes + * of locking CLOCK_REALTIME-based timers -- it is safe to + * provide p0 here. + */ + it->it_proc = &p0; + + err = it->it_backend->clk_timer_create(it, timerfd_fire); + + if (err != 0) { + it->it_backend = NULL; + timerfd_itimer_unlock(state, it); + return (err); + } + + it->it_frontend = state; + timerfd_itimer_unlock(state, it); + + return (0); + } + + case TIMERFDIOC_GETTIME: { + it = timerfd_itimer_lock(state); + + if (it->it_backend == NULL) { + timerfd_itimer_unlock(state, it); + return (ENODEV); + } + + err = it->it_backend->clk_timer_gettime(it, &when); + timerfd_itimer_unlock(state, it); + + if (err != 0) + return (err); + + if ((err = timerfd_copyout(&when, arg)) != 0) + return (err); + + return (0); + } + + case TIMERFDIOC_SETTIME: { + timerfd_settime_t st; + + if (copyin((void *)arg, &st, sizeof (st)) != 0) + return (EFAULT); + + if ((err = timerfd_copyin(st.tfd_settime_value, &when)) != 0) + return (err); + + it = timerfd_itimer_lock(state); + + if (it->it_backend == NULL) { + timerfd_itimer_unlock(state, it); + return (ENODEV); + } + + if (st.tfd_settime_ovalue != NULL) { + err = it->it_backend->clk_timer_gettime(it, &oval); + + if (err != 0) { + timerfd_itimer_unlock(state, it); + return (err); + } + } + + /* + * Before we set the time, we're going to clear tfd_fired. + * This can potentially race with the (old) timer firing, but + * the window is deceptively difficult to close: if we were + * to simply clear tfd_fired after the call to the backend + * returned, we would run the risk of plowing a firing of the + * new timer. Ultimately, the race can only be resolved by + * the backend, which would likely need to be extended with a + * function to call back into when the timer is between states + * (that is, after the timer can no longer fire with the old + * timer value, but before it can fire with the new one). + * This is straightforward enough for backends that set a + * timer's value by deleting the old one and adding the new + * one, but for those that modify the timer value in place + * (e.g., cyclics), the required serialization is necessarily + * delicate: the function would have to be callable from + * arbitrary interrupt context. While implementing all of + * this is possible, it does not (for the moment) seem worth + * it: if the timer is firing at essentially the same moment + * that it's being reprogrammed, there is a higher-level race + * with respect to timerfd usage that the progam itself will + * have to properly resolve -- and it seems reasonable to + * simply allow the program to resolve it in this case. + */ + mutex_enter(&state->tfd_lock); + state->tfd_fired = 0; + mutex_exit(&state->tfd_lock); + + err = it->it_backend->clk_timer_settime(it, + st.tfd_settime_flags & TFD_TIMER_ABSTIME ? + TIMER_ABSTIME : TIMER_RELTIME, &when); + timerfd_itimer_unlock(state, it); + + if (err != 0 || st.tfd_settime_ovalue == NULL) + return (err); + + if ((err = timerfd_copyout(&oval, st.tfd_settime_ovalue)) != 0) + return (err); + + return (0); + } + + default: + break; + } + + return (ENOTTY); +} + +/*ARGSUSED*/ +static int +timerfd_close(dev_t dev, int flag, int otyp, cred_t *cred_p) +{ + timerfd_state_t *state, **sp; + itimer_t *it; + minor_t minor = getminor(dev); + + state = ddi_get_soft_state(timerfd_softstate, minor); + + if (state->tfd_pollhd.ph_list != NULL) { + pollwakeup(&state->tfd_pollhd, POLLERR); + pollhead_clean(&state->tfd_pollhd); + } + + /* + * No one can get to this timer; we don't need to lock it -- we can + * just call on the backend to delete it. + */ + it = &state->tfd_itimer; + + if (it->it_backend != NULL) + it->it_backend->clk_timer_delete(it); + + mutex_enter(&timerfd_lock); + + /* + * Remove our state from our global list. + */ + for (sp = &timerfd_state; *sp != state; sp = &((*sp)->tfd_next)) + VERIFY(*sp != NULL); + + *sp = (*sp)->tfd_next; + + ddi_soft_state_free(timerfd_softstate, minor); + vmem_free(timerfd_minor, (void *)(uintptr_t)minor, 1); + + mutex_exit(&timerfd_lock); + + return (0); +} + +static int +timerfd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) +{ + switch (cmd) { + case DDI_ATTACH: + break; + + case DDI_RESUME: + return (DDI_SUCCESS); + + default: + return (DDI_FAILURE); + } + + mutex_enter(&timerfd_lock); + + if (ddi_soft_state_init(&timerfd_softstate, + sizeof (timerfd_state_t), 0) != 0) { + cmn_err(CE_NOTE, "/dev/timerfd failed to create soft state"); + mutex_exit(&timerfd_lock); + return (DDI_FAILURE); + } + + if (ddi_create_minor_node(devi, "timerfd", S_IFCHR, + TIMERFDMNRN_TIMERFD, DDI_PSEUDO, NULL) == DDI_FAILURE) { + cmn_err(CE_NOTE, "/dev/timerfd couldn't create minor node"); + ddi_soft_state_fini(&timerfd_softstate); + mutex_exit(&timerfd_lock); + return (DDI_FAILURE); + } + + ddi_report_dev(devi); + timerfd_devi = devi; + + timerfd_minor = vmem_create("timerfd_minor", (void *)TIMERFDMNRN_CLONE, + UINT32_MAX - TIMERFDMNRN_CLONE, 1, NULL, NULL, NULL, 0, + VM_SLEEP | VMC_IDENTIFIER); + + mutex_exit(&timerfd_lock); + + return (DDI_SUCCESS); +} + +/*ARGSUSED*/ +static int +timerfd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + switch (cmd) { + case DDI_DETACH: + break; + + case DDI_SUSPEND: + return (DDI_SUCCESS); + + default: + return (DDI_FAILURE); + } + + mutex_enter(&timerfd_lock); + vmem_destroy(timerfd_minor); + + ddi_remove_minor_node(timerfd_devi, NULL); + timerfd_devi = NULL; + + ddi_soft_state_fini(&timerfd_softstate); + mutex_exit(&timerfd_lock); + + return (DDI_SUCCESS); +} + +/*ARGSUSED*/ +static int +timerfd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) +{ + int error; + + switch (infocmd) { + case DDI_INFO_DEVT2DEVINFO: + *result = (void *)timerfd_devi; + error = DDI_SUCCESS; + break; + case DDI_INFO_DEVT2INSTANCE: + *result = (void *)0; + error = DDI_SUCCESS; + break; + default: + error = DDI_FAILURE; + } + return (error); +} + +static struct cb_ops timerfd_cb_ops = { + timerfd_open, /* open */ + timerfd_close, /* close */ + nulldev, /* strategy */ + nulldev, /* print */ + nodev, /* dump */ + timerfd_read, /* read */ + nodev, /* write */ + timerfd_ioctl, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + timerfd_poll, /* poll */ + ddi_prop_op, /* cb_prop_op */ + 0, /* streamtab */ + D_NEW | D_MP /* Driver compatibility flag */ +}; + +static struct dev_ops timerfd_ops = { + DEVO_REV, /* devo_rev */ + 0, /* refcnt */ + timerfd_info, /* get_dev_info */ + nulldev, /* identify */ + nulldev, /* probe */ + timerfd_attach, /* attach */ + timerfd_detach, /* detach */ + nodev, /* reset */ + &timerfd_cb_ops, /* driver operations */ + NULL, /* bus operations */ + nodev, /* dev power */ + ddi_quiesce_not_needed, /* quiesce */ +}; + +static struct modldrv modldrv = { + &mod_driverops, /* module type (this is a pseudo driver) */ + "timerfd support", /* name of module */ + &timerfd_ops, /* driver ops */ +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modldrv, + NULL +}; + +int +_init(void) +{ + return (mod_install(&modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +int +_fini(void) +{ + return (mod_remove(&modlinkage)); +} diff --git a/usr/src/uts/common/io/timerfd.conf b/usr/src/uts/common/io/timerfd.conf new file mode 100644 index 0000000000..c6ad86d051 --- /dev/null +++ b/usr/src/uts/common/io/timerfd.conf @@ -0,0 +1,16 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2015 Joyent, Inc. All rights reserved. +# + +name="timerfd" parent="pseudo" instance=0; diff --git a/usr/src/uts/common/os/clock_highres.c b/usr/src/uts/common/os/clock_highres.c index bcdf20c0bd..805813037d 100644 --- a/usr/src/uts/common/os/clock_highres.c +++ b/usr/src/uts/common/os/clock_highres.c @@ -25,7 +25,7 @@ */ /* - * Copyright (c) 2012, Joyent Inc. All rights reserved. + * Copyright (c) 2015, Joyent Inc. All rights reserved. */ #include <sys/timer.h> @@ -66,7 +66,7 @@ clock_highres_getres(timespec_t *ts) /*ARGSUSED*/ static int -clock_highres_timer_create(itimer_t *it, struct sigevent *ev) +clock_highres_timer_create(itimer_t *it, void (*fire)(itimer_t *)) { /* * CLOCK_HIGHRES timers of sufficiently high resolution can deny @@ -80,6 +80,7 @@ clock_highres_timer_create(itimer_t *it, struct sigevent *ev) } it->it_arg = kmem_zalloc(sizeof (cyclic_id_t), KM_SLEEP); + it->it_fire = fire; return (0); } @@ -95,7 +96,7 @@ clock_highres_fire(void *arg) old = *addr; } while (atomic_cas_64((uint64_t *)addr, old, new) != old); - timer_fire(it); + it->it_fire(it); } static int diff --git a/usr/src/uts/common/os/clock_realtime.c b/usr/src/uts/common/os/clock_realtime.c index ef3383fb28..4a75984b23 100644 --- a/usr/src/uts/common/os/clock_realtime.c +++ b/usr/src/uts/common/os/clock_realtime.c @@ -24,7 +24,9 @@ * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2015, Joyent Inc. All rights reserved. + */ #include <sys/timer.h> #include <sys/systm.h> @@ -80,8 +82,7 @@ clock_realtime_fire(void *arg) /* * First call into the timer subsystem to get the signal going. */ - timer_fire(it); - + it->it_fire(it); val = &it->it_itime.it_value; interval = &it->it_itime.it_interval; @@ -171,9 +172,10 @@ clock_realtime_fire_first(void *arg) /*ARGSUSED*/ static int -clock_realtime_timer_create(itimer_t *it, struct sigevent *ev) +clock_realtime_timer_create(itimer_t *it, void (*fire)(itimer_t *)) { it->it_arg = kmem_zalloc(sizeof (timeout_id_t), KM_SLEEP); + it->it_fire = fire; return (0); } @@ -184,7 +186,7 @@ clock_realtime_timer_settime(itimer_t *it, int flags, { timeout_id_t tid, *tidp = it->it_arg; timespec_t now; - proc_t *p = curproc; + proc_t *p = it->it_proc; clock_t ticks; gethrestime(&now); @@ -246,7 +248,7 @@ static int clock_realtime_timer_gettime(itimer_t *it, struct itimerspec *when) { timespec_t now; - proc_t *p = curproc; + proc_t *p = it->it_proc; /* * We always keep it_itime up to date, so we just need to snapshot @@ -276,7 +278,7 @@ clock_realtime_timer_gettime(itimer_t *it, struct itimerspec *when) static int clock_realtime_timer_delete(itimer_t *it) { - proc_t *p = curproc; + proc_t *p = it->it_proc; timeout_id_t tid, *tidp = it->it_arg; mutex_enter(&p->p_lock); diff --git a/usr/src/uts/common/os/timer.c b/usr/src/uts/common/os/timer.c index 8559d8736c..b25a6cbcf1 100644 --- a/usr/src/uts/common/os/timer.c +++ b/usr/src/uts/common/os/timer.c @@ -269,6 +269,15 @@ clock_add_backend(clockid_t clock, clock_backend_t *backend) clock_backend[clock] = backend; } +clock_backend_t * +clock_get_backend(clockid_t clock) +{ + if (clock < 0 || clock >= CLOCK_MAX) + return (NULL); + + return (clock_backend[clock]); +} + int clock_settime(clockid_t clock, timespec_t *tp) { @@ -398,7 +407,7 @@ timer_signal(sigqueue_t *sigq) /* * This routine is called from the clock backend. */ -void +static void timer_fire(itimer_t *it) { proc_t *p; @@ -672,7 +681,7 @@ timer_create(clockid_t clock, struct sigevent *evp, timer_t *tid) * Call on the backend to verify the event argument (or return * EINVAL if this clock type does not support timers). */ - if ((error = backend->clk_timer_create(it, &ev)) != 0) + if ((error = backend->clk_timer_create(it, timer_fire)) != 0) goto err; it->it_lwp = ttolwp(curthread); diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index c2bf2f0483..39288d5cc0 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -587,6 +587,7 @@ CHKHDRS= \ time_std_impl.h \ timeb.h \ timer.h \ + timerfd.h \ times.h \ timex.h \ timod.h \ diff --git a/usr/src/uts/common/sys/timer.h b/usr/src/uts/common/sys/timer.h index 604ddf5d83..ec349c962f 100644 --- a/usr/src/uts/common/sys/timer.h +++ b/usr/src/uts/common/sys/timer.h @@ -24,6 +24,10 @@ * Use is subject to license terms. */ +/* + * Copyright (c) 2015, Joyent, Inc. All rights reserved. + */ + #ifndef _SYS_TIMER_H #define _SYS_TIMER_H @@ -55,32 +59,45 @@ extern int timer_max; /* patchable via /etc/system */ struct clock_backend; -typedef struct itimer { +struct itimer; +typedef struct itimer itimer_t; + +struct itimer { itimerspec_t it_itime; hrtime_t it_hrtime; ushort_t it_flags; ushort_t it_lock; - void *it_arg; - sigqueue_t *it_sigq; - klwp_t *it_lwp; + void *it_arg; /* clock backend-specific data */ struct proc *it_proc; + union { + struct { + sigqueue_t *__it_sigq; + klwp_t *__it_lwp; + } __proc; + void *__it_frontend; + } __data; /* timer frontend-specific data */ kcondvar_t it_cv; int it_blockers; int it_pending; int it_overrun; struct clock_backend *it_backend; + void (*it_fire)(itimer_t *); kmutex_t it_mutex; void *it_portev; /* port_kevent_t pointer */ void *it_portsrc; /* port_source_t pointer */ int it_portfd; /* port file descriptor */ -} itimer_t; +}; + +#define it_sigq __data.__proc.__it_sigq +#define it_lwp __data.__proc.__it_lwp +#define it_frontend __data.__it_frontend typedef struct clock_backend { struct sigevent clk_default; int (*clk_clock_settime)(timespec_t *); int (*clk_clock_gettime)(timespec_t *); int (*clk_clock_getres)(timespec_t *); - int (*clk_timer_create)(itimer_t *, struct sigevent *); + int (*clk_timer_create)(itimer_t *, void (*)(itimer_t *)); int (*clk_timer_settime)(itimer_t *, int, const struct itimerspec *); int (*clk_timer_gettime)(itimer_t *, struct itimerspec *); int (*clk_timer_delete)(itimer_t *); @@ -88,8 +105,8 @@ typedef struct clock_backend { } clock_backend_t; extern void clock_add_backend(clockid_t clock, clock_backend_t *backend); +extern clock_backend_t *clock_get_backend(clockid_t clock); -extern void timer_fire(itimer_t *); extern void timer_lwpbind(); extern void timer_func(sigqueue_t *); diff --git a/usr/src/uts/common/sys/timerfd.h b/usr/src/uts/common/sys/timerfd.h new file mode 100644 index 0000000000..66cb50ac88 --- /dev/null +++ b/usr/src/uts/common/sys/timerfd.h @@ -0,0 +1,81 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2015 Joyent, Inc. All rights reserved. + */ + +/* + * Header file to support for the timerfd facility. + */ + +#ifndef _SYS_TIMERFD_H +#define _SYS_TIMERFD_H + +#include <sys/types.h> +#include <sys/time_impl.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * To assure binary compatibility with Linux, these values are fixed at their + * Linux equivalents, not their native ones. + */ +#define TFD_CLOEXEC 02000000 /* LX_O_CLOEXEC */ +#define TFD_NONBLOCK 04000 /* LX_O_NONBLOCK */ +#define TFD_TIMER_ABSTIME (1 << 0) +#define TFD_TIMER_CANCEL_ON_SET (1 << 1) + +/* + * These ioctl values are specific to the native implementation; applications + * shouldn't be using them directly, and they should therefore be safe to + * change without breaking apps. + */ +#define TIMERFDIOC (('t' << 24) | ('f' << 16) | ('d' << 8)) +#define TIMERFDIOC_CREATE (TIMERFDIOC | 1) /* create timer */ +#define TIMERFDIOC_SETTIME (TIMERFDIOC | 2) /* timerfd_settime() */ +#define TIMERFDIOC_GETTIME (TIMERFDIOC | 3) /* timerfd_gettime() */ + +typedef struct timerfd_settime { + uint64_t tfd_settime_flags; /* flags (e.g., TFD_TIMER_ABSTIME) */ + uint64_t tfd_settime_value; /* pointer to value */ + uint64_t tfd_settime_ovalue; /* pointer to old value, if any */ +} timerfd_settime_t; + +#ifndef _KERNEL + +extern int timerfd_create(int, int); +extern int timerfd_settime(int, int, + const struct itimerspec *, struct itimerspec *); +extern int timerfd_gettime(int, struct itimerspec *); + +#else + +#define TIMERFDMNRN_TIMERFD 0 +#define TIMERFDMNRN_CLONE 1 +#define TIMERFD_VALMAX (ULLONG_MAX - 1ULL) + +/* + * Fortunately, the values for the Linux clocks that are valid for timerfd + * (namely, CLOCK_REALTIME and CLOCK_MONOTONIC) don't overlap with our values + * the same. + */ +#define TIMERFD_MONOTONIC 1 /* Linux value for CLOCK_MONOTONIC */ + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIMERFD_H */ diff --git a/usr/src/uts/intel/Makefile.intel b/usr/src/uts/intel/Makefile.intel index 64b4962cae..18d05f23d0 100644 --- a/usr/src/uts/intel/Makefile.intel +++ b/usr/src/uts/intel/Makefile.intel @@ -21,6 +21,7 @@ # Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2015 Nexenta Systems, Inc. All rights reserved. # Copyright (c) 2013 Andrew Stormont. All rights reserved. +# Copyright (c) 2015, Joyent, Inc. All rights reserved. # # This makefile contains the common definitions for all intel @@ -338,6 +339,7 @@ DRV_KMODS += sysevent DRV_KMODS += sysmsg DRV_KMODS += tcp DRV_KMODS += tcp6 +DRV_KMODS += timerfd DRV_KMODS += tl DRV_KMODS += tnf DRV_KMODS += tpm diff --git a/usr/src/uts/intel/timerfd/Makefile b/usr/src/uts/intel/timerfd/Makefile new file mode 100644 index 0000000000..28cf8fd41e --- /dev/null +++ b/usr/src/uts/intel/timerfd/Makefile @@ -0,0 +1,68 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2015 Joyent, Inc. All rights reserved. +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = timerfd +OBJECTS = $(TIMERFD_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(TIMERFD_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(USR_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/io + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +CERRWARN += -_gcc=-Wno-parentheses + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ diff --git a/usr/src/uts/sparc/Makefile.sparc b/usr/src/uts/sparc/Makefile.sparc index d7c45a396e..29e4cd7ccf 100644 --- a/usr/src/uts/sparc/Makefile.sparc +++ b/usr/src/uts/sparc/Makefile.sparc @@ -21,6 +21,7 @@ # Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2013 Andrew Stormont. All rights reserved. +# Copyright (c) 2015, Joyent, Inc. All rights reserved. # Copyright 2015 Nexenta Systems, Inc. All rights reserved. diff --git a/usr/src/uts/sparc/timerfd/Makefile b/usr/src/uts/sparc/timerfd/Makefile new file mode 100644 index 0000000000..969ca6dd1a --- /dev/null +++ b/usr/src/uts/sparc/timerfd/Makefile @@ -0,0 +1,68 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2015 Joyent, Inc. All rights reserved. +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = timerfd +OBJECTS = $(TIMERFD_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(TIMERFD_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(USR_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/io + +# +# Include common rules. +# +include $(UTSBASE)/sparc/Makefile.sparc + +CERRWARN += -_gcc=-Wno-parentheses + +# +# Define targets +# +ALL_TARGET = $(BINARY) $(SRC_CONFILE) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ |