This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new a4a9eb2  fs/vfs: Add file descriptor based events support
a4a9eb2 is described below

commit a4a9eb2f5a86896c1af447925bd60d5471c0b677
Author: spiriou <simon.pir...@korys.io>
AuthorDate: Tue Jul 28 13:08:48 2020 +0200

    fs/vfs: Add file descriptor based events support
---
 fs/Kconfig                      |  28 ++
 fs/vfs/Make.defs                |   6 +
 fs/vfs/fs_eventfd.c             | 663 ++++++++++++++++++++++++++++++++++++++++
 include/nuttx/fs/ioctl.h        |  13 +-
 include/sys/eventfd.h           |  75 +++++
 include/sys/syscall_lookup.h    |   3 +
 libs/libc/Makefile              |   1 +
 libs/libc/eventfd/Make.defs     |  27 ++
 libs/libc/eventfd/lib_eventfd.c |  57 ++++
 syscall/syscall.csv             |   1 +
 10 files changed, 873 insertions(+), 1 deletion(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index d0055ed..cce2d2a 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -53,6 +53,34 @@ config PSEUDOFS_SOFTLINKS
                to link a directory in the pseudo-file system, such as /bin, to
                to a directory in a mounted volume, say /mnt/sdcard/bin.
 
+config EVENT_FD
+       bool "EventFD"
+       default n
+       ---help---
+               Create a file descriptor for event notification
+
+if EVENT_FD
+
+config EVENT_FD_VFS_PATH
+    string "Path to eventfd storage"
+    default "/var/event"
+    ---help---
+        The path to where eventfd will exist in the VFS namespace.
+
+config EVENT_FD_POLL
+       bool "EventFD poll support"
+       default y
+       ---help---
+               Poll support for file descriptor based events
+
+config EVENT_FD_NPOLLWAITERS
+       int "Number of eventFD poll waiters"
+       default 2
+       ---help---
+               Maximum number of threads that can be waiting on poll()
+
+endif # EVENT_FD
+
 source fs/aio/Kconfig
 source fs/semaphore/Kconfig
 source fs/mqueue/Kconfig
diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs
index b8bb9e6..5969d64 100644
--- a/fs/vfs/Make.defs
+++ b/fs/vfs/Make.defs
@@ -66,6 +66,12 @@ ifeq ($(CONFIG_NET_SENDFILE),y)
 CSRCS += fs_sendfile.c
 endif
 
+# Support for eventfd
+
+ifeq ($(CONFIG_EVENT_FD),y)
+CSRCS += fs_eventfd.c
+endif
+
 # Include vfs build support
 
 DEPPATH += --dep-path vfs
diff --git a/fs/vfs/fs_eventfd.c b/fs/vfs/fs_eventfd.c
new file mode 100644
index 0000000..80a2d00
--- /dev/null
+++ b/fs/vfs/fs_eventfd.c
@@ -0,0 +1,663 @@
+/****************************************************************************
+ * vfs/fs_eventfd.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdio.h>
+#include <poll.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <debug.h>
+
+#include <sys/ioctl.h>
+#include <sys/eventfd.h>
+
+#include "inode/inode.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_EVENT_FD_VFS_PATH
+#define CONFIG_EVENT_FD_VFS_PATH "/dev"
+#endif
+
+#ifndef CONFIG_EVENT_FD_NPOLLWAITERS
+/* Maximum number of threads than can be waiting for POLL events */
+#define CONFIG_EVENT_FD_NPOLLWAITERS 2
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef struct eventfd_waiter_sem_s
+{
+  sem_t sem;
+  struct eventfd_waiter_sem_s *next;
+} eventfd_waiter_sem_t;
+
+/* This structure describes the internal state of the driver */
+
+struct eventfd_priv_s
+{
+  sem_t     exclsem;            /* Enforces device exclusive access */
+  eventfd_waiter_sem_t *rdsems; /* List of blocking readers */
+  eventfd_waiter_sem_t *wrsems; /* List of blocking writers */
+  eventfd_t counter;            /* eventfd counter */
+  uint8_t   minor;              /* eventfd minor number */
+  uint8_t   crefs;              /* References counts on eventfd (max: 255) */
+  uint8_t   mode_semaphore;     /* eventfd mode (semaphore or counter) */
+
+  /* The following is a list if poll structures of threads waiting for
+   * driver events.
+   */
+
+#ifdef CONFIG_EVENT_FD_POLL
+  FAR struct pollfd *fds[CONFIG_EVENT_FD_NPOLLWAITERS];
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int eventfd_do_open(FAR struct file *filep);
+static int eventfd_do_close(FAR struct file *filep);
+
+static ssize_t eventfd_do_read(FAR struct file *filep, FAR char *buffer,
+                               size_t len);
+static ssize_t eventfd_do_write(FAR struct file *filep,
+                                FAR const char *buffer, size_t len);
+static int eventfd_do_ioctl(FAR struct file *filep, int cmd,
+                            unsigned long arg);
+#ifdef CONFIG_EVENT_FD_POLL
+static int eventfd_do_poll(FAR struct file *filep, FAR struct pollfd *fds,
+                       bool setup);
+
+static void eventfd_pollnotify(FAR struct eventfd_priv_s *dev,
+                               pollevent_t eventset);
+#endif
+
+static int eventfd_blocking_io(FAR struct eventfd_priv_s *dev,
+                               eventfd_waiter_sem_t *sem,
+                               FAR eventfd_waiter_sem_t **slist);
+
+static int eventfd_get_unique_minor(void);
+static void eventfd_release_minor(int minor);
+
+static FAR struct eventfd_priv_s *eventfd_allocdev(void);
+static void eventfd_destroy(FAR struct eventfd_priv_s *dev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_eventfd_fops =
+{
+  eventfd_do_open,  /* open */
+  eventfd_do_close, /* close */
+  eventfd_do_read,  /* read */
+  eventfd_do_write, /* write */
+  0,                /* seek */
+  eventfd_do_ioctl  /* ioctl */
+#ifdef CONFIG_EVENT_FD_POLL
+  , eventfd_do_poll /* poll */
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static FAR struct eventfd_priv_s *eventfd_allocdev(void)
+{
+  FAR struct eventfd_priv_s *dev;
+
+  dev = (FAR struct eventfd_priv_s *)
+    kmm_zalloc(sizeof(struct eventfd_priv_s));
+  if (dev)
+    {
+      /* Initialize the private structure */
+
+      nxsem_init(&dev->exclsem, 0, 0);
+    }
+
+  return dev;
+}
+
+static void eventfd_destroy(FAR struct eventfd_priv_s *dev)
+{
+  nxsem_destroy(&dev->exclsem);
+  kmm_free(dev);
+}
+
+#ifdef CONFIG_EVENT_FD_POLL
+static void eventfd_pollnotify(FAR struct eventfd_priv_s *dev,
+                               pollevent_t eventset)
+{
+  FAR struct pollfd *fds;
+  int i;
+
+  for (i = 0; i < CONFIG_EVENT_FD_NPOLLWAITERS; i++)
+    {
+      fds = dev->fds[i];
+      if (fds)
+        {
+          fds->revents |= eventset & fds->events;
+
+          if (fds->revents != 0)
+            {
+              nxsem_post(fds->sem);
+            }
+        }
+    }
+}
+#endif
+
+static int eventfd_get_unique_minor(void)
+{
+  static int minor = 0;
+
+  /* TODO reimplement this with minor bit map ?
+   * Current logic will not behave correctly after
+   * a minor overflow (> 255 eventfd created)
+   */
+
+  return (minor++) & 0xff;
+}
+
+static void eventfd_release_minor(int minor)
+{
+}
+
+static int eventfd_do_open(FAR struct file *filep)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct eventfd_priv_s *priv = inode->i_private;
+  int ret;
+
+  /* Get exclusive access to the device structures */
+
+  ret = nxsem_wait(&priv->exclsem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  finfo("crefs: %d <%s>\n", priv->crefs, inode->i_name);
+
+  if (priv->crefs >= 255)
+    {
+      /* More than 255 opens; uint8_t would overflow to zero */
+
+      ret = -EMFILE;
+    }
+  else
+    {
+      /* Save the new open count on success */
+
+      priv->crefs += 1;
+      ret = OK;
+    }
+
+  nxsem_post(&priv->exclsem);
+  return ret;
+}
+
+static int eventfd_do_close(FAR struct file *filep)
+{
+  int ret;
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct eventfd_priv_s *priv = inode->i_private;
+
+  /* devpath: EVENT_FD_VFS_PATH + /efd (4) + %d (3) + null char (1) */
+
+  char devpath[sizeof(CONFIG_EVENT_FD_VFS_PATH) + 4 + 3 + 1];
+
+  /* Get exclusive access to the device structures */
+
+  ret = nxsem_wait(&priv->exclsem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  finfo("crefs: %d <%s>\n", priv->crefs, inode->i_name);
+
+  /* Decrement the references to the driver.  If the reference count will
+   * decrement to 0, then uninitialize the driver.
+   */
+
+  if (priv->crefs > 1)
+    {
+      /* Just decrement the reference count and release the semaphore */
+
+      priv->crefs -= 1;
+      nxsem_post(&priv->exclsem);
+      return OK;
+    }
+
+  /* Re-create the path to the driver. */
+
+  finfo("destroy\n");
+  sprintf(devpath, CONFIG_EVENT_FD_VFS_PATH "/efd%d", priv->minor);
+
+  /* Will be unregistered later after close is done */
+
+  unregister_driver(devpath);
+
+  DEBUGASSERT(priv->exclsem.semcount == 0);
+  eventfd_release_minor(priv->minor);
+  eventfd_destroy(priv);
+
+  return OK;
+}
+
+static int eventfd_blocking_io(FAR struct eventfd_priv_s *dev,
+                               eventfd_waiter_sem_t *sem,
+                               FAR eventfd_waiter_sem_t **slist)
+{
+  int ret;
+  sem->next = *slist;
+  *slist = sem;
+
+  nxsem_post(&dev->exclsem);
+
+  /* Wait for eventfd to notify */
+
+  ret = nxsem_wait(&sem->sem);
+
+  if (ret < 0)
+    {
+      /* Interrupted wait, unregister semaphore
+       * TODO ensure that exclsem wait does not fail (ECANCELED)
+       */
+
+      nxsem_wait_uninterruptible(&dev->exclsem);
+
+      eventfd_waiter_sem_t *cur_sem = *slist;
+
+      if (cur_sem == sem)
+        {
+          *slist = sem->next;
+        }
+      else
+        {
+          while (cur_sem)
+            {
+              if (cur_sem->next == sem)
+                {
+                  cur_sem->next = sem->next;
+                  break;
+                }
+            }
+        }
+
+      nxsem_post(&dev->exclsem);
+      return ret;
+    }
+
+  return nxsem_wait(&dev->exclsem);
+}
+
+static ssize_t eventfd_do_read(FAR struct file *filep, FAR char *buffer,
+                               size_t len)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct eventfd_priv_s *dev = inode->i_private;
+  ssize_t ret;
+
+  if (len < sizeof(eventfd_t) || buffer == NULL)
+    {
+      return -EINVAL;
+    }
+
+  ret = nxsem_wait(&dev->exclsem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Wait for an incoming event */
+
+  if (dev->counter == 0)
+    {
+      if (filep->f_oflags & O_NONBLOCK)
+        {
+          nxsem_post(&dev->exclsem);
+          return -EAGAIN;
+        }
+
+      eventfd_waiter_sem_t sem;
+      nxsem_init(&sem.sem, 0, 0);
+      nxsem_set_protocol(&sem.sem, SEM_PRIO_NONE);
+
+      do
+        {
+          ret = eventfd_blocking_io(dev, &sem, &dev->rdsems);
+          if (ret < 0)
+            {
+              nxsem_destroy(&sem.sem);
+              return ret;
+            }
+        }
+      while (dev->counter == 0);
+
+      nxsem_destroy(&sem.sem);
+    }
+
+  /* Device ready for read */
+
+  if (dev->mode_semaphore)
+    {
+      *(FAR eventfd_t *)buffer = 1;
+      dev->counter -= 1;
+    }
+  else
+    {
+      *(FAR eventfd_t *)buffer = dev->counter;
+      dev->counter = 0;
+    }
+
+  /* Notify all waiting writers that counter have been decremented */
+
+  eventfd_waiter_sem_t *cur_sem = dev->wrsems;
+  while (cur_sem != NULL)
+    {
+      nxsem_post(&cur_sem->sem);
+      cur_sem = cur_sem->next;
+    }
+
+  dev->wrsems = NULL;
+
+#ifdef CONFIG_EVENT_FD_POLL
+  /* Notify all poll/select waiters */
+
+  eventfd_pollnotify(dev, POLLOUT);
+#endif
+
+  nxsem_post(&dev->exclsem);
+  return sizeof(eventfd_t);
+}
+
+static ssize_t eventfd_do_write(FAR struct file *filep,
+                                FAR const char *buffer, size_t len)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct eventfd_priv_s *dev = inode->i_private;
+  ssize_t ret;
+  eventfd_t new_counter;
+
+  if (len < sizeof(eventfd_t) || buffer == NULL ||
+      (*(FAR eventfd_t *)buffer == (eventfd_t)-1) ||
+      (*(FAR eventfd_t *)buffer == (eventfd_t)0))
+    {
+      return -EINVAL;
+    }
+
+  ret = nxsem_wait(&dev->exclsem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  new_counter = dev->counter + *(FAR eventfd_t *)buffer;
+
+  if (new_counter < dev->counter)
+    {
+      /* Overflow detected */
+
+      if (filep->f_oflags & O_NONBLOCK)
+        {
+          nxsem_post(&dev->exclsem);
+          return -EAGAIN;
+        }
+
+      eventfd_waiter_sem_t sem;
+      nxsem_init(&sem.sem, 0, 0);
+      nxsem_set_protocol(&sem.sem, SEM_PRIO_NONE);
+
+      do
+        {
+          ret = eventfd_blocking_io(dev, &sem, &dev->wrsems);
+          if (ret < 0)
+            {
+              nxsem_destroy(&sem.sem);
+              return ret;
+            }
+        }
+      while ((new_counter = dev->counter + *(FAR eventfd_t *)buffer)
+            < dev->counter);
+
+      nxsem_destroy(&sem.sem);
+    }
+
+  /* Ready to write, update counter */
+
+  dev->counter = new_counter;
+
+  /* Notify all of the waiting readers */
+
+  eventfd_waiter_sem_t *cur_sem = dev->rdsems;
+  while (cur_sem != NULL)
+    {
+      nxsem_post(&cur_sem->sem);
+      cur_sem = cur_sem->next;
+    }
+
+  dev->rdsems = NULL;
+
+#ifdef CONFIG_EVENT_FD_POLL
+  /* Notify all poll/select waiters */
+
+  eventfd_pollnotify(dev, POLLIN);
+#endif
+
+  nxsem_post(&dev->exclsem);
+  return sizeof(eventfd_t);
+}
+
+static int eventfd_do_ioctl(FAR struct file *filep, int cmd,
+                            unsigned long arg)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct eventfd_priv_s *priv = inode->i_private;
+
+  if (cmd == FIOC_MINOR)
+    {
+      *(FAR int *)((uintptr_t)arg) = priv->minor;
+      return OK;
+    }
+
+  return -ENOSYS;
+}
+
+#ifdef CONFIG_EVENT_FD_POLL
+static int eventfd_do_poll(FAR struct file *filep, FAR struct pollfd *fds,
+                        bool setup)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct eventfd_priv_s *dev = inode->i_private;
+  int ret;
+  int i;
+  pollevent_t eventset;
+
+  ret = nxsem_wait(&dev->exclsem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = OK;
+
+  if (!setup)
+    {
+      /* This is a request to tear down the poll. */
+
+      FAR struct pollfd **slot = (FAR struct pollfd **)fds->priv;
+
+      /* Remove all memory of the poll setup */
+
+      *slot                = NULL;
+      fds->priv            = NULL;
+      goto errout;
+    }
+
+  /* This is a request to set up the poll. Find an available
+   * slot for the poll structure reference
+   */
+
+  for (i = 0; i < CONFIG_EVENT_FD_NPOLLWAITERS; i++)
+    {
+      /* Find an available slot */
+
+      if (!dev->fds[i])
+        {
+          /* Bind the poll structure and this slot */
+
+          dev->fds[i] = fds;
+          fds->priv   = &dev->fds[i];
+          break;
+        }
+    }
+
+  if (i >= CONFIG_EVENT_FD_NPOLLWAITERS)
+    {
+      fds->priv = NULL;
+      ret       = -EBUSY;
+      goto errout;
+    }
+
+  /* Notify the POLLOUT event if the pipe is not full, but only if
+   * there is readers.
+   */
+
+  eventset = 0;
+  if (dev->counter < (eventfd_t)-1)
+    {
+      eventset |= POLLOUT;
+    }
+
+  /* Notify the POLLIN event if the pipe is not empty */
+
+  if (dev->counter > 0)
+    {
+      eventset |= POLLIN;
+    }
+
+  if (eventset)
+    {
+      eventfd_pollnotify(dev, eventset);
+    }
+
+errout:
+  nxsem_post(&dev->exclsem);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int eventfd(unsigned int count, int flags)
+{
+  int ret;
+  int new_fd;
+  unsigned int new_minor;
+  FAR struct eventfd_priv_s *new_dev;
+
+  /* devpath: EVENT_FD_VFS_PATH + /efd (4) + %d (3) + null char (1) */
+
+  char devpath[sizeof(CONFIG_EVENT_FD_VFS_PATH) + 4 + 3 + 1];
+
+  /* Allocate instance data for this driver */
+
+  new_dev = eventfd_allocdev();
+  if (new_dev == NULL)
+    {
+      /* Failed to allocate new device */
+
+      ret = ENOMEM;
+      goto exit_set_errno;
+    }
+
+  new_dev->counter = count;
+  new_dev->mode_semaphore = !!(flags & EFD_SEMAPHORE);
+
+  /* Request a unique minor device number */
+
+  new_minor = eventfd_get_unique_minor();
+
+  if (new_minor < 0)
+    {
+      ferr("Cannot get minor\n");
+      ret = -new_minor;
+      goto exit_free_new_dev;
+    }
+
+  new_dev->minor = new_minor;
+
+  /* Get device path */
+
+  sprintf(devpath, CONFIG_EVENT_FD_VFS_PATH "/efd%d", new_minor);
+
+  /* Register the driver */
+
+  ret = register_driver(devpath, &g_eventfd_fops, 0666, new_dev);
+  if (ret < 0)
+    {
+      ferr("Failed to register new device %s: %d\n", devpath, ret);
+      ret = -ret;
+      goto exit_release_minor;
+    }
+
+  /* Device is ready for use */
+
+  nxsem_post(&new_dev->exclsem);
+
+  /* Try open new device */
+
+  new_fd = open(devpath, O_RDWR |
+    (flags & (EFD_NONBLOCK | EFD_SEMAPHORE | EFD_CLOEXEC)));
+
+  if (new_fd < 0)
+    {
+      ret = -new_fd;
+      goto exit_unregister_driver;
+    }
+
+  return new_fd;
+
+exit_unregister_driver:
+  unregister_driver(devpath);
+exit_release_minor:
+  eventfd_release_minor(new_minor);
+exit_free_new_dev:
+  eventfd_destroy(new_dev);
+exit_set_errno:
+  set_errno(ret);
+  return ERROR;
+}
diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h
index a685599..42ccff7 100644
--- a/include/nuttx/fs/ioctl.h
+++ b/include/nuttx/fs/ioctl.h
@@ -121,6 +121,10 @@
 
 /* Terminal I/O IOCTL definitions are retained in tioctl.h */
 
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
 #include <nuttx/serial/tioctl.h>
 
 /* Watchdog driver ioctl commands *******************************************/
@@ -176,6 +180,10 @@
                                            *      int value.
                                            * OUT: Origin option.
                                            */
+#define FIOC_MINOR      _FIOC(0x000c)     /* IN:  None
+                                           * OUT: Integer that contains device
+                                           *      minor number
+                                           */
 
 /* NuttX file system ioctl definitions **************************************/
 
@@ -309,6 +317,7 @@
 #define _PWMIOC(nr)       _IOC(_PWMIOCBASE,nr)
 
 /* NuttX USB CDC/ACM serial driver ioctl definitions ************************/
+
 /* (see nuttx/usb/cdcacm.h) */
 
 #define _CAIOCVALID(c)    (_IOC_TYPE(c)==_CAIOCBASE)
@@ -322,6 +331,7 @@
 #define _BATIOC(nr)       _IOC(_BATIOCBASE,nr)
 
 /* NuttX Quadrature Encoder driver ioctl definitions ************************/
+
 /* (see nuttx/power/battery.h) */
 
 #define _QEIOCVALID(c)    (_IOC_TYPE(c)==_QEIOCBASE)
@@ -349,6 +359,7 @@
 #define _SLCDIOC(nr)      _IOC(_SLCDIOCBASE,nr)
 
 /* Wireless driver character driver ioctl definitions ***********************/
+
 /* (see nuttx/include/wireless/ioctl.h */
 
 #define _WLCIOCVALID(c)   (_IOC_TYPE(c)==_WLCIOCBASE)
@@ -368,7 +379,7 @@
 #define _TCIOCVALID(c)    (_IOC_TYPE(c)==_TCIOCBASE)
 #define _TCIOC(nr)        _IOC(_TCIOCBASE,nr)
 
-/* Joystick driver ioctl definitions ***************************************/
+/* Joystick driver ioctl definitions ****************************************/
 
 /* Discrete Joystick (see nuttx/include/input/djoystick.h */
 
diff --git a/include/sys/eventfd.h b/include/sys/eventfd.h
new file mode 100644
index 0000000..bb358b2
--- /dev/null
+++ b/include/sys/eventfd.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+ * include/sys/eventfd.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_SYS_EVENTFD_H
+#define __INCLUDE_SYS_EVENTFD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+#include <fcntl.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define EFD_NONBLOCK  O_NONBLOCK
+#define EFD_SEMAPHORE O_BINARY
+#define EFD_CLOEXEC   O_CLOEXEC
+
+/* Get device minor number */
+
+#define EFD_FIOC_MINOR FIOC_MINOR
+
+/****************************************************************************
+ * Public Type Declarations
+ ****************************************************************************/
+
+/* Type for event counter */
+
+typedef uint32_t eventfd_t;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+int eventfd(unsigned int count, int flags);
+
+int eventfd_read(int fd, FAR eventfd_t *value);
+int eventfd_write(int fd, eventfd_t value);
+
+int eventfd_get_minor(int fd);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_SYS_EVENTFD_H */
diff --git a/include/sys/syscall_lookup.h b/include/sys/syscall_lookup.h
index f07906a..9760e24 100644
--- a/include/sys/syscall_lookup.h
+++ b/include/sys/syscall_lookup.h
@@ -208,6 +208,9 @@ SYSCALL_LOOKUP(pwrite,                     4)
   SYSCALL_LOOKUP(select,                   5)
   SYSCALL_LOOKUP(ppoll,                    4)
   SYSCALL_LOOKUP(pselect,                  6)
+#ifdef CONFIG_EVENT_FD
+  SYSCALL_LOOKUP(eventfd,                  2)
+#endif
 #ifdef CONFIG_NETDEV_IFINDEX
   SYSCALL_LOOKUP(if_indextoname,           2)
   SYSCALL_LOOKUP(if_nametoindex,           1)
diff --git a/libs/libc/Makefile b/libs/libc/Makefile
index 6d890c3..03db586 100644
--- a/libs/libc/Makefile
+++ b/libs/libc/Makefile
@@ -28,6 +28,7 @@ include dirent/Make.defs
 include dlfcn/Make.defs
 include endian/Make.defs
 include errno/Make.defs
+include eventfd/Make.defs
 include fixedmath/Make.defs
 include grp/Make.defs
 include hex2bin/Make.defs
diff --git a/libs/libc/eventfd/Make.defs b/libs/libc/eventfd/Make.defs
new file mode 100644
index 0000000..d16c868
--- /dev/null
+++ b/libs/libc/eventfd/Make.defs
@@ -0,0 +1,27 @@
+############################################################################
+# libs/libc/eventfd/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifeq ($(CONFIG_EVENT_FD),y)
+CSRCS += lib_eventfd.c
+
+DEPPATH += --dep-path eventfd
+VPATH += :eventfd
+endif
+
diff --git a/libs/libc/eventfd/lib_eventfd.c b/libs/libc/eventfd/lib_eventfd.c
new file mode 100644
index 0000000..d227913
--- /dev/null
+++ b/libs/libc/eventfd/lib_eventfd.c
@@ -0,0 +1,57 @@
+/****************************************************************************
+ * libs/libc/lib_eventfd.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int eventfd_read(int fd, FAR eventfd_t *value)
+{
+  return read(fd, value, sizeof (eventfd_t)) != sizeof (eventfd_t) ? -1 : 0;
+}
+
+int eventfd_write(int fd, eventfd_t value)
+{
+  return write(fd, &value,
+      sizeof (eventfd_t)) != sizeof (eventfd_t) ? -1 : 0;
+}
+
+int eventfd_get_minor(int fd)
+{
+  int ret;
+  int minor;
+
+  ret = ioctl(fd, EFD_FIOC_MINOR, &minor);
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  return minor;
+}
diff --git a/syscall/syscall.csv b/syscall/syscall.csv
index 3389ac8..c02e5f4 100644
--- a/syscall/syscall.csv
+++ b/syscall/syscall.csv
@@ -19,6 +19,7 @@
 "connect","sys/socket.h","defined(CONFIG_NET)","int","int","FAR const struct 
sockaddr *","socklen_t"
 "dup","unistd.h","","int","int"
 "dup2","unistd.h","","int","int","int"
+"eventfd","sys/eventfd.h","defined(CONFIG_EVENT_FD)","unsigned int","int"
 "exec","nuttx/binfmt/binfmt.h","!defined(CONFIG_BINFMT_DISABLE) && 
!defined(CONFIG_BUILD_KERNEL)","int","FAR const char *","FAR char * const 
*","FAR const struct symtab_s *","int"
 "execv","unistd.h","!defined(CONFIG_BINFMT_DISABLE) && 
defined(CONFIG_LIBC_EXECFUNCS)","int","FAR const char *","FAR char * const 
[]|FAR char * const *"
 "exit","stdlib.h","","void","int"

Reply via email to