1 /* AirScan (a.k.a. eSCL) backend for SANE
2 *
3 * Copyright (C) 2019 and up by Alexander Pevzner (pzz@apevzner.com)
4 * See LICENSE for license terms and conditions
5 *
6 * Pollable events
7 */
8
9 #include "airscan.h"
10
11 #ifdef OS_HAVE_EVENTFD
12 #include <sys/eventfd.h>
13 #endif
14 #include <poll.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17
18 #pragma GCC diagnostic ignored "-Wunused-result"
19
20 /* The pollable event
21 */
22 struct pollable {
23 int efd; /* Underlying eventfd handle */
24 #ifndef OS_HAVE_EVENTFD
25 // Without eventfd we use a pipe, so we need a second fd.
26 int write_fd;
27 #endif
28 };
29
30 /* Create new pollable event
31 */
32 pollable*
pollable_new(void)33 pollable_new (void)
34 {
35 #ifdef OS_HAVE_EVENTFD
36 int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
37 #else
38 int fds[2];
39 int r = pipe2(fds, O_CLOEXEC | O_NONBLOCK);
40 int efd = r < 0 ? r : fds[0];
41 #endif
42 if (efd< 0) {
43 return NULL;
44 }
45
46 pollable *p = mem_new(pollable, 1);
47 p->efd = efd;
48 #ifndef OS_HAVE_EVENTFD
49 p->write_fd = fds[1];
50 #endif
51
52 return p;
53 }
54
55 /* Free pollable event
56 */
57 void
pollable_free(pollable * p)58 pollable_free (pollable *p)
59 {
60 close(p->efd);
61 #ifndef OS_HAVE_EVENTFD
62 close(p->write_fd);
63 #endif
64 mem_free(p);
65 }
66
67 /* Get file descriptor for poll()/select().
68 */
69 int
pollable_get_fd(pollable * p)70 pollable_get_fd (pollable *p)
71 {
72 return p->efd;
73 }
74
75 /* Make pollable event "ready"
76 */
77 void
pollable_signal(pollable * p)78 pollable_signal (pollable *p)
79 {
80 static uint64_t c = 1;
81 #ifdef OS_HAVE_EVENTFD
82 write(p->efd, &c, sizeof(c));
83 #else
84 write(p->write_fd, &c, sizeof(c));
85 #endif
86 }
87
88 /* Make pollable event "not ready"
89 */
90 void
pollable_reset(pollable * p)91 pollable_reset (pollable *p)
92 {
93 uint64_t unused;
94
95 (void) read(p->efd, &unused, sizeof(unused));
96 }
97
98 /* Wait until pollable event is ready
99 */
100 void
pollable_wait(pollable * p)101 pollable_wait (pollable *p)
102 {
103 int rc;
104
105 do {
106 struct pollfd pfd = {
107 .fd = p->efd,
108 .events = POLLIN,
109 .revents = 0
110 };
111 rc = poll(&pfd, 1, -1);
112 } while (rc < 1);
113 }
114
115 /* vim:ts=8:sw=4:et
116 */
117