1 /*
2  * Copyright (c) 2011, 2012 William Pitcock <nenolod@dereferenced.org>.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
9  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
12  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
17  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
18  * POSSIBILITY OF SUCH DAMAGE.
19  */
20 
21 #ifndef __MOWGLI_EVENTLOOP_EVENTLOOP_H__
22 #define __MOWGLI_EVENTLOOP_EVENTLOOP_H__
23 
24 #ifdef MOWGLI_OS_OSX
25 
26 # include <mach/mach.h>
27 # include <mach/mach_time.h>
28 
29 #endif
30 
31 #ifndef _WIN32
32 
33 typedef int mowgli_descriptor_t;
34 
35 #else
36 
37 typedef SOCKET mowgli_descriptor_t;
38 
39 #endif
40 
41 typedef enum
42 {
43 	MOWGLI_EVENTLOOP_TYPE_POLLABLE,
44 	MOWGLI_EVENTLOOP_TYPE_HELPER,
45 	MOWGLI_EVENTLOOP_TYPE_ERROR = -1
46 } mowgli_eventloop_io_type_t;
47 
48 typedef struct
49 {
50 	mowgli_eventloop_io_type_t type;
51 } mowgli_eventloop_io_obj_t;
52 
53 typedef struct _mowgli_eventloop mowgli_eventloop_t;
54 
55 typedef struct _mowgli_pollable mowgli_eventloop_pollable_t;
56 typedef struct _mowgli_helper mowgli_eventloop_helper_proc_t;
57 
58 typedef struct _mowgli_linebuf mowgli_linebuf_t;
59 
60 typedef enum
61 {
62 	MOWGLI_EVENTLOOP_IO_READ,
63 	MOWGLI_EVENTLOOP_IO_WRITE,
64 	MOWGLI_EVENTLOOP_IO_ERROR = -1
65 } mowgli_eventloop_io_dir_t;
66 
67 typedef void mowgli_eventloop_io_t;
68 
69 /* checked casts */
70 static inline mowgli_eventloop_pollable_t *
mowgli_eventloop_io_pollable(mowgli_eventloop_io_t * io)71 mowgli_eventloop_io_pollable(mowgli_eventloop_io_t *io)
72 {
73 	mowgli_eventloop_io_obj_t *obj = (mowgli_eventloop_io_obj_t *) io;
74 
75 	return_val_if_fail(io != NULL, NULL);
76 	return_val_if_fail(obj->type == MOWGLI_EVENTLOOP_TYPE_POLLABLE, NULL);
77 
78 	return (mowgli_eventloop_pollable_t *) io;
79 }
80 
81 static inline mowgli_eventloop_helper_proc_t *
mowgli_eventloop_io_helper(mowgli_eventloop_io_t * io)82 mowgli_eventloop_io_helper(mowgli_eventloop_io_t *io)
83 {
84 	mowgli_eventloop_io_obj_t *obj = (mowgli_eventloop_io_obj_t *) io;
85 
86 	return_val_if_fail(io != NULL, NULL);
87 	return_val_if_fail(obj->type == MOWGLI_EVENTLOOP_TYPE_HELPER, NULL);
88 
89 	return (mowgli_eventloop_helper_proc_t *) io;
90 }
91 
92 static inline mowgli_eventloop_io_type_t
mowgli_eventloop_io_type(mowgli_eventloop_io_t * io)93 mowgli_eventloop_io_type(mowgli_eventloop_io_t *io)
94 {
95 	mowgli_eventloop_io_obj_t *obj = (mowgli_eventloop_io_obj_t *) io;
96 
97 	return_val_if_fail(io != NULL, MOWGLI_EVENTLOOP_TYPE_ERROR);
98 
99 	return obj->type;
100 }
101 
102 typedef void mowgli_eventloop_io_cb_t (mowgli_eventloop_t * eventloop, mowgli_eventloop_io_t * io, mowgli_eventloop_io_dir_t dir, void *userdata);
103 
104 struct _mowgli_pollable
105 {
106 	mowgli_eventloop_io_obj_t type;
107 
108 	mowgli_descriptor_t fd;
109 	unsigned int slot;
110 	unsigned int events;
111 
112 	mowgli_eventloop_io_cb_t *read_function;
113 	mowgli_eventloop_io_cb_t *write_function;
114 	mowgli_eventloop_io_cb_t *error_function;
115 
116 	void *userdata;
117 
118 	mowgli_node_t node;
119 
120 	mowgli_eventloop_t *eventloop;
121 };
122 
123 typedef struct
124 {
125 	void (*timeout_once)(mowgli_eventloop_t *eventloop, int timeout);
126 	void (*run_once)(mowgli_eventloop_t *eventloop);
127 	void (*pollsetup)(mowgli_eventloop_t *eventloop);
128 	void (*pollshutdown)(mowgli_eventloop_t *eventloop);
129 	void (*setselect)(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function);
130 	void (*select)(mowgli_eventloop_t *eventloop, int time);
131 	void (*destroy)(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable);
132 } mowgli_eventloop_ops_t;
133 
134 struct _mowgli_eventloop
135 {
136 	time_t currtime;
137 	time_t deadline;
138 
139 	const char *last_ran;
140 
141 	mowgli_list_t timer_list;
142 	mowgli_mutex_t mutex;
143 
144 	mowgli_eventloop_ops_t *eventloop_ops;
145 	void *poller;
146 
147 	bool death_requested;
148 
149 	void *data;
150 
151 	time_t epochbias;
152 };
153 
154 typedef void mowgli_event_dispatch_func_t (void *userdata);
155 
156 typedef struct
157 {
158 	mowgli_node_t node;
159 
160 	mowgli_event_dispatch_func_t *func;
161 	void *arg;
162 	const char *name;
163 	time_t frequency;
164 	time_t deadline;
165 	bool active;
166 } mowgli_eventloop_timer_t;
167 
168 static inline void
mowgli_eventloop_set_time(mowgli_eventloop_t * eventloop,time_t newtime)169 mowgli_eventloop_set_time(mowgli_eventloop_t *eventloop, time_t newtime)
170 {
171 	return_if_fail(eventloop != NULL);
172 
173 	eventloop->currtime = newtime;
174 }
175 
176 static inline time_t
mowgli_eventloop_get_time(mowgli_eventloop_t * eventloop)177 mowgli_eventloop_get_time(mowgli_eventloop_t *eventloop)
178 {
179 	return_val_if_fail(eventloop != NULL, 0);
180 
181 	return eventloop->epochbias + eventloop->currtime;
182 }
183 
184 static inline void
mowgli_eventloop_synchronize(mowgli_eventloop_t * eventloop)185 mowgli_eventloop_synchronize(mowgli_eventloop_t *eventloop)
186 {
187 	long long time_;
188 
189 #if defined(CLOCK_MONOTONIC)
190 	struct timespec tp;
191 
192 	clock_gettime(CLOCK_MONOTONIC, &tp);
193 	time_ = tp.tv_sec;
194 #elif defined(CLOCK_HIGHRES)
195 	struct timespec tp;
196 
197 	clock_gettime(CLOCK_HIGHRES, &tp);
198 	time_ = tp.tv_sec;
199 #elif defined(MOWGLI_OS_WIN)
200 	static ULONGLONG (CALLBACK *GetTickCount64)(void) = NULL;
201 	static OSVERSIONINFOEX *winver = NULL;
202 	static bool load_err = false;
203 
204 	if (winver == NULL)
205 	{
206 		winver = mowgli_alloc(sizeof(OSVERSIONINFOEX));
207 		winver->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
208 
209 		if (!GetVersionEx((OSVERSIONINFO *) winver))
210 		{
211 			mowgli_free(winver);
212 			winver = NULL;	/* FIXME */
213 		}
214 	}
215 
216 	if (winver && (winver->dwMajorVersion >= 6))
217 	{
218 		if ((GetTickCount64 == NULL) && !load_err)
219 		{
220 			HINSTANCE hKernel32;
221 
222 			hKernel32 = GetModuleHandle("KERNEL32");
223 			GetTickCount64 = GetProcAddress(hKernel32, "GetTickCount64");
224 
225 			if (GetTickCount64 == NULL)
226 				load_err = true;
227 		}
228 
229 		if (load_err)
230 		{
231 			time_ = time(NULL);
232 		}
233 		else
234 		{
235 			soft_assert(GetTickCount64 != NULL);
236 
237 			time_ = (int) (GetTickCount64() * 1e-3);
238 		}
239 	}
240 	else
241 	{
242 		time_ = time(NULL);
243 	}
244 
245 #elif defined(MOWGLI_OS_OSX)
246 	static mach_timebase_info_data_t timebase;
247 
248 	if (timebase.denom == 0)
249 		mach_timebase_info(&timebase);
250 
251 	time_ = (int) (mach_absolute_time() * timebase.numer / timebase.denom * 1e-9);
252 #else
253 	time_ = time(NULL);
254 #endif
255 	mowgli_eventloop_set_time(eventloop, (time_t) time_);
256 }
257 
258 /* Sets the bias of eventloop->currtime relative to Jan 1 00:00:00 1970 */
259 static inline void
mowgli_eventloop_calibrate(mowgli_eventloop_t * eventloop)260 mowgli_eventloop_calibrate(mowgli_eventloop_t *eventloop)
261 {
262 	mowgli_eventloop_synchronize(eventloop);
263 	eventloop->epochbias = time(NULL) - eventloop->currtime;
264 }
265 
266 static inline bool
mowgli_eventloop_ignore_errno(int error)267 mowgli_eventloop_ignore_errno(int error)
268 {
269 	switch (error)
270 	{
271 #ifdef EINPROGRESS
272 	case EINPROGRESS:
273 #endif
274 #if defined(EWOULDBLOCK)
275 	case EWOULDBLOCK:
276 #endif
277 #if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
278 	case EAGAIN:
279 #endif
280 #ifdef ETIME
281 	case ETIME:
282 #endif
283 #ifdef EINTR
284 	case EINTR:
285 #endif
286 #ifdef ERESTART
287 	case ERESTART:
288 #endif
289 #ifdef ENOBUFS
290 	case ENOBUFS:
291 #endif
292 #ifdef ENOENT
293 	case ENOENT:
294 #endif
295 		return true;
296 	default:
297 		break;
298 	}
299 
300 	return false;
301 }
302 
303 typedef void mowgli_eventloop_helper_start_fn_t (mowgli_eventloop_helper_proc_t * helper, void *userdata);
304 
305 struct _mowgli_helper
306 {
307 	mowgli_eventloop_io_obj_t type;
308 
309 	mowgli_process_t *child;
310 	mowgli_eventloop_t *eventloop;
311 
312 	mowgli_descriptor_t fd;
313 	mowgli_eventloop_pollable_t *pfd;
314 
315 	mowgli_eventloop_io_cb_t *read_function;
316 
317 	void *userdata;
318 };
319 
320 /* helper.c */
321 extern mowgli_eventloop_helper_proc_t *mowgli_helper_create(mowgli_eventloop_t *eventloop, mowgli_eventloop_helper_start_fn_t *start_fn, const char *helpername, void *userdata);
322 
323 /* creation of helpers inside other executable images */
324 extern mowgli_eventloop_helper_proc_t *mowgli_helper_spawn(mowgli_eventloop_t *eventloop, const char *path, char *const argv[]);
325 extern mowgli_eventloop_helper_proc_t *mowgli_helper_setup(mowgli_eventloop_t *eventloop);
326 
327 /* synchronization of helpers happens on reading from mowgli_eventloop_helper_proc_t::in_pfd. */
328 extern void mowgli_helper_set_read_cb(mowgli_eventloop_t *eventloop, mowgli_eventloop_helper_proc_t *helper, mowgli_eventloop_io_cb_t *read_fn);
329 extern void mowgli_helper_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_helper_proc_t *helper);
330 
331 /* null_pollops.c */
332 extern void mowgli_simple_eventloop_run_once(mowgli_eventloop_t *eventloop);
333 extern void mowgli_simple_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int timeout);
334 extern void mowgli_simple_eventloop_error_handler(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata);
335 
336 /* eventloop.c */
337 extern mowgli_eventloop_t *mowgli_eventloop_create(void);
338 extern void mowgli_eventloop_destroy(mowgli_eventloop_t *eventloop);
339 extern void mowgli_eventloop_run(mowgli_eventloop_t *eventloop);
340 extern void mowgli_eventloop_run_once(mowgli_eventloop_t *eventloop);
341 extern void mowgli_eventloop_timeout_once(mowgli_eventloop_t *eventloop, int timeout);
342 extern void mowgli_eventloop_break(mowgli_eventloop_t *eventloop);
343 extern void mowgli_eventloop_timers_only(mowgli_eventloop_t *eventloop);
344 extern void mowgli_eventloop_set_data(mowgli_eventloop_t *eventloop, void *data);
345 extern void *mowgli_eventloop_get_data(mowgli_eventloop_t *eventloop);
346 
347 /* timer.c */
348 extern mowgli_eventloop_timer_t *mowgli_timer_add(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when);
349 extern mowgli_eventloop_timer_t *mowgli_timer_add_once(mowgli_eventloop_t *eventloop, const char *name, mowgli_event_dispatch_func_t *func, void *arg, time_t when);
350 extern void mowgli_timer_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_timer_t *timer);
351 extern void mowgli_eventloop_run_timers(mowgli_eventloop_t *eventloop);
352 extern time_t mowgli_eventloop_next_timer(mowgli_eventloop_t *eventloop);
353 extern mowgli_eventloop_timer_t *mowgli_timer_find(mowgli_eventloop_t *eventloop, mowgli_event_dispatch_func_t *func, void *arg);
354 
355 /* pollable.c */
356 extern mowgli_eventloop_pollable_t *mowgli_pollable_create(mowgli_eventloop_t *eventloop, mowgli_descriptor_t fd, void *userdata);
357 extern void mowgli_pollable_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable);
358 extern void mowgli_pollable_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function);
359 extern void mowgli_pollable_set_nonblocking(mowgli_eventloop_pollable_t *pollable, bool nonblocking);
360 extern void mowgli_pollable_set_cloexec(mowgli_eventloop_pollable_t *pollable, bool cloexec);
361 extern void mowgli_pollable_trigger(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir);
362 
363 #endif
364