Fix two doxygen errors
[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         struct timespec ts;
71
72         if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
73                 uint64_t now = ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000;
74                 if (abs(expire - now) > 5000)
75                         log_bug_libinput(timer->libinput,
76                                          "timer offset more than 5s, now %"
77                                          PRIu64 " expire %" PRIu64 "\n",
78                                          now, expire);
79         } else {
80                 log_error(timer->libinput,
81                           "clock_gettime error: %s\n", strerror(errno));
82         }
83 #endif
84
85         assert(expire);
86
87         if (!timer->expire)
88                 list_insert(&timer->libinput->timer.list, &timer->link);
89
90         timer->expire = expire;
91         libinput_timer_arm_timer_fd(timer->libinput);
92 }
93
94 void
95 libinput_timer_cancel(struct libinput_timer *timer)
96 {
97         if (!timer->expire)
98                 return;
99
100         timer->expire = 0;
101         list_remove(&timer->link);
102         libinput_timer_arm_timer_fd(timer->libinput);
103 }
104
105 static void
106 libinput_timer_handler(void *data)
107 {
108         struct libinput *libinput = data;
109         struct libinput_timer *timer, *tmp;
110         struct timespec ts;
111         uint64_t now;
112         int r;
113
114         r = clock_gettime(CLOCK_MONOTONIC, &ts);
115         if (r) {
116                 log_error(libinput, "clock_gettime error: %s\n", strerror(errno));
117                 return;
118         }
119
120         now = ts.tv_sec * 1000ULL + ts.tv_nsec / 1000000;
121
122         list_for_each_safe(timer, tmp, &libinput->timer.list, link) {
123                 if (timer->expire <= now) {
124                         /* Clear the timer before calling timer_func,
125                            as timer_func may re-arm it */
126                         libinput_timer_cancel(timer);
127                         timer->timer_func(now, timer->timer_func_data);
128                 }
129         }
130 }
131
132 int
133 libinput_timer_subsys_init(struct libinput *libinput)
134 {
135         libinput->timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
136         if (libinput->timer.fd < 0)
137                 return -1;
138
139         list_init(&libinput->timer.list);
140
141         libinput->timer.source = libinput_add_fd(libinput,
142                                                  libinput->timer.fd,
143                                                  libinput_timer_handler,
144                                                  libinput);
145         if (!libinput->timer.source) {
146                 close(libinput->timer.fd);
147                 return -1;
148         }
149
150         return 0;
151 }
152
153 void
154 libinput_timer_subsys_destroy(struct libinput *libinput)
155 {
156         /* All timer users should have destroyed their timers now */
157         assert(list_empty(&libinput->timer.list));
158
159         libinput_remove_source(libinput, libinput->timer.source);
160         close(libinput->timer.fd);
161 }