2 * Polling/timing management
3 * Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #define FP_COMPONENT "poll"
30 #include "fp_internal.h"
33 * @defgroup poll Polling and timing operations
34 * These functions are only applicable to users of libfprint's asynchronous
37 * libfprint does not create internal library threads and hence can only
38 * execute when your application is calling a libfprint function. However,
39 * libfprint often has work to be do, such as handling of completed USB
40 * transfers, and processing of timeouts required in order for the library
41 * to function. Therefore it is essential that your own application must
42 * regularly "phone into" libfprint so that libfprint can handle any pending
45 * The function you must call is fp_handle_events() or a variant of it. This
46 * function will handle any pending events, and it is from this context that
47 * all asynchronous event callbacks from the library will occur. You can view
48 * this function as a kind of iteration function.
50 * If there are no events pending, fp_handle_events() will block for a few
51 * seconds (and will handle any new events should anything occur in that time).
52 * If you wish to customise this timeout, you can use
53 * fp_handle_events_timeout() instead. If you wish to do a nonblocking
54 * iteration, call fp_handle_events_timeout() with a zero timeout.
56 * TODO: document how application is supposed to know when to call these
60 /* this is a singly-linked list of pending timers, sorted with the timer that
61 * is expiring soonest at the head. */
62 static GSList
*active_timers
= NULL
;
64 /* notifiers for added or removed poll fds */
65 static fp_pollfd_added_cb fd_added_cb
= NULL
;
66 static fp_pollfd_removed_cb fd_removed_cb
= NULL
;
69 struct timeval expiry
;
70 fpi_timeout_fn callback
;
74 static int timeout_sort_fn(gconstpointer _a
, gconstpointer _b
)
76 struct fpi_timeout
*a
= (struct fpi_timeout
*) _a
;
77 struct fpi_timeout
*b
= (struct fpi_timeout
*) _b
;
78 struct timeval
*tv_a
= &a
->expiry
;
79 struct timeval
*tv_b
= &b
->expiry
;
81 if (timercmp(tv_a
, tv_b
, <))
83 else if (timercmp(tv_a
, tv_b
, >))
89 /* A timeout is the asynchronous equivalent of sleeping. You create a timeout
90 * saying that you'd like to have a function invoked at a certain time in
92 struct fpi_timeout
*fpi_timeout_add(unsigned int msec
, fpi_timeout_fn callback
,
96 struct timeval add_msec
;
97 struct fpi_timeout
*timeout
;
100 fp_dbg("in %dms", msec
);
102 r
= clock_gettime(CLOCK_MONOTONIC
, &ts
);
104 fp_err("failed to read monotonic clock, errno=%d", errno
);
108 timeout
= g_malloc(sizeof(*timeout
));
109 timeout
->callback
= callback
;
110 timeout
->data
= data
;
111 TIMESPEC_TO_TIMEVAL(&timeout
->expiry
, &ts
);
113 /* calculate timeout expiry by adding delay to current monotonic clock */
114 timerclear(&add_msec
);
115 add_msec
.tv_sec
= msec
/ 1000;
116 add_msec
.tv_usec
= (msec
% 1000) * 1000;
117 timeradd(&timeout
->expiry
, &add_msec
, &timeout
->expiry
);
119 active_timers
= g_slist_insert_sorted(active_timers
, timeout
,
125 void fpi_timeout_cancel(struct fpi_timeout
*timeout
)
128 active_timers
= g_slist_remove(active_timers
, timeout
);
132 /* get the expiry time and optionally the timeout structure for the next
133 * timeout. returns 0 if there are no expired timers, or 1 if the
134 * timeval/timeout output parameters were populated. if the returned timeval
135 * is zero then it means the timeout has already expired and should be handled
137 static int get_next_timeout_expiry(struct timeval
*out
,
138 struct fpi_timeout
**out_timeout
)
142 struct fpi_timeout
*next_timeout
;
145 if (active_timers
== NULL
)
148 r
= clock_gettime(CLOCK_MONOTONIC
, &ts
);
150 fp_err("failed to read monotonic clock, errno=%d", errno
);
153 TIMESPEC_TO_TIMEVAL(&tv
, &ts
);
155 next_timeout
= active_timers
->data
;
157 *out_timeout
= next_timeout
;
159 if (timercmp(&tv
, &next_timeout
->expiry
, >=)) {
160 fp_dbg("first timeout already expired");
163 timersub(&next_timeout
->expiry
, &tv
, out
);
164 fp_dbg("next timeout in %d.%06ds", out
->tv_sec
, out
->tv_usec
);
170 /* handle a timeout that has expired */
171 static void handle_timeout(struct fpi_timeout
*timeout
)
174 timeout
->callback(timeout
->data
);
175 active_timers
= g_slist_remove(active_timers
, timeout
);
179 static int handle_timeouts(void)
181 struct timeval next_timeout_expiry
;
182 struct fpi_timeout
*next_timeout
;
185 r
= get_next_timeout_expiry(&next_timeout_expiry
, &next_timeout
);
189 if (!timerisset(&next_timeout_expiry
))
190 handle_timeout(next_timeout
);
196 * Handle any pending events. If a non-zero timeout is specified, the function
197 * will potentially block for the specified amount of time, although it may
198 * return sooner if events have been handled. The function acts as non-blocking
199 * for a zero timeout.
201 * \param timeout Maximum timeout for this blocking function
202 * \returns 0 on success, non-zero on error.
204 API_EXPORTED
int fp_handle_events_timeout(struct timeval
*timeout
)
206 struct timeval next_timeout_expiry
;
207 struct timeval select_timeout
;
208 struct fpi_timeout
*next_timeout
;
211 r
= get_next_timeout_expiry(&next_timeout_expiry
, &next_timeout
);
216 /* timer already expired? */
217 if (!timerisset(&next_timeout_expiry
)) {
218 handle_timeout(next_timeout
);
222 /* choose the smallest of next URB timeout or user specified timeout */
223 if (timercmp(&next_timeout_expiry
, timeout
, <))
224 select_timeout
= next_timeout_expiry
;
226 select_timeout
= *timeout
;
228 select_timeout
= *timeout
;
231 r
= libusb_handle_events_timeout(fpi_usb_ctx
, &select_timeout
);
232 *timeout
= select_timeout
;
236 return handle_timeouts();
240 * Convenience function for calling fp_handle_events_timeout() with a sensible
241 * default timeout value of two seconds (subject to change if we decide another
242 * value is more sensible).
244 * \returns 0 on success, non-zero on error.
246 API_EXPORTED
int fp_handle_events(void)
251 return fp_handle_events_timeout(&tv
);
255 * returns 0 if no timeouts active
256 * returns 1 if timeout returned
257 * zero timeout means events are to be handled immediately */
258 API_EXPORTED
int fp_get_next_timeout(struct timeval
*tv
)
260 struct timeval fprint_timeout
;
261 struct timeval libusb_timeout
;
265 r_fprint
= get_next_timeout_expiry(&fprint_timeout
, NULL
);
266 r_libusb
= libusb_get_next_timeout(fpi_usb_ctx
, &libusb_timeout
);
268 /* if we have no pending timeouts and the same is true for libusb,
269 * indicate that we have no pending timouts */
270 if (r_fprint
== 0 && r_libusb
== 0)
273 /* otherwise return the smaller of the 2 timeouts */
274 else if (timercmp(&fprint_timeout
, &libusb_timeout
, <))
275 *tv
= fprint_timeout
;
277 *tv
= libusb_timeout
;
282 * Retrieve a list of file descriptors that should be polled for events
283 * interesting to libfprint. This function is only for users who wish to
284 * combine libfprint's file descriptor set with other event sources - more
285 * simplistic users will be able to call fp_handle_events() or a variant
288 * \param pollfds output location for a list of pollfds. If non-NULL, must be
289 * released with free() when done.
290 * \returns the number of pollfds in the resultant list, or negative on error.
292 API_EXPORTED
size_t fp_get_pollfds(struct fp_pollfd
**pollfds
)
294 const struct libusb_pollfd
**usbfds
;
295 const struct libusb_pollfd
*usbfd
;
296 struct fp_pollfd
*ret
;
300 usbfds
= libusb_get_pollfds(fpi_usb_ctx
);
306 while ((usbfd
= usbfds
[i
++]) != NULL
)
309 ret
= g_malloc(sizeof(struct fp_pollfd
) * cnt
);
311 while ((usbfd
= usbfds
[i
]) != NULL
) {
312 ret
[i
].fd
= usbfd
->fd
;
313 ret
[i
].events
= usbfd
->events
;
322 API_EXPORTED
void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb
,
323 fp_pollfd_removed_cb removed_cb
)
325 fd_added_cb
= added_cb
;
326 fd_removed_cb
= removed_cb
;
329 static void add_pollfd(int fd
, short events
, void *user_data
)
332 fd_added_cb(fd
, events
);
335 static void remove_pollfd(int fd
, void *user_data
)
341 void fpi_poll_init(void)
343 libusb_set_pollfd_notifiers(fpi_usb_ctx
, add_pollfd
, remove_pollfd
, NULL
);
346 void fpi_poll_exit(void)
348 g_slist_free(active_timers
);
349 active_timers
= NULL
;
351 fd_removed_cb
= NULL
;
352 libusb_set_pollfd_notifiers(fpi_usb_ctx
, NULL
, NULL
, NULL
);