Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/fhandler/timerfd.cc')
-rw-r--r--winsup/cygwin/fhandler/timerfd.cc338
1 files changed, 338 insertions, 0 deletions
diff --git a/winsup/cygwin/fhandler/timerfd.cc b/winsup/cygwin/fhandler/timerfd.cc
new file mode 100644
index 000000000..9269494db
--- /dev/null
+++ b/winsup/cygwin/fhandler/timerfd.cc
@@ -0,0 +1,338 @@
+/* fhandler_timerfd.cc: fhandler for timerfd, public timerfd API
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include "path.h"
+#include "fhandler.h"
+#include "pinfo.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "timerfd.h"
+#include <sys/timerfd.h>
+#include <cygwin/signal.h>
+
+fhandler_timerfd::fhandler_timerfd () :
+ fhandler_base ()
+{
+}
+
+char *
+fhandler_timerfd::get_proc_fd_name (char *buf)
+{
+ return strcpy (buf, "anon_inode:[timerfd]");
+}
+
+/* The timers connected to a descriptor are stored on the cygheap
+ together with their fhandler. */
+
+int
+fhandler_timerfd::timerfd (clockid_t clock_id, int flags)
+{
+ timerfd_tracker *tfd = (timerfd_tracker *)
+ ccalloc (HEAP_FHANDLER, 1, sizeof (timerfd_tracker));
+ if (!tfd)
+ {
+ set_errno (ENOMEM);
+ return -1;
+ }
+ new (tfd) timerfd_tracker ();
+ int ret = tfd->create (clock_id);
+ if (ret < 0)
+ {
+ cfree (tfd);
+ set_errno (-ret);
+ return -1;
+ }
+ if (flags & TFD_NONBLOCK)
+ set_nonblocking (true);
+ if (flags & TFD_CLOEXEC)
+ set_close_on_exec (true);
+ nohandle (true);
+ set_unique_id ();
+ set_ino (get_unique_id ());
+ set_flags (O_RDWR | O_BINARY);
+ timerid = (timer_t) tfd;
+ return 0;
+}
+
+int
+fhandler_timerfd::settime (int flags, const struct itimerspec *new_value,
+ struct itimerspec *old_value)
+{
+ int ret = -1;
+
+ __try
+ {
+ timerfd_tracker *tfd = (timerfd_tracker *) timerid;
+ ret = tfd->settime (flags, new_value, old_value);
+ if (ret < 0)
+ {
+ set_errno (-ret);
+ ret = -1;
+ }
+ }
+ __except (EFAULT) {}
+ __endtry
+ return ret;
+}
+
+int
+fhandler_timerfd::gettime (struct itimerspec *ovalue)
+{
+ int ret = -1;
+
+ __try
+ {
+ timerfd_tracker *tfd = (timerfd_tracker *) timerid;
+ ret = tfd->gettime (ovalue);
+ if (ret < 0)
+ {
+ set_errno (-ret);
+ ret = -1;
+ }
+ }
+ __except (EFAULT) {}
+ __endtry
+ return ret;
+}
+
+int
+fhandler_timerfd::fstat (struct stat *buf)
+{
+ int ret = fhandler_base::fstat (buf);
+ if (!ret)
+ {
+ buf->st_mode = S_IRUSR | S_IWUSR;
+ buf->st_dev = FH_TIMERFD;
+ buf->st_ino = get_unique_id ();
+ }
+ return ret;
+}
+
+void
+fhandler_timerfd::read (void *ptr, size_t& len)
+{
+ if (len < sizeof (LONG64))
+ {
+ set_errno (EINVAL);
+ len = (size_t) -1;
+ return;
+ }
+
+ __try
+ {
+ timerfd_tracker *tfd = (timerfd_tracker *) timerid;
+ LONG64 ret = tfd->wait (is_nonblocking ());
+ if (ret < 0)
+ {
+ set_errno (-ret);
+ __leave;
+ }
+ *(PLONG64) ptr = ret;
+ len = sizeof (LONG64);
+ return;
+ }
+ __except (EFAULT) {}
+ __endtry
+ len = (size_t) -1;
+ return;
+}
+
+ssize_t
+fhandler_timerfd::write (const void *, size_t)
+{
+ set_errno (EINVAL);
+ return -1;
+}
+
+HANDLE
+fhandler_timerfd::get_timerfd_handle ()
+{
+ __try
+ {
+ timerfd_tracker *tfd = (timerfd_tracker *) timerid;
+ return tfd->get_timerfd_handle ();
+ }
+ __except (EFAULT) {}
+ __endtry
+ return NULL;
+}
+
+int
+fhandler_timerfd::dup (fhandler_base *child, int flags)
+{
+ int ret = fhandler_base::dup (child, flags);
+
+ if (!ret)
+ {
+ fhandler_timerfd *fhc = (fhandler_timerfd *) child;
+ __try
+ {
+ timerfd_tracker *tfd = (timerfd_tracker *) fhc->timerid;
+ tfd->dup ();
+ ret = 0;
+ }
+ __except (EFAULT) {}
+ __endtry
+ }
+ return ret;
+}
+
+int
+fhandler_timerfd::ioctl (unsigned int cmd, void *p)
+{
+ int ret = -1;
+ uint64_t exp_cnt;
+
+ switch (cmd)
+ {
+ case TFD_IOC_SET_TICKS:
+ __try
+ {
+ timerfd_tracker *tfd = (timerfd_tracker *) timerid;
+
+ exp_cnt = *(uint64_t *) p;
+ ret = tfd->ioctl_set_ticks (exp_cnt);
+ if (ret < 0)
+ set_errno (-ret);
+ }
+ __except (EFAULT) {}
+ __endtry
+ break;
+ default:
+ ret = fhandler_base::ioctl (cmd, p);
+ break;
+ }
+ syscall_printf ("%d = ioctl_timerfd(%x, %p)", ret, cmd, p);
+ return ret;
+}
+
+void
+fhandler_timerfd::fixup_after_fork (HANDLE)
+{
+ __try
+ {
+ timerfd_tracker *tfd = (timerfd_tracker *) timerid;
+ tfd->fixup_after_fork ();
+ }
+ __except (EFAULT) {}
+ __endtry
+}
+
+void
+fhandler_timerfd::fixup_after_exec ()
+{
+ __try
+ {
+ timerfd_tracker *tfd = (timerfd_tracker *) timerid;
+ tfd->init_fixup_after_fork_exec ();
+ if (close_on_exec ())
+ timerfd_tracker::dtor (tfd);
+ else
+ tfd->fixup_after_exec ();
+ }
+ __except (EFAULT) {}
+ __endtry
+}
+
+int
+fhandler_timerfd::close ()
+{
+ int ret = -1;
+
+ __try
+ {
+ timerfd_tracker *tfd = (timerfd_tracker *) timerid;
+ timerfd_tracker::dtor (tfd);
+ ret = 0;
+ }
+ __except (EFAULT) {}
+ __endtry
+ return ret;
+}
+
+extern "C" int
+timerfd_create (clockid_t clock_id, int flags)
+{
+ int ret = -1;
+ fhandler_timerfd *fh;
+
+ debug_printf ("timerfd_create (%lu, %y)", clock_id, flags);
+
+ if (clock_id != CLOCK_REALTIME
+ && clock_id != CLOCK_MONOTONIC
+ && clock_id != CLOCK_BOOTTIME)
+ {
+ set_errno (EINVAL);
+ goto done;
+ }
+ if ((flags & ~(TFD_NONBLOCK | TFD_CLOEXEC)) != 0)
+ {
+ set_errno (EINVAL);
+ goto done;
+ }
+
+ {
+ /* Create new timerfd descriptor. */
+ cygheap_fdnew fd;
+
+ if (fd < 0)
+ goto done;
+ fh = (fhandler_timerfd *) build_fh_dev (*timerfd_dev);
+ if (fh && fh->timerfd (clock_id, flags) == 0)
+ {
+ fd = fh;
+ if (fd <= 2)
+ set_std_handle (fd);
+ ret = fd;
+ }
+ else
+ delete fh;
+ }
+
+done:
+ syscall_printf ("%R = timerfd_create (%lu, %y)", ret, clock_id, flags);
+ return ret;
+}
+
+extern "C" int
+timerfd_settime (int fd_in, int flags, const struct itimerspec *value,
+ struct itimerspec *ovalue)
+{
+ if ((flags & ~(TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET)) != 0)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+
+ cygheap_fdget fd (fd_in);
+ if (fd < 0)
+ return -1;
+ fhandler_timerfd *fh = fd->is_timerfd ();
+ if (!fh)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ return fh->settime (flags, value, ovalue);
+}
+
+extern "C" int
+timerfd_gettime (int fd_in, struct itimerspec *ovalue)
+{
+ cygheap_fdget fd (fd_in);
+ if (fd < 0)
+ return -1;
+ fhandler_timerfd *fh = fd->is_timerfd ();
+ if (!fh)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ return fh->gettime (ovalue);
+}