Index: lib/libc/gen/Makefile.inc =================================================================== --- lib/libc/gen/Makefile.inc +++ lib/libc/gen/Makefile.inc @@ -38,6 +38,7 @@ err.c \ errlst.c \ errno.c \ + eventfd_rw.c \ exec.c \ fdevname.c \ feature_present.c \ Index: lib/libc/gen/Symbol.map =================================================================== --- lib/libc/gen/Symbol.map +++ lib/libc/gen/Symbol.map @@ -410,6 +410,8 @@ }; FBSD_1.4 { + eventfd_read; + eventfd_write; scandir_b; }; Index: lib/libc/gen/eventfd_rw.c =================================================================== --- /dev/null +++ lib/libc/gen/eventfd_rw.c @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2015 Dmitry Chagin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +int +eventfd_read(int fd, eventfd_t *value) +{ + int bytes; + + bytes = read(fd, value, sizeof(eventfd_t)); + if (bytes != sizeof(eventfd_t)) + return (-1); + else + return (0); +} + +int +eventfd_write(int fd, eventfd_t value) +{ + int bytes; + + bytes = write(fd, &value, sizeof(eventfd_t)); + if (bytes != sizeof(eventfd_t)) + return (-1); + else + return (0); +} Index: lib/libc/sys/Makefile.inc =================================================================== --- lib/libc/sys/Makefile.inc +++ lib/libc/sys/Makefile.inc @@ -166,6 +166,7 @@ cpuset.2 \ cpuset_getaffinity.2 \ dup.2 \ + eventfd.2 \ execve.2 \ _exit.2 \ extattr_get_file.2 \ @@ -352,6 +353,8 @@ cpuset.2 cpuset_setid.2 MLINKS+=cpuset_getaffinity.2 cpuset_setaffinity.2 MLINKS+=dup.2 dup2.2 +MLINKS+=eventfd.2 eventfd_read.2 \ + eventfd.2 eventfd_write.2 MLINKS+=execve.2 fexecve.2 MLINKS+=extattr_get_file.2 extattr.2 \ extattr_get_file.2 extattr_delete_fd.2 \ Index: lib/libc/sys/Symbol.map =================================================================== --- lib/libc/sys/Symbol.map +++ lib/libc/sys/Symbol.map @@ -397,6 +397,7 @@ }; FBSD_1.4 { + eventfd; futimens; ppoll; utimensat; Index: lib/libc/sys/eventfd.2 =================================================================== --- /dev/null +++ lib/libc/sys/eventfd.2 @@ -0,0 +1,259 @@ +.\" Copyright (c) Davide Libenzi +.\" Copyright (c) 2008 Michael Kerrisk +.\" Copyright (c) 2015 Dmitry Chagin +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd March 28, 2015 +.Dt EVENTFD 2 +.Os +.Sh NAME +.Nm eventfd +.Nd interprocess communication mechanism +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/eventfd.h +.Ft int +.Fn eventfd "unsigned int initval" "int flags" +.Bd -literal +typedef uint64_t eventfd_t; +.Ed +.Pp +.Ft int +.Fn eventfd_read "int fd" "eventfd_t *value" +.Pp +.Ft int +.Fn eventfd_write "int fd" "eventfd_t value" +.Sh DESCRIPTION +The +.Fn eventfd +function creates an "eventfd object" that can be used +as an event wait/notify mechanism by user-space applications. +The eventfd object points to the 64-bit integer counter that is +maintained by the kernel. +This counter is initialized with the value specified in the argument +.Fa initval . +.Pp +The +.Fa flags +field can contain the following values: +.Bl -tag -width EFD_SEMAPHORE +.It Dv EFD_CLOEXEC +Set the close-on-exec flag on an eventfd file descriptor, +associated with the new eventfd object. +.It Dv EFD_NONBLOCK +Set the O_NONBLOCK file status on an eventfd file descriptor, +associated with the new eventfd object. +.It Dv EFD_SEMAPHORE +Provide semaphore-like semantics for reads from the new +eventfd object. +.El +.Pp +The following operations can be performed on the +eventfd file descriptor: +.Bl -tag -width EFD_SEMAPHORE +.It Xr read 2 +Each successful +.Xr read 2 +returns an 64-bit integer. A +.Xr read 2 +will fail with the error +.Dv EINVAL +if the size of the +supplied buffer is less than 8 bytes. +.Pp +The semantics of +.Xr read 2 +depend on whether the eventfd counter currently has +a nonzero value and whether the +.Dv EFD_SEMAPHORE +flag was specified when creating the eventfd object: +.Bl -tag -width * +.It * +If +.Dv EFD_SEMAPHORE +was not specified and the eventfd counter has a nonzero value, +then a +.Xr read 2 +returns 8 bytes containing that value, and the counter's value +is reset to zero. +.It * +If +.Dv EFD_SEMAPHORE +was specified and the eventfd counter has a nonzero value, +then a +.Xr read 2 +returns 8 bytes containing the value 1, and the counter's +value is decremented by 1. +.It * +If the eventfd counter is zero at the time of the call to +.Xr read 2 , +then the call either blocks until the counter becomes nonzero +(at which time, the +.Xr read 2 +proceeds as described above) or fails with the error +.Dv EAGAIN +if the eventfd file descriptor has been made nonblocking. +.El +.It Xr write 2 +A +.Xr write 2 +call adds the 64-bit integer value supplied in its buffer +to the counter. +The maximum value that may be stored in the counter is the +largest unsigned 64-bit value minus 1 (i.e., 0xfffffffffffffffe). +.Pp +If the addition would cause the +counter's value to exceed the maximum, then the +.Xr write 2 +either blocks until a +.Xr read 2 +is performed on the eventfd file descriptor, or fails with the error +.Dv EAGAIN +if the eventfd file descriptor has been made nonblocking. +.Pp +A +.Xr write 2 +will fail with the error +.Dv EINVAL +if the size of the supplied +buffer is less than 8 bytes, or if an attempt is made to +write the value 0xffffffffffffffff. +.It Xr poll 2 +The eventfd file descriptor supports +.Xr poll 2 +as follows: +.Bl -tag -width * +.It * +The eventfd file descriptor is readable if the counter has a value +greater than 0. +.It * +The eventfd file descriptor is writable if it is possible to write +a value of at least "1" without blocking. +.It * +If an overflow of the counter value was detected, then +.Xr select 2 +indicates the eventfd file descriptor as being both readable and +writable, and +.Xr poll 2 +returns a +.Fa POLLERR +event. +As noted above, +.Xr write 2 +can never overflow the counter. +.El +.Pp +The eventfd file descriptor also supports the other file- +descriptor multiplexing APIs: +.Xr kqueue 2 , +.Xr pselect 2 , +.Xr select 2 +and +.Xr ppoll 2 . +.It Xr close 2 +When the eventfd object is no longer required it should be closed. +When all file descriptors associated with the same eventfd object +have been closed, the resources for object are freed by the kernel. +.El +.Pp +A copy of the eventfd file descriptor created by +.Fn eventfd +is inherited by the child produced by +.Xr fork 2 . +The duplicate eventfd file descriptor is associated with the same +eventfd object. +File descriptors created by +.Fn eventfd +are preserved across +.Xr execve 2 , +unless the close-on-exec flag has been set. +.Pp +The +.Fn eventfd_read +and +.Fn eventfd_write +functions perform the read and write operations on an eventfd +file descriptor. +.Sh NOTES +Applications can use an eventfd object +instead of a +.Xr pipe 2 +in all cases where a +.Xr pipe 2 +is used simply to signal events. +The kernel overhead of an eventfd object is much lower than +that of a +.Xr pipe 2 , +and only one file descriptor is required. +.Pp +A key point about an eventfd object is that it can +be monitored just like any other file descriptor using +.Xr select 2 , +.Xr poll 2 . +.Sh RETURN VALUES +On success, +.Fn eventfd +returns a file descriptor, associated with the new eventfd object. +On error, -1 is returned and errno is set to indicate the error. +.Pp +The +.Fn eventfd_read +and +.Fn eventfd_write +functions return 0 if the correct number of bytes was transferred, +or -1 otherwise. +.Sh ERRORS +The +.Fn eventfd +function call fails if: +.Bl -tag -width Er +.It Bq Er EINVAL +The unsupported value was specified in +.Fa flags . +.It Bq Er EMFILE +The process has already reached its limit for open +file descriptors. +.It Bq Er ENFILE +The system file table is full. +.It Bq Er ENOMEM +No memory was available to create new eventfd object. +.El +.Sh SEE ALSO +.Xr close 2 , +.Xr kqueue 2 , +.Xr poll 2 , +.Xr ppoll 2 , +.Xr pselect 2 , +.Xr read 2 , +.Xr select 2 , +.Xr write 2 +.Sh HISTORY +The +.Fn eventfd +function is based on a similar feature of Linux and first +appeared in +.Fx 11.0 Index: sys/compat/freebsd32/syscalls.master =================================================================== --- sys/compat/freebsd32/syscalls.master +++ sys/compat/freebsd32/syscalls.master @@ -1074,3 +1074,5 @@ 547 AUE_FUTIMESAT STD { int freebsd32_utimensat(int fd, \ char *path, \ struct timespec *times, int flag); } +548 AUE_NULL NOPROTO { int eventfd(unsigned int initval, \ + int flags); } Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -2996,6 +2996,7 @@ kern/kern_environment.c standard kern/kern_et.c standard kern/kern_event.c standard +kern/kern_eventfd.c standard kern/kern_exec.c standard kern/kern_exit.c standard kern/kern_fail.c standard Index: sys/kern/kern_eventfd.c =================================================================== --- /dev/null +++ sys/kern/kern_eventfd.c @@ -0,0 +1,411 @@ +/*- + * Copyright (c) 2015 Dmitry Chagin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static uma_zone_t eventfd_zone; + +static fo_rdwr_t eventfd_read; +static fo_rdwr_t eventfd_write; +static fo_truncate_t eventfd_truncate; +static fo_ioctl_t eventfd_ioctl; +static fo_poll_t eventfd_poll; +static fo_kqfilter_t eventfd_kqfilter; +static fo_stat_t eventfd_stat; +static fo_close_t eventfd_close; +static fo_fill_kinfo_t eventfd_fill_kinfo; + +static struct fileops eventfdops = { + .fo_read = eventfd_read, + .fo_write = eventfd_write, + .fo_truncate = eventfd_truncate, + .fo_ioctl = eventfd_ioctl, + .fo_poll = eventfd_poll, + .fo_kqfilter = eventfd_kqfilter, + .fo_stat = eventfd_stat, + .fo_close = eventfd_close, + .fo_chmod = invfo_chmod, + .fo_chown = invfo_chown, + .fo_sendfile = invfo_sendfile, + .fo_fill_kinfo = eventfd_fill_kinfo, + .fo_flags = DFLAG_PASSABLE +}; + +static void filt_eventfddetach(struct knote *kn); +static int filt_eventfdread(struct knote *kn, long hint); +static int filt_eventfdwrite(struct knote *kn, long hint); + +static struct filterops eventfd_rfiltops = { + .f_isfd = 1, + .f_detach = filt_eventfddetach, + .f_event = filt_eventfdread +}; +static struct filterops eventfd_wfiltops = { + .f_isfd = 1, + .f_detach = filt_eventfddetach, + .f_event = filt_eventfdwrite +}; + +struct eventfd { + eventfd_t efd_count; + int efd_flags; + struct selinfo efd_sel; + struct mtx efd_lock; +}; + +static void eventfdinit(void); +static int eventfd_init(); +static void eventfd_fini(); + + +static int +eventfd_init(void *mem, int size, int flags) +{ + struct eventfd *efd; + + efd = (struct eventfd *)mem; + + mtx_init(&efd->efd_lock, "eventfd", NULL, MTX_DEF); + knlist_init_mtx(&efd->efd_sel.si_note, &efd->efd_lock); + return (0); +} + +static void +eventfd_fini(void *mem, int size) +{ + struct eventfd *efd; + + efd = (struct eventfd *)mem; + + knlist_destroy(&efd->efd_sel.si_note); + mtx_destroy(&efd->efd_lock); +} + +static void +eventfdinit() +{ + + eventfd_zone = uma_zcreate("eventfd", sizeof(struct eventfd), + NULL, NULL, eventfd_init, eventfd_fini, UMA_ALIGN_PTR, 0); +} +SYSINIT(eventfd, SI_SUB_PSEUDO, SI_ORDER_ANY, eventfdinit, NULL); + +int +sys_eventfd(struct thread *td, struct eventfd_args *args) +{ + struct filedesc *fdp; + struct eventfd *efd; + struct file *fp; + int fflags, fd; + int error; + + if ((args->flags & ~(EFD_CLOEXEC|EFD_NONBLOCK|EFD_SEMAPHORE)) != 0) + return (EINVAL); + + fflags = 0; + if ((args->flags & EFD_CLOEXEC) != 0) + fflags |= O_CLOEXEC; + + fdp = td->td_proc->p_fd; + error = falloc(td, &fp, &fd, fflags); + if (error != 0) + return (error); + + efd = uma_zalloc(eventfd_zone, M_WAITOK); + efd->efd_flags = args->flags; + efd->efd_count = args->initval; + + fflags = FREAD | FWRITE; + if ((args->flags & EFD_NONBLOCK) != 0) + fflags |= FNONBLOCK; + + finit(fp, fflags, DTYPE_EVENTFD, efd, &eventfdops); + fdrop(fp, td); + + td->td_retval[0] = fd; + return (error); +} + +static int +eventfd_close(struct file *fp, struct thread *td) +{ + struct eventfd *efd; + + efd = fp->f_data; + if (fp->f_type != DTYPE_EVENTFD || efd == NULL) + return (EBADF); + + seldrain(&efd->efd_sel); + fp->f_ops = &badfileops; + uma_zfree(eventfd_zone, efd); + return (0); +} + +static int +eventfd_read(struct file *fp, struct uio *uio, struct ucred *active_cred, + int flags, struct thread *td) +{ + struct eventfd *efd; + eventfd_t count; + int error; + + efd = fp->f_data; + if (fp->f_type != DTYPE_EVENTFD || efd == NULL) + return (EBADF); + + if (uio->uio_resid < sizeof(eventfd_t)) + return (EINVAL); + + error = 0; + mtx_lock(&efd->efd_lock); + retry: + if (efd->efd_count == 0) { + if ((efd->efd_flags & EFD_NONBLOCK) != 0) { + mtx_unlock(&efd->efd_lock); + return (EAGAIN); + } + error = mtx_sleep(&efd->efd_count, &efd->efd_lock, + PCATCH, "evfdrd", 0); + if (error == 0) + goto retry; + } + if (error == 0) { + if ((efd->efd_flags & EFD_SEMAPHORE) != 0) { + count = 1; + --efd->efd_count; + } else { + count = efd->efd_count; + efd->efd_count = 0; + } + KNOTE_LOCKED(&efd->efd_sel.si_note, 0); + selwakeup(&efd->efd_sel); + wakeup(&efd->efd_count); + mtx_unlock(&efd->efd_lock); + error = uiomove(&count, sizeof(eventfd_t), uio); + } else + mtx_unlock(&efd->efd_lock); + + return (error); +} + +static int +eventfd_write(struct file *fp, struct uio *uio, struct ucred *active_cred, + int flags, struct thread *td) +{ + struct eventfd *efd; + eventfd_t count; + int error; + + efd = fp->f_data; + if (fp->f_type != DTYPE_EVENTFD || efd == NULL) + return (EBADF); + + if (uio->uio_resid < sizeof(eventfd_t)) + return (EINVAL); + + error = uiomove(&count, sizeof(eventfd_t), uio); + if (error != 0) + return (error); + if (count == UINT64_MAX) + return (EINVAL); + + mtx_lock(&efd->efd_lock); + retry: + if (UINT64_MAX - efd->efd_count <= count) { + if ((efd->efd_flags & EFD_NONBLOCK) != 0) { + mtx_unlock(&efd->efd_lock); + return (EAGAIN); + } + error = mtx_sleep(&efd->efd_count, &efd->efd_lock, + PCATCH, "evfdwr", 0); + if (error == 0) + goto retry; + } + if (error == 0) { + efd->efd_count += count; + KNOTE_LOCKED(&efd->efd_sel.si_note, 0); + selwakeup(&efd->efd_sel); + wakeup(&efd->efd_count); + } + mtx_unlock(&efd->efd_lock); + + return (error); +} + +static int +eventfd_poll(struct file *fp, int events, struct ucred *active_cred, + struct thread *td) +{ + struct eventfd *efd; + int revents = 0; + + efd = fp->f_data; + if (fp->f_type != DTYPE_EVENTFD || efd == NULL) + return (POLLERR); + + mtx_lock(&efd->efd_lock); + if ((events & (POLLIN|POLLRDNORM)) && efd->efd_count > 0) + revents |= events & (POLLIN|POLLRDNORM); + if ((events & (POLLOUT|POLLWRNORM)) && UINT64_MAX - 1 > efd->efd_count) + revents |= events & (POLLOUT|POLLWRNORM); + if (revents == 0) + selrecord(td, &efd->efd_sel); + mtx_unlock(&efd->efd_lock); + + return (revents); +} + +/*ARGSUSED*/ +static int +eventfd_kqfilter(struct file *fp, struct knote *kn) +{ + struct eventfd *efd; + + efd = fp->f_data; + if (fp->f_type != DTYPE_EVENTFD || efd == NULL) + return (EINVAL); + + mtx_lock(&efd->efd_lock); + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &eventfd_rfiltops; + break; + case EVFILT_WRITE: + kn->kn_fop = &eventfd_wfiltops; + break; + default: + mtx_unlock(&efd->efd_lock); + return (EINVAL); + } + + kn->kn_hook = efd; + knlist_add(&efd->efd_sel.si_note, kn, 1); + mtx_unlock(&efd->efd_lock); + + return (0); +} + +static void +filt_eventfddetach(struct knote *kn) +{ + struct eventfd *efd = kn->kn_hook; + + mtx_lock(&efd->efd_lock); + knlist_remove(&efd->efd_sel.si_note, kn, 1); + mtx_unlock(&efd->efd_lock); +} + +/*ARGSUSED*/ +static int +filt_eventfdread(struct knote *kn, long hint) +{ + struct eventfd *efd = kn->kn_hook; + int ret; + + mtx_assert(&efd->efd_lock, MA_OWNED); + ret = (efd->efd_count > 0); + + return (ret); +} + +/*ARGSUSED*/ +static int +filt_eventfdwrite(struct knote *kn, long hint) +{ + struct eventfd *efd = kn->kn_hook; + int ret; + + mtx_assert(&efd->efd_lock, MA_OWNED); + ret = (UINT64_MAX - 1 > efd->efd_count); + + return (ret); +} + +/*ARGSUSED*/ +static int +eventfd_truncate(struct file *fp, off_t length, struct ucred *active_cred, + struct thread *td) +{ + + return (ENXIO); +} + +/*ARGSUSED*/ +static int +eventfd_ioctl(struct file *fp, u_long cmd, void *data, + struct ucred *active_cred, struct thread *td) +{ + + return (ENXIO); +} + +/*ARGSUSED*/ +static int +eventfd_stat(struct file *fp, struct stat *st, struct ucred *active_cred, + struct thread *td) +{ + + return (ENXIO); +} + +/*ARGSUSED*/ +static int +eventfd_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp) +{ + struct eventfd *efd; + + efd = fp->f_data; + if (fp->f_type != DTYPE_EVENTFD || efd == NULL) + return (EINVAL); + + mtx_lock(&efd->efd_lock); + kif->kf_un.kf_file.kf_file_size = efd->efd_count; + mtx_unlock(&efd->efd_lock); + + kif->kf_un.kf_file.kf_file_rdev = efd->efd_flags; + kif->kf_type = KF_TYPE_EVENTFD; + return (0); +} Index: sys/kern/syscalls.master =================================================================== --- sys/kern/syscalls.master +++ sys/kern/syscalls.master @@ -988,5 +988,7 @@ 547 AUE_FUTIMESAT STD { int utimensat(int fd, \ char *path, \ struct timespec *times, int flag); } +548 AUE_NULL STD { int eventfd(unsigned int initval, \ + int flags); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master Index: sys/sys/eventfd.h =================================================================== --- /dev/null +++ sys/sys/eventfd.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2015 Dmitry Chagin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_EVENTFD_H_ +#define _SYS_EVENTFD_H_ + +#define EFD_SEMAPHORE 0x0001 +#define EFD_CLOEXEC 0x0002 +#define EFD_NONBLOCK 0x0004 + +#ifndef _KERNEL +#include +#endif + +typedef uint64_t eventfd_t; + +#ifndef _KERNEL +__BEGIN_DECLS +int eventfd(unsigned int initval, int flags); +int eventfd_read(int fd, eventfd_t *value); +int eventfd_write(int fd, eventfd_t value); +__END_DECLS +#endif + +#endif /* !_SYS_EVENTFD_H_ */ Index: sys/sys/file.h =================================================================== --- sys/sys/file.h +++ sys/sys/file.h @@ -66,6 +66,7 @@ #define DTYPE_PTS 10 /* pseudo teletype master device */ #define DTYPE_DEV 11 /* Device specific fd type */ #define DTYPE_PROCDESC 12 /* process descriptor */ +#define DTYPE_EVENTFD 13 /* eventfd type */ #ifdef _KERNEL Index: sys/sys/user.h =================================================================== --- sys/sys/user.h +++ sys/sys/user.h @@ -258,6 +258,7 @@ #define KF_TYPE_SEM 9 #define KF_TYPE_PTS 10 #define KF_TYPE_PROCDESC 11 +#define KF_TYPE_EVENTFD 12 #define KF_TYPE_UNKNOWN 255 #define KF_VTYPE_VNON 0