Fix documentation for libinput_log_set_handler
[platform/upstream/libinput.git] / src / timer.c
1 /*
2  * Copyright © 2014 Red Hat, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  The copyright holders make
11  * no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 #include <assert.h>
24 #include <errno.h>
25 #include <inttypes.h>
26 #include <string.h>
27 #include <sys/timerfd.h>
28 #include <unistd.h>
29
30 #include "libinput-private.h"
31 #include "timer.h"
32
33 void
34 libinput_timer_init(struct libinput_timer *timer, struct libinput *libinput,
35                     void (*timer_func)(uint64_t now, void *timer_func_data),
36                     void *timer_func_data)
37 {
38         timer->libinput = libinput;
39         timer->timer_func = timer_func;
40         timer->timer_func_data = timer_func_data;
41 }
42
43 static void
44 libinput_timer_arm_timer_fd(struct libinput *libinput)
45 {
46         int r;
47         struct libinput_timer *timer;
48         struct itimerspec its = { { 0, 0 }, { 0, 0 } };
49         uint64_t earliest_expire = UINT64_MAX;
50
51         list_for_each(timer, &libinput->timer.list, link) {
52                 if (timer->expire < earliest_expire)
53                         earliest_expire = timer->expire;
54         }
55
56         if (earliest_expire != UINT64_MAX) {
57                 its.it_value.tv_sec = earliest_expire / 1000;
58                 its.it_value.tv_nsec = (earliest_expire % 1000) * 1000 * 1000;
59         }
60
61         r = timerfd_settime(libinput->timer.fd, TFD_TIMER_ABSTIME, &its, NULL);
62         if (r)
63                 log_error(libinput, "timerfd_settime error: %s\n", strerror(errno));
64 }
65
66 void
67 libinput_timer_set(struct libinput_timer *timer, uint64_t expire)
68 {
69 #ifndef NDEBUG
70         uint64_t now = libinput_now(timer->libinput);
71         if (abs(expire - now) > 5000)
72                 log_bug_libinput(timer->libinput,
73                                  "timer offset more than 5s, now %"
74                                  PRIu64 " expire %" PRIu64 "\n",
75                                  now, expire);
76 #endif
77
78         assert(expire);
79
80         if (!timer->expire)
81                 list_insert(&timer->libinput->timer.list, &timer->link);
82
83         timer->expire = expire;
84         libinput_timer_arm_timer_fd(timer->libinput);
85 }
86
87 void
88 libinput_timer_cancel(struct libinput_timer *timer)
89 {
90         if (!timer->expire)
91                 return;
92
93         timer->expire = 0;
94         list_remove(&timer->link);
95         libinput_timer_arm_timer_fd(timer->libinput);
96 }
97
98 static void
99 libinput_timer_handler(void *data)
100 {
101         struct libinput *libinput = data;
102         struct libinput_timer *timer, *tmp;
103         uint64_t now;
104
105         now = libinput_now(libinput);
106         if (now == 0)
107                 return;
108
109         list_for_each_safe(timer, tmp, &libinput->timer.list, link) {
110                 if (timer->expire <= now) {
111                         /* Clear the timer before calling timer_func,
112                            as timer_func may re-arm it */
113                         libinput_timer_cancel(timer);
114                         timer->timer_func(now, timer->timer_func_data);
115                 }
116         }
117 }
118
119 int
120 libinput_timer_subsys_init(struct libinput *libinput)
121 {
122         libinput->timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
123         if (libinput->timer.fd < 0)
124                 return -1;
125
126         list_init(&libinput->timer.list);
127
128         libinput->timer.source = libinput_add_fd(libinput,
129                                                  libinput->timer.fd,
130                                                  libinput_timer_handler,
131                                                  libinput);
132         if (!libinput->timer.source) {
133                 close(libinput->timer.fd);
134                 return -1;
135         }
136
137         return 0;
138 }
139
140 void
141 libinput_timer_subsys_destroy(struct libinput *libinput)
142 {
143         /* All timer users should have destroyed their timers now */
144         assert(list_empty(&libinput->timer.list));
145
146         libinput_remove_source(libinput, libinput->timer.source);
147         close(libinput->timer.fd);
148 }