xref: /illumos-gate/usr/src/lib/libc/port/sys/timerfd.c (revision 3ce5372277f4657ad0e52d36c979527c4ca22de2)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright (c) 2015, Joyent, Inc.  All rights reserved.
14  */
15 
16 #include <sys/timerfd.h>
17 #include <sys/stat.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 
22 int
23 timerfd_create(int clockid, int flags)
24 {
25 	int oflags = O_RDWR;
26 	int fd;
27 
28 	if (flags & ~(TFD_NONBLOCK | TFD_CLOEXEC)) {
29 		errno = EINVAL;
30 		return (-1);
31 	}
32 
33 	if (flags & TFD_NONBLOCK)
34 		oflags |= O_NONBLOCK;
35 
36 	if (flags & TFD_CLOEXEC)
37 		oflags |= O_CLOEXEC;
38 
39 	if ((fd = open("/dev/timerfd", oflags)) < 0)
40 		return (-1);
41 
42 	if (ioctl(fd, TIMERFDIOC_CREATE, clockid) != 0) {
43 		(void) close(fd);
44 		return (-1);
45 	}
46 
47 	return (fd);
48 }
49 
50 int
51 timerfd_settime(int fd, int flags, const struct itimerspec *new_value,
52     struct itimerspec *old_value)
53 {
54 	timerfd_settime_t st;
55 	int rval;
56 
57 	if (flags & ~(TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET)) {
58 		errno = EINVAL;
59 		return (-1);
60 	}
61 
62 	st.tfd_settime_flags = flags;
63 	st.tfd_settime_value = (uint64_t)(uintptr_t)new_value;
64 	st.tfd_settime_ovalue = (uint64_t)(uintptr_t)old_value;
65 
66 	rval = ioctl(fd, TIMERFDIOC_SETTIME, &st);
67 
68 	if (rval == -1 && errno == ENOTTY) {
69 		/*
70 		 * Linux has us return EINVAL when the file descriptor is valid
71 		 * but is not a timerfd file descriptor -- and LTP explicitly
72 		 * checks this case.
73 		 */
74 		errno = EINVAL;
75 	}
76 
77 	return (rval);
78 }
79 
80 int
81 timerfd_gettime(int fd, struct itimerspec *curr_value)
82 {
83 	int rval = ioctl(fd, TIMERFDIOC_GETTIME, curr_value);
84 
85 	if (rval == -1 && errno == ENOTTY) {
86 		/*
87 		 * See comment in timerfd_settime(), above.
88 		 */
89 		errno = EINVAL;
90 	}
91 
92 	return (rval);
93 }
94