5fda52ba1d14dbb0a43bab225569748535232f37
[dhcpcd-ui] / src / dhcpcd-curses / eloop.h
1 /*
2  * dhcpcd - DHCP client daemon
3  * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
4  * All rights reserved
5
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #ifndef ELOOP_H
29 #define ELOOP_H
30
31 #include <time.h>
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #else
36 /* Attempt to autodetect kqueue or epoll.
37  * If we can't, the system has to support pselect, which is a POSIX call. */
38 #if (defined(__unix__) || defined(unix)) && !defined(USG)
39 #include <sys/param.h>
40 #endif
41 #if defined(BSD)
42 /* Assume BSD has a working sys/queue.h and kqueue(2) interface */
43 #define HAVE_SYS_QUEUE_H
44 #define HAVE_KQUEUE
45 #elif defined(__linux__)
46 /* Assume Linux has a working epoll(3) interface */
47 #define HAVE_EPOLL
48 #endif
49 #endif
50
51 /* Our structures require TAILQ macros, which really every libc should
52  * ship as they are useful beyond belief.
53  * Sadly some libc's don't have sys/queue.h and some that do don't have
54  * the TAILQ_FOREACH macro. For those that don't, the application using
55  * this implementation will need to ship a working queue.h somewhere.
56  * If we don't have sys/queue.h found in config.h, then
57  * allow QUEUE_H to override loading queue.h in the current directory. */
58 #ifndef TAILQ_FOREACH
59 #ifdef HAVE_SYS_QUEUE_H
60 #include <sys/queue.h>
61 #elif defined(QUEUE_H)
62 #define __QUEUE_HEADER(x) #x
63 #define _QUEUE_HEADER(x) __QUEUE_HEADER(x)
64 #include _QUEUE_HEADER(QUEUE_H)
65 #else
66 #include "queue.h"
67 #endif
68 #endif
69
70 /* Some systems don't define timespec macros */
71 #ifndef timespecclear
72 #define timespecclear(tsp)      (tsp)->tv_sec = (time_t)((tsp)->tv_nsec = 0L)
73 #define timespecisset(tsp)      ((tsp)->tv_sec || (tsp)->tv_nsec)
74 #define timespeccmp(tsp, usp, cmp)                                      \
75         (((tsp)->tv_sec == (usp)->tv_sec) ?                             \
76             ((tsp)->tv_nsec cmp (usp)->tv_nsec) :                       \
77             ((tsp)->tv_sec cmp (usp)->tv_sec))
78 #define timespecadd(tsp, usp, vsp)                                      \
79         do {                                                            \
80                 (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec;          \
81                 (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec;       \
82                 if ((vsp)->tv_nsec >= 1000000000L) {                    \
83                         (vsp)->tv_sec++;                                \
84                         (vsp)->tv_nsec -= 1000000000L;                  \
85                 }                                                       \
86         } while (/* CONSTCOND */ 0)
87 #define timespecsub(tsp, usp, vsp)                                      \
88         do {                                                            \
89                 (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;          \
90                 (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;       \
91                 if ((vsp)->tv_nsec < 0) {                               \
92                         (vsp)->tv_sec--;                                \
93                         (vsp)->tv_nsec += 1000000000L;                  \
94                 }                                                       \
95         } while (/* CONSTCOND */ 0)
96 #endif
97
98 /* eloop queues are really only for deleting timeouts registered
99  * for a function or object.
100  * The idea being that one interface as different timeouts for
101  * say DHCP and DHCPv6. */
102 #ifndef ELOOP_QUEUE
103   #define ELOOP_QUEUE 1
104 #endif
105
106 struct eloop_event {
107         TAILQ_ENTRY(eloop_event) next;
108         int fd;
109         void (*read_cb)(void *);
110         void *read_cb_arg;
111         void (*write_cb)(void *);
112         void *write_cb_arg;
113 #if !defined(HAVE_KQUEUE) && !defined(HAVE_EPOLL)
114         struct pollfd *pollfd;
115 #endif
116 };
117
118 struct eloop_timeout {
119         TAILQ_ENTRY(eloop_timeout) next;
120         struct timespec when;
121         void (*callback)(void *);
122         void *arg;
123         int queue;
124 };
125
126 struct eloop {
127         size_t events_len;
128         TAILQ_HEAD (event_head, eloop_event) events;
129         struct event_head free_events;
130
131         TAILQ_HEAD (timeout_head, eloop_timeout) timeouts;
132         struct timeout_head free_timeouts;
133
134         void (*timeout0)(void *);
135         void *timeout0_arg;
136         const int *signals;
137         void (*signal_cb)(int, void *);
138         void *signal_cb_ctx;
139
140 #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
141         int poll_fd;
142 #else
143         struct pollfd *fds;
144         size_t fds_len;
145 #endif
146
147         int exitnow;
148         int exitcode;
149 };
150
151 int eloop_event_add(struct eloop *, int,
152     void (*)(void *), void *,
153     void (*)(void *), void *);
154 void eloop_event_delete(struct eloop *, int, int);
155
156 #define eloop_timeout_add_tv(eloop, tv, cb, ctx) \
157     eloop_q_timeout_add_tv((eloop), ELOOP_QUEUE, (tv), (cb), (ctx))
158 #define eloop_timeout_add_sec(eloop, tv, cb, ctx) \
159     eloop_q_timeout_add_sec((eloop), ELOOP_QUEUE, (tv), (cb), (ctx))
160 #define eloop_timeout_add_msec(eloop, ms, cb, ctx) \
161     eloop_q_timeout_add_msec((eloop), ELOOP_QUEUE, (ms), (cb), (ctx))
162 #define eloop_timeout_delete(eloop, cb, ctx) \
163     eloop_q_timeout_delete((eloop), ELOOP_QUEUE, (cb), (ctx))
164 int eloop_q_timeout_add_tv(struct eloop *, int queue,
165     const struct timespec *, void (*)(void *), void *);
166 int eloop_q_timeout_add_sec(struct eloop *, int queue,
167     time_t, void (*)(void *), void *);
168 int eloop_q_timeout_add_msec(struct eloop *, int queue,
169     long, void (*)(void *), void *);
170 void eloop_q_timeout_delete(struct eloop *, int, void (*)(void *), void *);
171
172 int eloop_signal_set_cb(struct eloop *, const int *,
173     void (*)(int, void *), void *);
174 int eloop_signal_mask(struct eloop *, sigset_t *oldset);
175
176 struct eloop * eloop_new(void);
177 #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
178 int eloop_requeue(struct eloop *);
179 #else
180 #define eloop_requeue(eloop) (0)
181 #endif
182 void eloop_free(struct eloop *);
183 void eloop_exit(struct eloop *, int);
184 int eloop_start(struct eloop *, sigset_t *);
185
186 #endif