2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2014 Dmitry Chagin <dchagin@FreeBSD.org>
5 * Copyright (c) 2023 Jake Freeland <jfree@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/callout.h>
32 #include <sys/fcntl.h>
34 #include <sys/filedesc.h>
35 #include <sys/filio.h>
36 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/mount.h>
40 #include <sys/mutex.h>
43 #include <sys/queue.h>
44 #include <sys/selinfo.h>
47 #include <sys/sysctl.h>
48 #include <sys/sysent.h>
49 #include <sys/sysproto.h>
50 #include <sys/timerfd.h>
51 #include <sys/timespec.h>
55 #include <security/audit/audit.h>
57 static MALLOC_DEFINE(M_TIMERFD, "timerfd", "timerfd structures");
59 static struct mtx timerfd_list_lock;
60 static LIST_HEAD(, timerfd) timerfd_list;
61 MTX_SYSINIT(timerfd, &timerfd_list_lock, "timerfd_list_lock", MTX_DEF);
63 static struct unrhdr64 tfdino_unr;
65 #define TFD_NOJUMP 0 /* Realtime clock has not jumped. */
66 #define TFD_READ 1 /* Jumped, tfd has been read since. */
67 #define TFD_ZREAD 2 /* Jumped backwards, CANCEL_ON_SET=false. */
68 #define TFD_CANCELED 4 /* Jumped, CANCEL_ON_SET=true. */
69 #define TFD_JUMPED (TFD_ZREAD | TFD_CANCELED)
72 * One structure allocated per timerfd descriptor.
75 * (t) locked by tfd_lock mtx
76 * (l) locked by timerfd_list_lock sx
77 * (c) const until freeing
81 struct itimerspec tfd_time; /* (t) tfd timer */
82 clockid_t tfd_clockid; /* (c) timing base */
83 int tfd_flags; /* (c) creation flags */
84 int tfd_timflags; /* (t) timer flags */
86 /* Used internally. */
87 timerfd_t tfd_count; /* (t) expiration count since read */
88 bool tfd_expired; /* (t) true upon initial expiration */
89 struct mtx tfd_lock; /* tfd mtx lock */
90 struct callout tfd_callout; /* (t) expiration notification */
91 struct selinfo tfd_sel; /* (t) I/O alerts */
92 struct timespec tfd_boottim; /* (t) cached boottime */
93 int tfd_jumped; /* (t) timer jump status */
94 LIST_ENTRY(timerfd) entry; /* (l) entry in list */
97 ino_t tfd_ino; /* (c) inode number */
98 struct timespec tfd_atim; /* (t) time of last read */
99 struct timespec tfd_mtim; /* (t) time of last settime */
100 struct timespec tfd_birthtim; /* (c) creation time */
104 timerfd_init(void *data)
106 new_unrhdr64(&tfdino_unr, 1);
109 SYSINIT(timerfd, SI_SUB_VFS, SI_ORDER_ANY, timerfd_init, NULL);
112 timerfd_getboottime(struct timespec *ts)
117 TIMEVAL_TO_TIMESPEC(&tv, ts);
121 * Call when a discontinuous jump has occured in CLOCK_REALTIME and
122 * update timerfd's cached boottime. A jump can be triggered using
123 * functions like clock_settime(2) or settimeofday(2).
125 * Timer is marked TFD_CANCELED if TFD_TIMER_CANCEL_ON_SET is set
126 * and the realtime clock jumps.
127 * Timer is marked TFD_ZREAD if TFD_TIMER_CANCEL_ON_SET is not set,
128 * but the realtime clock jumps backwards.
134 struct timespec boottime, diff;
136 if (LIST_EMPTY(&timerfd_list))
139 timerfd_getboottime(&boottime);
140 mtx_lock(&timerfd_list_lock);
141 LIST_FOREACH(tfd, &timerfd_list, entry) {
142 mtx_lock(&tfd->tfd_lock);
143 if (tfd->tfd_clockid != CLOCK_REALTIME ||
144 (tfd->tfd_timflags & TFD_TIMER_ABSTIME) == 0 ||
145 timespeccmp(&boottime, &tfd->tfd_boottim, ==)) {
146 mtx_unlock(&tfd->tfd_lock);
150 if (callout_active(&tfd->tfd_callout)) {
151 if ((tfd->tfd_timflags & TFD_TIMER_CANCEL_ON_SET) != 0)
152 tfd->tfd_jumped = TFD_CANCELED;
153 else if (timespeccmp(&boottime, &tfd->tfd_boottim, <))
154 tfd->tfd_jumped = TFD_ZREAD;
157 * Do not reschedule callout when
158 * inside interval time loop.
160 if (!tfd->tfd_expired) {
161 timespecsub(&boottime,
162 &tfd->tfd_boottim, &diff);
163 timespecsub(&tfd->tfd_time.it_value,
164 &diff, &tfd->tfd_time.it_value);
165 if (callout_stop(&tfd->tfd_callout) == 1) {
166 callout_schedule_sbt(&tfd->tfd_callout,
167 tstosbt(tfd->tfd_time.it_value),
173 tfd->tfd_boottim = boottime;
174 mtx_unlock(&tfd->tfd_lock);
176 mtx_unlock(&timerfd_list_lock);
180 timerfd_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
181 int flags, struct thread *td)
183 struct timerfd *tfd = fp->f_data;
187 if (uio->uio_resid < sizeof(timerfd_t))
190 mtx_lock(&tfd->tfd_lock);
192 getnanotime(&tfd->tfd_atim);
193 if ((tfd->tfd_jumped & TFD_JUMPED) != 0) {
194 if (tfd->tfd_jumped == TFD_CANCELED)
196 tfd->tfd_jumped = TFD_READ;
198 mtx_unlock(&tfd->tfd_lock);
201 tfd->tfd_jumped = TFD_NOJUMP;
203 if (tfd->tfd_count == 0) {
204 if ((fp->f_flag & FNONBLOCK) != 0) {
205 mtx_unlock(&tfd->tfd_lock);
208 td->td_rtcgen = atomic_load_acq_int(&rtc_generation);
209 error = mtx_sleep(&tfd->tfd_count, &tfd->tfd_lock,
214 mtx_unlock(&tfd->tfd_lock);
219 count = tfd->tfd_count;
221 mtx_unlock(&tfd->tfd_lock);
222 error = uiomove(&count, sizeof(timerfd_t), uio);
228 timerfd_ioctl(struct file *fp, u_long cmd, void *data,
229 struct ucred *active_cred, struct thread *td)
233 if (*(int *)data != 0)
234 atomic_set_int(&fp->f_flag, FASYNC);
236 atomic_clear_int(&fp->f_flag, FASYNC);
239 if (*(int *)data != 0)
240 atomic_set_int(&fp->f_flag, FNONBLOCK);
242 atomic_clear_int(&fp->f_flag, FNONBLOCK);
249 timerfd_poll(struct file *fp, int events, struct ucred *active_cred,
252 struct timerfd *tfd = fp->f_data;
255 mtx_lock(&tfd->tfd_lock);
256 if ((events & (POLLIN | POLLRDNORM)) != 0 &&
257 tfd->tfd_count > 0 && tfd->tfd_jumped != TFD_READ)
258 revents |= events & (POLLIN | POLLRDNORM);
260 selrecord(td, &tfd->tfd_sel);
261 mtx_unlock(&tfd->tfd_lock);
267 filt_timerfddetach(struct knote *kn)
269 struct timerfd *tfd = kn->kn_hook;
271 mtx_lock(&tfd->tfd_lock);
272 knlist_remove(&tfd->tfd_sel.si_note, kn, 1);
273 mtx_unlock(&tfd->tfd_lock);
277 filt_timerfdread(struct knote *kn, long hint)
279 struct timerfd *tfd = kn->kn_hook;
281 mtx_assert(&tfd->tfd_lock, MA_OWNED);
282 kn->kn_data = (int64_t)tfd->tfd_count;
283 return (tfd->tfd_count > 0);
286 static struct filterops timerfd_rfiltops = {
288 .f_detach = filt_timerfddetach,
289 .f_event = filt_timerfdread,
293 timerfd_kqfilter(struct file *fp, struct knote *kn)
295 struct timerfd *tfd = fp->f_data;
297 if (kn->kn_filter != EVFILT_READ)
300 kn->kn_fop = &timerfd_rfiltops;
302 knlist_add(&tfd->tfd_sel.si_note, kn, 0);
308 timerfd_stat(struct file *fp, struct stat *sb, struct ucred *active_cred)
310 struct timerfd *tfd = fp->f_data;
312 bzero(sb, sizeof(*sb));
313 sb->st_nlink = fp->f_count - 1;
314 sb->st_uid = fp->f_cred->cr_uid;
315 sb->st_gid = fp->f_cred->cr_gid;
316 sb->st_blksize = PAGE_SIZE;
317 mtx_lock(&tfd->tfd_lock);
318 sb->st_atim = tfd->tfd_atim;
319 sb->st_mtim = tfd->tfd_mtim;
320 mtx_unlock(&tfd->tfd_lock);
321 sb->st_ctim = sb->st_mtim;
322 sb->st_ino = tfd->tfd_ino;
323 sb->st_birthtim = tfd->tfd_birthtim;
329 timerfd_close(struct file *fp, struct thread *td)
331 struct timerfd *tfd = fp->f_data;
333 mtx_lock(&timerfd_list_lock);
334 LIST_REMOVE(tfd, entry);
335 mtx_unlock(&timerfd_list_lock);
337 callout_drain(&tfd->tfd_callout);
338 seldrain(&tfd->tfd_sel);
339 knlist_destroy(&tfd->tfd_sel.si_note);
340 mtx_destroy(&tfd->tfd_lock);
341 free(tfd, M_TIMERFD);
342 fp->f_ops = &badfileops;
348 timerfd_fill_kinfo(struct file *fp, struct kinfo_file *kif,
349 struct filedesc *fdp)
351 struct timerfd *tfd = fp->f_data;
353 kif->kf_type = KF_TYPE_TIMERFD;
354 kif->kf_un.kf_timerfd.kf_timerfd_clockid = tfd->tfd_clockid;
355 kif->kf_un.kf_timerfd.kf_timerfd_flags = tfd->tfd_flags;
356 kif->kf_un.kf_timerfd.kf_timerfd_addr = (uintptr_t)tfd;
361 static struct fileops timerfdops = {
362 .fo_read = timerfd_read,
363 .fo_write = invfo_rdwr,
364 .fo_truncate = invfo_truncate,
365 .fo_ioctl = timerfd_ioctl,
366 .fo_poll = timerfd_poll,
367 .fo_kqfilter = timerfd_kqfilter,
368 .fo_stat = timerfd_stat,
369 .fo_close = timerfd_close,
370 .fo_chmod = invfo_chmod,
371 .fo_chown = invfo_chown,
372 .fo_sendfile = invfo_sendfile,
373 .fo_fill_kinfo = timerfd_fill_kinfo,
374 .fo_flags = DFLAG_PASSABLE,
378 timerfd_curval(struct timerfd *tfd, struct itimerspec *old_value)
380 struct timespec curr_value;
382 mtx_assert(&tfd->tfd_lock, MA_OWNED);
383 *old_value = tfd->tfd_time;
384 if (timespecisset(&tfd->tfd_time.it_value)) {
385 nanouptime(&curr_value);
386 timespecsub(&tfd->tfd_time.it_value, &curr_value,
387 &old_value->it_value);
392 timerfd_expire(void *arg)
394 struct timerfd *tfd = (struct timerfd *)arg;
395 struct timespec uptime;
398 tfd->tfd_expired = true;
399 if (timespecisset(&tfd->tfd_time.it_interval)) {
400 /* Count missed events. */
402 if (timespeccmp(&uptime, &tfd->tfd_time.it_value, >)) {
403 timespecsub(&uptime, &tfd->tfd_time.it_value, &uptime);
404 tfd->tfd_count += tstosbt(uptime) /
405 tstosbt(tfd->tfd_time.it_interval);
407 timespecadd(&tfd->tfd_time.it_value,
408 &tfd->tfd_time.it_interval, &tfd->tfd_time.it_value);
409 callout_schedule_sbt(&tfd->tfd_callout,
410 tstosbt(tfd->tfd_time.it_value),
413 /* Single shot timer. */
414 callout_deactivate(&tfd->tfd_callout);
415 timespecclear(&tfd->tfd_time.it_value);
418 wakeup(&tfd->tfd_count);
419 selwakeup(&tfd->tfd_sel);
420 KNOTE_LOCKED(&tfd->tfd_sel.si_note, 0);
424 kern_timerfd_create(struct thread *td, int clockid, int flags)
428 int error, fd, fflags;
430 AUDIT_ARG_VALUE(clockid);
431 AUDIT_ARG_FFLAGS(flags);
433 if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC)
435 if ((flags & ~(TFD_CLOEXEC | TFD_NONBLOCK)) != 0)
439 if ((flags & TFD_CLOEXEC) != 0)
441 if ((flags & TFD_NONBLOCK) != 0)
444 error = falloc(td, &fp, &fd, fflags);
448 tfd = malloc(sizeof(*tfd), M_TIMERFD, M_WAITOK | M_ZERO);
449 tfd->tfd_clockid = (clockid_t)clockid;
450 tfd->tfd_flags = flags;
451 tfd->tfd_ino = alloc_unr64(&tfdino_unr);
452 mtx_init(&tfd->tfd_lock, "timerfd", NULL, MTX_DEF);
453 callout_init_mtx(&tfd->tfd_callout, &tfd->tfd_lock, 0);
454 knlist_init_mtx(&tfd->tfd_sel.si_note, &tfd->tfd_lock);
455 timerfd_getboottime(&tfd->tfd_boottim);
456 getnanotime(&tfd->tfd_birthtim);
457 mtx_lock(&timerfd_list_lock);
458 LIST_INSERT_HEAD(&timerfd_list, tfd, entry);
459 mtx_unlock(&timerfd_list_lock);
461 finit(fp, fflags, DTYPE_TIMERFD, tfd, &timerfdops);
465 td->td_retval[0] = fd;
470 kern_timerfd_gettime(struct thread *td, int fd, struct itimerspec *curr_value)
476 error = fget(td, fd, &cap_write_rights, &fp);
479 if (fp->f_type != DTYPE_TIMERFD) {
485 mtx_lock(&tfd->tfd_lock);
486 timerfd_curval(tfd, curr_value);
487 mtx_unlock(&tfd->tfd_lock);
494 kern_timerfd_settime(struct thread *td, int fd, int flags,
495 const struct itimerspec *new_value, struct itimerspec *old_value)
502 if ((flags & ~(TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET)) != 0)
504 if (!timespecvalid_interval(&new_value->it_value) ||
505 !timespecvalid_interval(&new_value->it_interval))
508 error = fget(td, fd, &cap_write_rights, &fp);
511 if (fp->f_type != DTYPE_TIMERFD) {
517 mtx_lock(&tfd->tfd_lock);
518 getnanotime(&tfd->tfd_mtim);
519 tfd->tfd_timflags = flags;
521 /* Store old itimerspec, if applicable. */
522 if (old_value != NULL)
523 timerfd_curval(tfd, old_value);
525 /* Set new expiration. */
526 tfd->tfd_time = *new_value;
527 if (timespecisset(&tfd->tfd_time.it_value)) {
528 if ((flags & TFD_TIMER_ABSTIME) == 0) {
530 timespecadd(&tfd->tfd_time.it_value, &ts,
531 &tfd->tfd_time.it_value);
532 } else if (tfd->tfd_clockid == CLOCK_REALTIME) {
533 /* ECANCELED if unread jump is pending. */
534 if (tfd->tfd_jumped == TFD_CANCELED)
536 /* Convert from CLOCK_REALTIME to CLOCK_BOOTTIME. */
537 timespecsub(&tfd->tfd_time.it_value, &tfd->tfd_boottim,
538 &tfd->tfd_time.it_value);
540 callout_reset_sbt(&tfd->tfd_callout,
541 tstosbt(tfd->tfd_time.it_value),
542 0, timerfd_expire, tfd, C_ABSOLUTE);
544 callout_stop(&tfd->tfd_callout);
547 tfd->tfd_expired = false;
548 tfd->tfd_jumped = TFD_NOJUMP;
549 mtx_unlock(&tfd->tfd_lock);
556 sys_timerfd_create(struct thread *td, struct timerfd_create_args *uap)
558 return (kern_timerfd_create(td, uap->clockid, uap->flags));
562 sys_timerfd_gettime(struct thread *td, struct timerfd_gettime_args *uap)
564 struct itimerspec curr_value;
567 error = kern_timerfd_gettime(td, uap->fd, &curr_value);
569 error = copyout(&curr_value, uap->curr_value,
576 sys_timerfd_settime(struct thread *td, struct timerfd_settime_args *uap)
578 struct itimerspec new_value, old_value;
581 error = copyin(uap->new_value, &new_value, sizeof(new_value));
584 if (uap->old_value == NULL) {
585 error = kern_timerfd_settime(td, uap->fd, uap->flags,
588 error = kern_timerfd_settime(td, uap->fd, uap->flags,
589 &new_value, &old_value);
591 error = copyout(&old_value, uap->old_value,