1 /*
2 * Copyright (C) 2011 Citrix Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14 /*
15 * Internal event machinery for use by other parts of libxl
16 */
17
18 #include <poll.h>
19
20 #include "libxl_internal.h"
21
22
23 //#define DEBUG 1
24
25 #ifdef DEBUG
26 # define LIBXL__DBG_LOG(ctx, args, ...) \
27 LIBXL__LOG((ctx), XTL_DEBUG, args, __VA_ARGS__)
28 #else
29 # define LIBXL__DBG_LOG(ctx, args, ...) ((void)0)
30 #endif
31 #define DBG(args, ...) LIBXL__DBG_LOG(CTX, args, __VA_ARGS__)
32
33
34 static libxl__ao *ao_nested_root(libxl__ao *ao);
35
36 static void ao__check_destroy(libxl_ctx *ctx, libxl__ao *ao);
37
38
39 /*
40 * osevent update baton handling
41 *
42 * We need the following property (the "unstale liveness property"):
43 *
44 * Whenever any thread is blocking as a result of being given an fd
45 * set or timeout by libxl, at least one thread must be using an up to
46 * date osevent set. It is OK for all but one threads to have stale
47 * event sets, because so long as one waiting thread has the right
48 * event set, any actually interesting event will, if nothing else,
49 * wake that "right" thread up. It will then make some progress
50 * and/or, if it exits, ensure that some other thread becomes the
51 * "right" thread.
52 *
53 * For threads blocking outside libxl and which are receiving libxl's
54 * fd and timeout information via the libxl_osevent_hooks callbacks,
55 * libxl calls this function as soon as it becomes interested. It is
56 * the responsiblity of a provider of these functions in a
57 * multithreaded environment to make arrangements to wake up event
58 * waiting thread(s) with stale event sets.
59 *
60 * Waiters outside libxl using _beforepoll are dealt with below.
61 *
62 * For the libxl event loop, the argument is as follows:
63 *
64 * The issue we are concerned about is libxl sleeping on an out of
65 * date fd set, or too long a timeout, so that it doesn't make
66 * progress. If the property above is satisfied, then if any thread
67 * is waiting in libxl at least one such thread will be waiting on a
68 * sufficient osevent set, so any relevant osevent will wake up a
69 * libxl thread which will either handle the event, or arrange that at
70 * least one other libxl thread has the right set.
71 *
72 * There are two calls to poll in libxl: one is the fd recheck, which
73 * is not blocking. There is only the one blocking call, in
74 * eventloop_iteration. poll runs with the ctx unlocked, so osevents
75 * might be added after it unlocks the ctx - that is what we are
76 * worried about.
77 *
78 * To demonstrate that the unstale liveness property is satisfied:
79 *
80 * We define a baton holder as follows: a libxl thread is a baton
81 * holder if
82 * (a) it has an egc or an ao and holds the ctx lock, or
83 * (b) it has an active non-app poller and no osevents have been
84 * added since it released the lock, or
85 * (c) it has an active non-app poller which has been woken
86 * (by writing to its pipe), so it will not sleep
87 * We will maintain the invariant (the "baton invariant") that
88 * whenever there is any active poller, there is at least
89 * one baton holder. ("non-app" means simply "not poller_app".)
90 *
91 * No thread outside libxl can have an active non-app poller: pollers
92 * are put on the active list by poller_get which is called in three
93 * places: libxl_event_wait, which puts it before returning;
94 * libxl__ao_create but only in the synchronous case, in which case
95 * the poller is put before returning; and the poller_app, during
96 * initialisation.
97 *
98 * So any time when all libxl threads are blocking (and therefore do
99 * not have the ctx lock), the non-app active pollers belong to those
100 * threads. If at least one is a baton holder (the invariant), that
101 * thread has a good enough event set.
102 *
103 * Now we will demonstrate that the "baton invariant" is maintained:
104 *
105 * The rule is that any thread which might be the baton holder is
106 * responsible for checking that there continues to be a baton holder
107 * as needed.
108 *
109 * Firstly, consider the case when the baton holders (b) cease to be
110 * baton holders because osevents are added.
111 *
112 * There are only two kinds of osevents: timeouts and fds. Every
113 * other internal event source reduces to one of these eventually.
114 * Both of these cases are handled (in the case of fd events, add and
115 * modify, separately), calling pollers_note_osevent_added.
116 *
117 * This walks the poller_active list, marking the active pollers
118 * osevents_added=1. Such a poller cannot be the baton holder. But
119 * pollers_note_osevent_added is called only from ev_* functions,
120 * which are only called from event-chain libxl code: ie, code with an
121 * ao or an egc. So at this point we are a baton holder, and there is
122 * still a baton holder.
123 *
124 * Secondly, consider the case where baton holders (a) cease to be
125 * batton holders because they dispose of their egc or ao. We call
126 * libxl__egc_ao_cleanup_1_baton on every exit path. We arrange that
127 * everything that disposes of an egc or an ao checks that there is a
128 * new baton holder by calling libxl__egc_ao_cleanup_1_baton.
129 *
130 * This function handles the invariant explicitly: if we have any
131 * non-app active pollers it looks for one which is up to date (baton
132 * holder category (b)), and failing that it picks a victim to turn
133 * into the baton holder category (c) by waking it up. (Correctness
134 * depends on this function not spotting its own thread as the
135 * baton-holder, since it is on its way to not being the baton-holder,
136 * so it must be called after the poller has been put back.)
137 *
138 * Thirdly, we must consider the case (c). A thread in category (c)
139 * will reenter libxl when it gains the lock and necessarily then
140 * becomes a baton holder in category (a).
141 *
142 * So the "baton invariant" is maintained.
143 * QED (for waiters in libxl).
144 *
145 *
146 * For waiters outside libxl which used libxl_osevent_beforepoll
147 * to get the fd set:
148 *
149 * As above, adding an osevent involves having an egc or an ao.
150 * It sets poller->osevents_added on all active pollers. Notably
151 * it sets it on poller_app, which is always active.
152 *
153 * The thread which does this will dispose of its egc or ao before
154 * exiting libxl so it will always wake up the poller_app if the last
155 * call to _beforepoll was before the osevents were added. So the
156 * application's fd set contains at least a wakeup in the form of the
157 * poller_app fd. The application cannot sleep on the libxl fd set
158 * until it has called _afterpoll which empties the pipe, and it
159 * is expected to then call _beforepoll again before sleeping.
160 *
161 * So all the application's event waiting thread(s) will always have
162 * an up to date osevent set, and will be woken up if necessary to
163 * achieve this. (This is in contrast libxl's own event loop where
164 * only one thread need be up to date, as discussed above.)
165 */
pollers_note_osevent_added(libxl_ctx * ctx)166 static void pollers_note_osevent_added(libxl_ctx *ctx) {
167 libxl__poller *poller;
168 LIBXL_LIST_FOREACH(poller, &ctx->pollers_active, active_entry)
169 poller->osevents_added = 1;
170 }
171
baton_wake(libxl__gc * gc,libxl__poller * wake)172 static void baton_wake(libxl__gc *gc, libxl__poller *wake)
173 {
174 libxl__poller_wakeup(gc, wake);
175
176 wake->osevents_added = 0;
177 /* This serves to make _1_baton idempotent. It is OK even though
178 * that poller may currently be sleeping on only old osevents,
179 * because it is going to wake up because we've just prodded it,
180 * and it pick up new osevents on its next iteration (or pass
181 * on the baton). */
182 }
183
libxl__egc_ao_cleanup_1_baton(libxl__gc * gc)184 void libxl__egc_ao_cleanup_1_baton(libxl__gc *gc)
185 /* Any poller we had must have been `put' already. */
186 {
187 libxl__poller *search, *wake=0;
188
189 if (CTX->poller_app->osevents_added)
190 baton_wake(gc, CTX->poller_app);
191
192 LIBXL_LIST_FOREACH(search, &CTX->pollers_active, active_entry) {
193 if (search == CTX->poller_app)
194 /* This one is special. We can't give it the baton. */
195 continue;
196 if (!search->osevents_added)
197 /* This poller is up to date and will wake up as needed. */
198 return;
199 if (!wake)
200 wake = search;
201 }
202
203 if (!wake)
204 /* no-one in libxl waiting for any events */
205 return;
206
207 baton_wake(gc, wake);
208 }
209
210 /*
211 * The counter osevent_in_hook is used to ensure that the application
212 * honours the reentrancy restriction documented in libxl_event.h.
213 *
214 * The application's registration hooks should be called ONLY via
215 * these macros, with the ctx locked. Likewise all the "occurred"
216 * entrypoints from the application should assert(!in_hook);
217 *
218 * During the hook call - including while the arguments are being
219 * evaluated - ev->nexus is guaranteed to be valid and refer to the
220 * nexus which is being used for this event registration. The
221 * arguments should specify ev->nexus for the for_libxl argument and
222 * ev->nexus->for_app_reg (or a pointer to it) for for_app_reg.
223 */
224 #define OSEVENT_HOOK_INTERN(retval, failedp, evkind, hookop, nexusop, ...) do { \
225 if (CTX->osevent_hooks) { \
226 CTX->osevent_in_hook++; \
227 libxl__osevent_hook_nexi *nexi = &CTX->hook_##evkind##_nexi_idle; \
228 osevent_hook_pre_##nexusop(gc, ev, nexi, &ev->nexus); \
229 retval CTX->osevent_hooks->evkind##_##hookop \
230 (CTX->osevent_user, __VA_ARGS__); \
231 if ((failedp)) \
232 osevent_hook_failed_##nexusop(gc, ev, nexi, &ev->nexus); \
233 CTX->osevent_in_hook--; \
234 } \
235 } while (0)
236
237 #define OSEVENT_HOOK(evkind, hookop, nexusop, ...) ({ \
238 int osevent_hook_rc = 0; \
239 OSEVENT_HOOK_INTERN(osevent_hook_rc =, !!osevent_hook_rc, \
240 evkind, hookop, nexusop, __VA_ARGS__); \
241 osevent_hook_rc; \
242 })
243
244 #define OSEVENT_HOOK_VOID(evkind, hookop, nexusop, ...) \
245 OSEVENT_HOOK_INTERN(/* void */, 0, evkind, hookop, nexusop, __VA_ARGS__)
246
247 /*
248 * The application's calls to libxl_osevent_occurred_... may be
249 * indefinitely delayed with respect to the rest of the program (since
250 * they are not necessarily called with any lock held). So the
251 * for_libxl value we receive may be (almost) arbitrarily old. All we
252 * know is that it came from this ctx.
253 *
254 * Therefore we may not free the object referred to by any for_libxl
255 * value until we free the whole libxl_ctx. And if we reuse it we
256 * must be able to tell when an old use turns up, and discard the
257 * stale event.
258 *
259 * Thus we cannot use the ev directly as the for_libxl value - we need
260 * a layer of indirection.
261 *
262 * We do this by keeping a pool of libxl__osevent_hook_nexus structs,
263 * and use pointers to them as for_libxl values. In fact, there are
264 * two pools: one for fds and one for timeouts. This ensures that we
265 * don't risk a type error when we upcast nexus->ev. In each nexus
266 * the ev is either null or points to a valid libxl__ev_time or
267 * libxl__ev_fd, as applicable.
268 *
269 * We /do/ allow ourselves to reassociate an old nexus with a new ev
270 * as otherwise we would have to leak nexi. (This reassociation
271 * might, of course, be an old ev being reused for a new purpose so
272 * simply comparing the ev pointer is not sufficient.) Thus the
273 * libxl_osevent_occurred functions need to check that the condition
274 * allegedly signalled by this event actually exists.
275 *
276 * The nexi and the lists are all protected by the ctx lock.
277 */
278
279 struct libxl__osevent_hook_nexus {
280 void *ev;
281 void *for_app_reg;
282 LIBXL_SLIST_ENTRY(libxl__osevent_hook_nexus) next;
283 };
284
osevent_ev_from_hook_nexus(libxl_ctx * ctx,libxl__osevent_hook_nexus * nexus)285 static void *osevent_ev_from_hook_nexus(libxl_ctx *ctx,
286 libxl__osevent_hook_nexus *nexus /* pass void *for_libxl */)
287 {
288 return nexus->ev;
289 }
290
osevent_release_nexus(libxl__gc * gc,libxl__osevent_hook_nexi * nexi_idle,libxl__osevent_hook_nexus * nexus)291 static void osevent_release_nexus(libxl__gc *gc,
292 libxl__osevent_hook_nexi *nexi_idle,
293 libxl__osevent_hook_nexus *nexus)
294 {
295 nexus->ev = 0;
296 LIBXL_SLIST_INSERT_HEAD(nexi_idle, nexus, next);
297 }
298
299 /*----- OSEVENT* hook functions for nexusop "alloc" -----*/
osevent_hook_pre_alloc(libxl__gc * gc,void * ev,libxl__osevent_hook_nexi * nexi_idle,libxl__osevent_hook_nexus ** nexus_r)300 static void osevent_hook_pre_alloc(libxl__gc *gc, void *ev,
301 libxl__osevent_hook_nexi *nexi_idle,
302 libxl__osevent_hook_nexus **nexus_r)
303 {
304 libxl__osevent_hook_nexus *nexus = LIBXL_SLIST_FIRST(nexi_idle);
305 if (nexus) {
306 LIBXL_SLIST_REMOVE_HEAD(nexi_idle, next);
307 } else {
308 nexus = libxl__zalloc(NOGC, sizeof(*nexus));
309 }
310 nexus->ev = ev;
311 *nexus_r = nexus;
312 }
osevent_hook_failed_alloc(libxl__gc * gc,void * ev,libxl__osevent_hook_nexi * nexi_idle,libxl__osevent_hook_nexus ** nexus)313 static void osevent_hook_failed_alloc(libxl__gc *gc, void *ev,
314 libxl__osevent_hook_nexi *nexi_idle,
315 libxl__osevent_hook_nexus **nexus)
316 {
317 osevent_release_nexus(gc, nexi_idle, *nexus);
318 }
319
320 /*----- OSEVENT* hook functions for nexusop "release" -----*/
osevent_hook_pre_release(libxl__gc * gc,void * ev,libxl__osevent_hook_nexi * nexi_idle,libxl__osevent_hook_nexus ** nexus)321 static void osevent_hook_pre_release(libxl__gc *gc, void *ev,
322 libxl__osevent_hook_nexi *nexi_idle,
323 libxl__osevent_hook_nexus **nexus)
324 {
325 osevent_release_nexus(gc, nexi_idle, *nexus);
326 }
osevent_hook_failed_release(libxl__gc * gc,void * ev,libxl__osevent_hook_nexi * nexi_idle,libxl__osevent_hook_nexus ** nexus)327 static void osevent_hook_failed_release(libxl__gc *gc, void *ev,
328 libxl__osevent_hook_nexi *nexi_idle,
329 libxl__osevent_hook_nexus **nexus)
330 {
331 abort();
332 }
333
334 /*----- OSEVENT* hook functions for nexusop "noop" -----*/
osevent_hook_pre_noop(libxl__gc * gc,void * ev,libxl__osevent_hook_nexi * nexi_idle,libxl__osevent_hook_nexus ** nexus)335 static void osevent_hook_pre_noop(libxl__gc *gc, void *ev,
336 libxl__osevent_hook_nexi *nexi_idle,
337 libxl__osevent_hook_nexus **nexus) { }
osevent_hook_failed_noop(libxl__gc * gc,void * ev,libxl__osevent_hook_nexi * nexi_idle,libxl__osevent_hook_nexus ** nexus)338 static void osevent_hook_failed_noop(libxl__gc *gc, void *ev,
339 libxl__osevent_hook_nexi *nexi_idle,
340 libxl__osevent_hook_nexus **nexus) { }
341
342
343 /*
344 * fd events
345 */
346
libxl__ev_fd_register(libxl__gc * gc,libxl__ev_fd * ev,libxl__ev_fd_callback * func,int fd,short events)347 int libxl__ev_fd_register(libxl__gc *gc, libxl__ev_fd *ev,
348 libxl__ev_fd_callback *func,
349 int fd, short events)
350 {
351 int rc;
352
353 assert(fd >= 0);
354
355 CTX_LOCK;
356
357 DBG("ev_fd=%p register fd=%d events=%x", ev, fd, events);
358
359 rc = OSEVENT_HOOK(fd,register, alloc, fd, &ev->nexus->for_app_reg,
360 events, ev->nexus);
361 if (rc) goto out;
362
363 ev->fd = fd;
364 ev->events = events;
365 ev->func = func;
366
367 LIBXL_LIST_INSERT_HEAD(&CTX->efds, ev, entry);
368 pollers_note_osevent_added(CTX);
369
370 rc = 0;
371
372 out:
373 CTX_UNLOCK;
374 return rc;
375 }
376
libxl__ev_fd_modify(libxl__gc * gc,libxl__ev_fd * ev,short events)377 int libxl__ev_fd_modify(libxl__gc *gc, libxl__ev_fd *ev, short events)
378 {
379 int rc;
380
381 CTX_LOCK;
382 assert(libxl__ev_fd_isregistered(ev));
383
384 DBG("ev_fd=%p modify fd=%d events=%x", ev, ev->fd, events);
385
386 rc = OSEVENT_HOOK(fd,modify, noop, ev->fd, &ev->nexus->for_app_reg, events);
387 if (rc) goto out;
388
389 if ((events & ~ev->events))
390 pollers_note_osevent_added(CTX);
391 ev->events = events;
392
393 rc = 0;
394 out:
395 CTX_UNLOCK;
396 return rc;
397 }
398
libxl__ev_fd_deregister(libxl__gc * gc,libxl__ev_fd * ev)399 void libxl__ev_fd_deregister(libxl__gc *gc, libxl__ev_fd *ev)
400 {
401 CTX_LOCK;
402 libxl__poller *poller;
403
404 if (!libxl__ev_fd_isregistered(ev)) {
405 DBG("ev_fd=%p deregister unregistered",ev);
406 goto out;
407 }
408
409 DBG("ev_fd=%p deregister fd=%d", ev, ev->fd);
410
411 OSEVENT_HOOK_VOID(fd,deregister, release, ev->fd, ev->nexus->for_app_reg);
412 LIBXL_LIST_REMOVE(ev, entry);
413 ev->fd = -1;
414
415 LIBXL_LIST_FOREACH(poller, &CTX->pollers_active, active_entry)
416 poller->fds_deregistered = 1;
417
418 out:
419 CTX_UNLOCK;
420 }
421
libxl__fd_poll_recheck(libxl__egc * egc,int fd,short events)422 short libxl__fd_poll_recheck(libxl__egc *egc, int fd, short events) {
423 struct pollfd check;
424 int r;
425 EGC_GC;
426
427 for (;;) {
428 check.fd = fd;
429 check.events = events;
430 r = poll(&check, 1, 0);
431 DBG("poll recheck fd=%d r=%d revents=%#x", fd, r, check.revents);
432 if (!r)
433 break;
434 if (r==1)
435 break;
436 assert(r<0);
437 if (errno != EINTR) {
438 LIBXL__EVENT_DISASTER(gc, "failed poll to check for fd", errno, 0);
439 return 0;
440 }
441 }
442 assert(!!r == !!check.revents);
443 return check.revents;
444 }
445
446 /*
447 * timeouts
448 */
449
450
libxl__gettimeofday(libxl__gc * gc,struct timeval * now_r)451 int libxl__gettimeofday(libxl__gc *gc, struct timeval *now_r)
452 {
453 int rc = gettimeofday(now_r, 0);
454 if (rc) {
455 LOGE(ERROR, "gettimeofday failed");
456 return ERROR_FAIL;
457 }
458 return 0;
459 }
460
time_rel_to_abs(libxl__gc * gc,int ms,struct timeval * abs_out)461 static int time_rel_to_abs(libxl__gc *gc, int ms, struct timeval *abs_out)
462 {
463 int rc;
464 struct timeval additional = {
465 .tv_sec = ms / 1000,
466 .tv_usec = (ms % 1000) * 1000
467 };
468 struct timeval now;
469
470 rc = libxl__gettimeofday(gc, &now);
471 if (rc) return rc;
472
473 timeradd(&now, &additional, abs_out);
474 return 0;
475 }
476
time_register_finite(libxl__gc * gc,libxl__ev_time * ev,struct timeval absolute)477 static int time_register_finite(libxl__gc *gc, libxl__ev_time *ev,
478 struct timeval absolute)
479 {
480 int rc;
481 libxl__ev_time *evsearch;
482
483 rc = OSEVENT_HOOK(timeout,register, alloc, &ev->nexus->for_app_reg,
484 absolute, ev->nexus);
485 if (rc) return rc;
486
487 ev->infinite = 0;
488 ev->abs = absolute;
489 LIBXL_TAILQ_INSERT_SORTED(&CTX->etimes, entry, ev, evsearch, /*empty*/,
490 timercmp(&ev->abs, &evsearch->abs, >));
491
492 pollers_note_osevent_added(CTX);
493 return 0;
494 }
495
time_deregister(libxl__gc * gc,libxl__ev_time * ev)496 static void time_deregister(libxl__gc *gc, libxl__ev_time *ev)
497 {
498 libxl__ao_abortable_deregister(&ev->abrt);
499
500 if (!ev->infinite) {
501 struct timeval right_away = { 0, 0 };
502 if (ev->nexus) /* only set if app provided hooks */
503 ev->nexus->ev = 0;
504 OSEVENT_HOOK_VOID(timeout,modify,
505 noop /* release nexus in _occurred_ */,
506 &ev->nexus->for_app_reg, right_away);
507 LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry);
508 }
509 }
510
time_done_debug(libxl__gc * gc,const char * func,libxl__ev_time * ev,int rc)511 static void time_done_debug(libxl__gc *gc, const char *func,
512 libxl__ev_time *ev, int rc)
513 {
514 #ifdef DEBUG
515 libxl__log(CTX, XTL_DEBUG, -1, __FILE__, 0, func, INVALID_DOMID,
516 "ev_time=%p done rc=%d .func=%p infinite=%d abs=%lu.%06lu",
517 ev, rc, ev->func, ev->infinite,
518 (unsigned long)ev->abs.tv_sec, (unsigned long)ev->abs.tv_usec);
519 #endif
520 }
521
time_aborted(libxl__egc * egc,libxl__ao_abortable * abrt,int rc)522 static void time_aborted(libxl__egc *egc, libxl__ao_abortable *abrt, int rc)
523 {
524 libxl__ev_time *ev = CONTAINER_OF(abrt, *ev, abrt);
525 EGC_GC;
526
527 time_deregister(gc, ev);
528 DBG("ev_time=%p aborted", ev);
529 ev->func(egc, ev, &ev->abs, rc);
530 }
531
time_register_abortable(libxl__ao * ao,libxl__ev_time * ev)532 static int time_register_abortable(libxl__ao *ao, libxl__ev_time *ev)
533 {
534 ev->abrt.ao = ao;
535 ev->abrt.callback = time_aborted;
536 return libxl__ao_abortable_register(&ev->abrt);
537 }
538
libxl__ev_time_register_abs(libxl__ao * ao,libxl__ev_time * ev,libxl__ev_time_callback * func,struct timeval absolute)539 int libxl__ev_time_register_abs(libxl__ao *ao, libxl__ev_time *ev,
540 libxl__ev_time_callback *func,
541 struct timeval absolute)
542 {
543 AO_GC;
544 int rc;
545
546 CTX_LOCK;
547
548 DBG("ev_time=%p register abs=%lu.%06lu",
549 ev, (unsigned long)absolute.tv_sec, (unsigned long)absolute.tv_usec);
550
551 rc = time_register_abortable(ao, ev);
552 if (rc) goto out;
553
554 rc = time_register_finite(gc, ev, absolute);
555 if (rc) goto out;
556
557 ev->func = func;
558
559 rc = 0;
560 out:
561 libxl__ao_abortable_deregister(&ev->abrt);
562 time_done_debug(gc,__func__,ev,rc);
563 CTX_UNLOCK;
564 return rc;
565 }
566
567
libxl__ev_time_register_rel(libxl__ao * ao,libxl__ev_time * ev,libxl__ev_time_callback * func,int milliseconds)568 int libxl__ev_time_register_rel(libxl__ao *ao, libxl__ev_time *ev,
569 libxl__ev_time_callback *func,
570 int milliseconds /* as for poll(2) */)
571 {
572 AO_GC;
573 struct timeval absolute;
574 int rc;
575
576 CTX_LOCK;
577
578 DBG("ev_time=%p register ms=%d", ev, milliseconds);
579
580 rc = time_register_abortable(ao, ev);
581 if (rc) goto out;
582
583 if (milliseconds < 0) {
584 ev->infinite = 1;
585 } else {
586 rc = time_rel_to_abs(gc, milliseconds, &absolute);
587 if (rc) goto out;
588
589 rc = time_register_finite(gc, ev, absolute);
590 if (rc) goto out;
591 }
592
593 ev->func = func;
594 rc = 0;
595
596 out:
597 if (!libxl__ev_time_isregistered(ev))
598 libxl__ao_abortable_deregister(&ev->abrt);
599 time_done_debug(gc,__func__,ev,rc);
600 CTX_UNLOCK;
601 return rc;
602 }
603
libxl__ev_time_deregister(libxl__gc * gc,libxl__ev_time * ev)604 void libxl__ev_time_deregister(libxl__gc *gc, libxl__ev_time *ev)
605 {
606 CTX_LOCK;
607
608 DBG("ev_time=%p deregister", ev);
609
610 if (!libxl__ev_time_isregistered(ev))
611 goto out;
612
613 time_deregister(gc, ev);
614 ev->func = 0;
615
616 out:
617 time_done_debug(gc,__func__,ev,0);
618 CTX_UNLOCK;
619 return;
620 }
621
time_occurs(libxl__egc * egc,libxl__ev_time * etime,int rc)622 static void time_occurs(libxl__egc *egc, libxl__ev_time *etime, int rc)
623 {
624 EGC_GC;
625
626 DBG("ev_time=%p occurs abs=%lu.%06lu",
627 etime, (unsigned long)etime->abs.tv_sec,
628 (unsigned long)etime->abs.tv_usec);
629
630 libxl__ev_time_callback *func = etime->func;
631 etime->func = 0;
632 func(egc, etime, &etime->abs, rc);
633 }
634
635
636 /*
637 * xenstore watches
638 */
639
libxl__watch_slot_contents(libxl__gc * gc,int slotnum)640 libxl__ev_xswatch *libxl__watch_slot_contents(libxl__gc *gc, int slotnum)
641 {
642 libxl__ev_watch_slot *slot = &CTX->watch_slots[slotnum];
643 libxl__ev_watch_slot *slotcontents = LIBXL_SLIST_NEXT(slot, empty);
644
645 if (slotcontents == NULL ||
646 ((uintptr_t)slotcontents >= (uintptr_t)CTX->watch_slots &&
647 (uintptr_t)slotcontents < (uintptr_t)(CTX->watch_slots +
648 CTX->watch_nslots)))
649 /* An empty slot has either a NULL pointer (end of the
650 * free list), or a pointer to another entry in the array.
651 * So we can do a bounds check to distinguish empty from
652 * full slots.
653 */
654 /* We need to do the comparisons as uintptr_t because
655 * comparing pointers which are not in the same object is
656 * undefined behaviour; if the compiler managed to figure
657 * out that watch_slots[0..watch_nslots-1] is all of the
658 * whole array object it could prove that the above bounds
659 * check was always true if it was legal, and remove it!
660 *
661 * uintptr_t because even on a machine with signed
662 * pointers, objects do not cross zero; whereas on
663 * machines with unsigned pointers, they may cross
664 * 0x8bazillion.
665 */
666 return NULL;
667
668 /* see comment near libxl__ev_watch_slot definition */
669 return (void*)slotcontents;
670 }
671
libxl__set_watch_slot_contents(libxl__ev_watch_slot * slot,libxl__ev_xswatch * w)672 static void libxl__set_watch_slot_contents(libxl__ev_watch_slot *slot,
673 libxl__ev_xswatch *w)
674 {
675 /* we look a bit behind the curtain of LIBXL_SLIST, to explicitly
676 * assign to the pointer that's the next link. See the comment
677 * by the definition of libxl__ev_watch_slot */
678 slot->empty.sle_next = (void*)w;
679 }
680
watchfd_callback(libxl__egc * egc,libxl__ev_fd * ev,int fd,short events,short revents)681 static void watchfd_callback(libxl__egc *egc, libxl__ev_fd *ev,
682 int fd, short events, short revents)
683 {
684 EGC_GC;
685
686 if (revents & (POLLERR|POLLHUP))
687 LIBXL__EVENT_DISASTER(gc, "unexpected poll event on watch fd", 0, 0);
688
689 for (;;) {
690 char **event = xs_check_watch(CTX->xsh);
691 if (!event) {
692 if (errno == EAGAIN) break;
693 if (errno == EINTR) continue;
694 LIBXL__EVENT_DISASTER(gc, "cannot check/read watches", errno, 0);
695 return;
696 }
697
698 const char *epath = event[0];
699 const char *token = event[1];
700 int slotnum;
701 uint32_t counterval;
702 int rc = sscanf(token, "%d/%"SCNx32, &slotnum, &counterval);
703 if (rc != 2) {
704 LOG(ERROR, "watch epath=%s token=%s: failed to parse token",
705 epath, token);
706 /* oh well */
707 goto ignore;
708 }
709 if (slotnum < 0 || slotnum >= CTX->watch_nslots) {
710 /* perhaps in the future we will make the watchslots array shrink */
711 LIBXL__LOG(CTX, LIBXL__LOG_DEBUG, "watch epath=%s token=%s:"
712 " slotnum %d out of range [0,%d>",
713 epath, token, slotnum, CTX->watch_nslots);
714 goto ignore;
715 }
716
717 libxl__ev_xswatch *w = libxl__watch_slot_contents(gc, slotnum);
718
719 if (!w) {
720 LOG(DEBUG, "watch epath=%s token=%s: empty slot", epath, token);
721 goto ignore;
722 }
723
724 if (w->counterval != counterval) {
725 LOG(DEBUG, "watch w=%p epath=%s token=%s: counter != %"PRIx32,
726 w, epath, token, w->counterval);
727 goto ignore;
728 }
729
730 /* Now it's possible, though unlikely, that this was an event
731 * from a previous use of the same slot with the same counterval.
732 *
733 * In that case either:
734 * - the event path is a child of the watch path, in
735 * which case this watch would really have generated this
736 * event if it had been registered soon enough and we are
737 * OK to give this possibly-spurious event to the caller; or
738 * - it is not, in which case we must suppress it as the
739 * caller should not see events for unrelated paths.
740 *
741 * See also docs/misc/xenstore.txt.
742 */
743 if (!xs_path_is_subpath(w->path, epath)) {
744 LOG(DEBUG, "watch w=%p wpath=%s token=%s: unexpected epath=%s",
745 w, w->path, token, epath);
746 goto ignore;
747 }
748
749 /* At last, we have checked everything! */
750 LOG(DEBUG, "watch w=%p wpath=%s token=%s: event epath=%s",
751 w, w->path, token, epath);
752 w->callback(egc, w, w->path, epath);
753
754 ignore:
755 free(event);
756 }
757 }
758
watch_token(libxl__gc * gc,int slotnum,uint32_t counterval)759 static char *watch_token(libxl__gc *gc, int slotnum, uint32_t counterval)
760 {
761 return GCSPRINTF("%d/%"PRIx32, slotnum, counterval);
762 }
763
watches_check_fd_deregister(libxl__gc * gc)764 static void watches_check_fd_deregister(libxl__gc *gc)
765 {
766 assert(CTX->nwatches>=0);
767 if (!CTX->nwatches)
768 libxl__ev_fd_deregister(gc, &CTX->watch_efd);
769 }
770
libxl__ev_xswatch_register(libxl__gc * gc,libxl__ev_xswatch * w,libxl__ev_xswatch_callback * func,const char * path)771 int libxl__ev_xswatch_register(libxl__gc *gc, libxl__ev_xswatch *w,
772 libxl__ev_xswatch_callback *func,
773 const char *path /* copied */)
774 {
775 libxl__ev_watch_slot *use = NULL;
776 char *path_copy = NULL;
777 int rc;
778
779 CTX_LOCK;
780
781 if (!libxl__ev_fd_isregistered(&CTX->watch_efd)) {
782 rc = libxl__ev_fd_register(gc, &CTX->watch_efd, watchfd_callback,
783 xs_fileno(CTX->xsh), POLLIN);
784 if (rc) goto out_rc;
785 }
786
787 if (LIBXL_SLIST_EMPTY(&CTX->watch_freeslots)) {
788 /* Free list is empty so there is not in fact a linked
789 * free list in the array and we can safely realloc it */
790 int newarraysize = (CTX->watch_nslots + 1) << 2;
791 int i;
792 libxl__ev_watch_slot *newarray =
793 libxl__realloc(NOGC,
794 CTX->watch_slots, sizeof(*newarray) * newarraysize);
795 if (!newarray) goto out_nomem;
796 for (i = CTX->watch_nslots; i < newarraysize; i++)
797 LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots,
798 &newarray[i], empty);
799 CTX->watch_slots = newarray;
800 CTX->watch_nslots = newarraysize;
801 }
802 use = LIBXL_SLIST_FIRST(&CTX->watch_freeslots);
803 assert(use);
804 LIBXL_SLIST_REMOVE_HEAD(&CTX->watch_freeslots, empty);
805
806 path_copy = strdup(path);
807 if (!path_copy) goto out_nomem;
808
809 int slotnum = use - CTX->watch_slots;
810 w->counterval = CTX->watch_counter++;
811
812 const char *token = watch_token(gc, slotnum, w->counterval);
813 LOG(DEBUG, "watch w=%p wpath=%s token=%s: register slotnum=%d",
814 w, path, token, slotnum);
815
816 if (!xs_watch(CTX->xsh, path, token)) {
817 LOGEV(ERROR, errno, "create watch for path %s", path);
818 rc = ERROR_FAIL;
819 goto out_rc;
820 }
821
822 w->slotnum = slotnum;
823 w->path = path_copy;
824 w->callback = func;
825 CTX->nwatches++;
826 libxl__set_watch_slot_contents(use, w);
827
828 CTX_UNLOCK;
829 return 0;
830
831 out_nomem:
832 rc = ERROR_NOMEM;
833 out_rc:
834 if (use)
835 LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, use, empty);
836 free(path_copy);
837 watches_check_fd_deregister(gc);
838 CTX_UNLOCK;
839 return rc;
840 }
841
libxl__ev_xswatch_deregister(libxl__gc * gc,libxl__ev_xswatch * w)842 void libxl__ev_xswatch_deregister(libxl__gc *gc, libxl__ev_xswatch *w)
843 {
844 /* it is legal to deregister from within _callback */
845 CTX_LOCK;
846
847 if (w->slotnum >= 0) {
848 const char *token = watch_token(gc, w->slotnum, w->counterval);
849
850 LOG(DEBUG, "watch w=%p wpath=%s token=%s: deregister slotnum=%d",
851 w, w->path, token, w->slotnum);
852
853 if (!xs_unwatch(CTX->xsh, w->path, token))
854 /* Oh well, we will just get watch events forever more
855 * and ignore them. But we should complain to the log. */
856 LOGEV(ERROR, errno, "remove watch for path %s", w->path);
857
858 libxl__ev_watch_slot *slot = &CTX->watch_slots[w->slotnum];
859 LIBXL_SLIST_INSERT_HEAD(&CTX->watch_freeslots, slot, empty);
860 w->slotnum = -1;
861 CTX->nwatches--;
862 watches_check_fd_deregister(gc);
863 } else {
864 LOG(DEBUG, "watch w=%p: deregister unregistered", w);
865 }
866
867 free(w->path);
868 w->path = NULL;
869
870 CTX_UNLOCK;
871 }
872
873 /*
874 * evtchn
875 */
876
evtchn_revents_check(libxl__egc * egc,int revents)877 static int evtchn_revents_check(libxl__egc *egc, int revents)
878 {
879 EGC_GC;
880
881 if (revents & ~POLLIN) {
882 LOG(ERROR, "unexpected poll event on event channel fd: %x", revents);
883 LIBXL__EVENT_DISASTER(gc,
884 "unexpected poll event on event channel fd", 0, 0);
885 libxl__ev_fd_deregister(gc, &CTX->evtchn_efd);
886 return ERROR_FAIL;
887 }
888
889 assert(revents & POLLIN);
890
891 return 0;
892 }
893
evtchn_fd_callback(libxl__egc * egc,libxl__ev_fd * ev,int fd,short events,short revents)894 static void evtchn_fd_callback(libxl__egc *egc, libxl__ev_fd *ev,
895 int fd, short events, short revents)
896 {
897 EGC_GC;
898 libxl__ev_evtchn *evev;
899 int rc;
900 xenevtchn_port_or_error_t port;
901
902 rc = evtchn_revents_check(egc, revents);
903 if (rc) return;
904
905 for (;;) {
906 /* Check the fd again. The incoming revent may no longer be
907 * true, because the libxl ctx lock has not necessarily been
908 * held continuously since someone noticed the fd. Normally
909 * this wouldn't be a problem but evtchn devices don't always
910 * honour O_NONBLOCK (see xenctrl.h). */
911 revents = libxl__fd_poll_recheck(egc,fd,POLLIN);
912 if (!revents)
913 break;
914 rc = evtchn_revents_check(egc, revents);
915 if (rc) return;
916
917 /* OK, that's that workaround done. We can actually check for
918 * work for us to do: */
919
920 port = xenevtchn_pending(CTX->xce);
921 if (port < 0) {
922 if (errno == EAGAIN)
923 break;
924 LIBXL__EVENT_DISASTER(gc,
925 "unexpected failure fetching occurring event port number from evtchn",
926 errno, 0);
927 return;
928 }
929
930 LIBXL_LIST_FOREACH(evev, &CTX->evtchns_waiting, entry)
931 if (port == evev->port)
932 goto found;
933 /* not found */
934 DBG("ev_evtchn port=%d no-one cared", port);
935 continue;
936
937 found:
938 DBG("ev_evtchn=%p port=%d signaled", evev, port);
939 evev->waiting = 0;
940 LIBXL_LIST_REMOVE(evev, entry);
941 evev->callback(egc, evev);
942 }
943 }
944
libxl__ctx_evtchn_init(libxl__gc * gc)945 int libxl__ctx_evtchn_init(libxl__gc *gc) {
946 xenevtchn_handle *xce;
947 int rc, fd;
948
949 if (CTX->xce)
950 return 0;
951
952 xce = xenevtchn_open(CTX->lg, 0);
953 if (!xce) {
954 LOGE(ERROR,"cannot open libxc evtchn handle");
955 rc = ERROR_FAIL;
956 goto out;
957 }
958
959 fd = xenevtchn_fd(xce);
960 assert(fd >= 0);
961
962 rc = libxl_fd_set_nonblock(CTX, fd, 1);
963 if (rc) goto out;
964
965 CTX->xce = xce;
966 return 0;
967
968 out:
969 xenevtchn_close(xce);
970 return rc;
971 }
972
evtchn_check_fd_deregister(libxl__gc * gc)973 static void evtchn_check_fd_deregister(libxl__gc *gc)
974 {
975 if (CTX->xce && LIBXL_LIST_EMPTY(&CTX->evtchns_waiting))
976 libxl__ev_fd_deregister(gc, &CTX->evtchn_efd);
977 }
978
libxl__ev_evtchn_wait(libxl__gc * gc,libxl__ev_evtchn * evev)979 int libxl__ev_evtchn_wait(libxl__gc *gc, libxl__ev_evtchn *evev)
980 {
981 int r, rc;
982
983 DBG("ev_evtchn=%p port=%d wait (was waiting=%d)",
984 evev, evev->port, evev->waiting);
985
986 rc = libxl__ctx_evtchn_init(gc);
987 if (rc) goto out;
988
989 if (!libxl__ev_fd_isregistered(&CTX->evtchn_efd)) {
990 rc = libxl__ev_fd_register(gc, &CTX->evtchn_efd, evtchn_fd_callback,
991 xenevtchn_fd(CTX->xce), POLLIN);
992 if (rc) goto out;
993 }
994
995 if (evev->waiting)
996 return 0;
997
998 r = xenevtchn_unmask(CTX->xce, evev->port);
999 if (r) {
1000 LOGE(ERROR,"cannot unmask event channel %d",evev->port);
1001 rc = ERROR_FAIL;
1002 goto out;
1003 }
1004
1005 evev->waiting = 1;
1006 LIBXL_LIST_INSERT_HEAD(&CTX->evtchns_waiting, evev, entry);
1007 return 0;
1008
1009 out:
1010 evtchn_check_fd_deregister(gc);
1011 return rc;
1012 }
1013
libxl__ev_evtchn_cancel(libxl__gc * gc,libxl__ev_evtchn * evev)1014 void libxl__ev_evtchn_cancel(libxl__gc *gc, libxl__ev_evtchn *evev)
1015 {
1016 DBG("ev_evtchn=%p port=%d cancel (was waiting=%d)",
1017 evev, evev->port, evev->waiting);
1018
1019 if (!evev->waiting)
1020 return;
1021
1022 evev->waiting = 0;
1023 LIBXL_LIST_REMOVE(evev, entry);
1024 evtchn_check_fd_deregister(gc);
1025 }
1026
1027 /*
1028 * waiting for device state
1029 */
1030
devstate_callback(libxl__egc * egc,libxl__xswait_state * xsw,int rc,const char * sstate)1031 static void devstate_callback(libxl__egc *egc, libxl__xswait_state *xsw,
1032 int rc, const char *sstate)
1033 {
1034 EGC_GC;
1035 libxl__ev_devstate *ds = CONTAINER_OF(xsw, *ds, w);
1036
1037 if (rc) {
1038 if (rc == ERROR_TIMEDOUT)
1039 LOG(DEBUG, "backend %s wanted state %d "" timed out", ds->w.path,
1040 ds->wanted);
1041 goto out;
1042 }
1043 if (!sstate) {
1044 LOG(DEBUG, "backend %s wanted state %d"" but it was removed",
1045 ds->w.path, ds->wanted);
1046 rc = ERROR_INVAL;
1047 goto out;
1048 }
1049
1050 int got = atoi(sstate);
1051 if (got == ds->wanted) {
1052 LOG(DEBUG, "backend %s wanted state %d ok", ds->w.path, ds->wanted);
1053 rc = 0;
1054 } else {
1055 LOG(DEBUG, "backend %s wanted state %d"" still waiting state %d",
1056 ds->w.path, ds->wanted, got);
1057 return;
1058 }
1059
1060 out:
1061 libxl__ev_devstate_cancel(gc, ds);
1062 ds->callback(egc, ds, rc);
1063 }
1064
libxl__ev_devstate_wait(libxl__ao * ao,libxl__ev_devstate * ds,libxl__ev_devstate_callback cb,const char * state_path,int state,int milliseconds)1065 int libxl__ev_devstate_wait(libxl__ao *ao, libxl__ev_devstate *ds,
1066 libxl__ev_devstate_callback cb,
1067 const char *state_path, int state, int milliseconds)
1068 {
1069 AO_GC;
1070 int rc;
1071
1072 libxl__xswait_init(&ds->w);
1073 ds->wanted = state;
1074 ds->callback = cb;
1075
1076 ds->w.ao = ao;
1077 ds->w.what = GCSPRINTF("backend %s (hoping for state change to %d)",
1078 state_path, state);
1079 ds->w.path = state_path;
1080 ds->w.timeout_ms = milliseconds;
1081 ds->w.callback = devstate_callback;
1082 rc = libxl__xswait_start(gc, &ds->w);
1083 if (rc) goto out;
1084
1085 return 0;
1086
1087 out:
1088 libxl__ev_devstate_cancel(gc, ds);
1089 return rc;
1090 }
1091
1092 /*
1093 * immediate non-reentrant callback
1094 */
1095
libxl__ev_immediate_register(libxl__egc * egc,libxl__ev_immediate * ei)1096 void libxl__ev_immediate_register(libxl__egc *egc, libxl__ev_immediate *ei)
1097 {
1098 LIBXL_STAILQ_INSERT_TAIL(&egc->ev_immediates, ei, entry);
1099 }
1100
1101 /*
1102 * domain death/destruction
1103 */
1104
1105 /*
1106 * We use a xenstore watch on the domain's path, rather than using an
1107 * @releaseDomain watch and asking the hypervisor. This is simpler
1108 * because turning @releaseDomain into domain-specific information is
1109 * complicated.
1110 *
1111 * It is also sufficient for our callers, which are generally trying
1112 * to do cleanup of their own execution state on domain death, for the
1113 * following reason: if the domain is destroyed then either (a) the
1114 * entries in xenstore have already been deleted, in which case the
1115 * test here works or (b) they have not in which case something has
1116 * gone very badly wrong and we are going to leak those xenstore
1117 * entries, in which case trying to avoid leaking other stuff is
1118 * futile.
1119 */
1120
libxl__domaindeathcheck_init(libxl__domaindeathcheck * dc)1121 void libxl__domaindeathcheck_init(libxl__domaindeathcheck *dc)
1122 {
1123 libxl__ao_abortable_init(&dc->abrt);
1124 libxl__ev_xswatch_init(&dc->watch);
1125 }
1126
libxl__domaindeathcheck_stop(libxl__gc * gc,libxl__domaindeathcheck * dc)1127 void libxl__domaindeathcheck_stop(libxl__gc *gc, libxl__domaindeathcheck *dc)
1128 {
1129 libxl__ao_abortable_deregister(&dc->abrt);
1130 libxl__ev_xswatch_deregister(gc,&dc->watch);
1131 }
1132
domaindeathcheck_callback(libxl__egc * egc,libxl__ev_xswatch * w,const char * watch_path,const char * event_path)1133 static void domaindeathcheck_callback(libxl__egc *egc, libxl__ev_xswatch *w,
1134 const char *watch_path, const char *event_path)
1135 {
1136 libxl__domaindeathcheck *dc = CONTAINER_OF(w, *dc, watch);
1137 EGC_GC;
1138 const char *p = libxl__xs_read(gc, XBT_NULL, watch_path);
1139 if (p) return;
1140
1141 libxl__domaindeathcheck_stop(gc,dc);
1142
1143 if (errno!=ENOENT) {
1144 LIBXL__EVENT_DISASTER(gc,"failed to read xenstore"
1145 " for domain detach check", errno, 0);
1146 return;
1147 }
1148
1149 LOG(ERROR,"%s: domain %"PRIu32" removed (%s no longer in xenstore)",
1150 dc->what, dc->domid, watch_path);
1151 dc->callback(egc, dc, ERROR_DOMAIN_DESTROYED);
1152 }
1153
domaindeathcheck_abort(libxl__egc * egc,libxl__ao_abortable * abrt,int rc)1154 static void domaindeathcheck_abort(libxl__egc *egc,
1155 libxl__ao_abortable *abrt,
1156 int rc)
1157 {
1158 libxl__domaindeathcheck *dc = CONTAINER_OF(abrt, *dc, abrt);
1159 EGC_GC;
1160
1161 libxl__domaindeathcheck_stop(gc,dc);
1162 dc->callback(egc, dc, rc);
1163 }
1164
libxl__domaindeathcheck_start(libxl__ao * ao,libxl__domaindeathcheck * dc)1165 int libxl__domaindeathcheck_start(libxl__ao *ao,
1166 libxl__domaindeathcheck *dc)
1167 {
1168 AO_GC;
1169 int rc;
1170 const char *path = GCSPRINTF("/local/domain/%"PRIu32, dc->domid);
1171
1172 libxl__domaindeathcheck_init(dc);
1173
1174 dc->abrt.ao = ao;
1175 dc->abrt.callback = domaindeathcheck_abort;
1176 rc = libxl__ao_abortable_register(&dc->abrt);
1177 if (rc) goto out;
1178
1179 rc = libxl__ev_xswatch_register(gc, &dc->watch,
1180 domaindeathcheck_callback, path);
1181 if (rc) goto out;
1182
1183 return 0;
1184
1185 out:
1186 libxl__domaindeathcheck_stop(gc,dc);
1187 return rc;
1188 }
1189
1190 /*
1191 * osevent poll
1192 */
1193
beforepoll_internal(libxl__gc * gc,libxl__poller * poller,int * nfds_io,struct pollfd * fds,int * timeout_upd,struct timeval now)1194 static int beforepoll_internal(libxl__gc *gc, libxl__poller *poller,
1195 int *nfds_io, struct pollfd *fds,
1196 int *timeout_upd, struct timeval now)
1197 {
1198 libxl__ev_fd *efd;
1199 int rc;
1200
1201 /*
1202 * We need to look at the fds we want twice: firstly, to count
1203 * them so we can make the rindex array big enough, and secondly
1204 * to actually fill the arrays in.
1205 *
1206 * To ensure correctness and avoid repeating the logic for
1207 * deciding which fds are relevant, we define a macro
1208 * REQUIRE_FDS( BODY )
1209 * which calls
1210 * do{
1211 * int req_fd;
1212 * int req_events;
1213 * BODY;
1214 * }while(0)
1215 * for each fd with a nonzero events. This is invoked twice.
1216 *
1217 * The definition of REQUIRE_FDS is simplified with the helper
1218 * macro
1219 * void REQUIRE_FD(int req_fd, int req_events, BODY);
1220 */
1221
1222 #define REQUIRE_FDS(BODY) do{ \
1223 \
1224 LIBXL_LIST_FOREACH(efd, &CTX->efds, entry) \
1225 REQUIRE_FD(efd->fd, efd->events, BODY); \
1226 \
1227 REQUIRE_FD(poller->wakeup_pipe[0], POLLIN, BODY); \
1228 \
1229 }while(0)
1230
1231 #define REQUIRE_FD(req_fd_, req_events_, BODY) do{ \
1232 int req_events = (req_events_); \
1233 int req_fd = (req_fd_); \
1234 if (req_events) { \
1235 BODY; \
1236 } \
1237 }while(0)
1238
1239
1240 /*
1241 * In order to be able to efficiently find the libxl__ev_fd for a
1242 * struct poll during _afterpoll, we maintain a shadow data
1243 * structure in CTX->fd_rindices: each fd corresponds to a slot in
1244 * fd_rindices, and each element in the rindices is three indices
1245 * into the fd array (for POLLIN, POLLPRI and POLLOUT).
1246 */
1247
1248 if (*nfds_io) {
1249 /*
1250 * As an optimisation, we don't touch fd_rindex
1251 * if *nfds_io is zero on entry, since in that case the
1252 * caller just wanted to know how big an array to give us.
1253 *
1254 * If !*nfds_io, the unconditional parts below are guaranteed
1255 * not to mess with fd_rindex.
1256 */
1257
1258 int maxfd = 0;
1259
1260 REQUIRE_FDS({
1261 if (req_fd >= maxfd)
1262 maxfd = req_fd + 1;
1263 });
1264
1265 /* make sure our array is as big as *nfds_io */
1266 if (poller->fd_rindices_allocd < maxfd) {
1267 assert(ARRAY_SIZE_OK(poller->fd_rindices, maxfd));
1268 poller->fd_rindices =
1269 libxl__realloc(NOGC, poller->fd_rindices,
1270 maxfd * sizeof(*poller->fd_rindices));
1271 memset(poller->fd_rindices + poller->fd_rindices_allocd,
1272 0,
1273 (maxfd - poller->fd_rindices_allocd)
1274 * sizeof(*poller->fd_rindices));
1275 poller->fd_rindices_allocd = maxfd;
1276 }
1277 }
1278
1279 int used = 0;
1280
1281 REQUIRE_FDS({
1282 if (used < *nfds_io) {
1283 fds[used].fd = req_fd;
1284 fds[used].events = req_events;
1285 fds[used].revents = 0;
1286 assert(req_fd < poller->fd_rindices_allocd);
1287 if (req_events & POLLIN) poller->fd_rindices[req_fd][0] = used;
1288 if (req_events & POLLPRI) poller->fd_rindices[req_fd][1] = used;
1289 if (req_events & POLLOUT) poller->fd_rindices[req_fd][2] = used;
1290 }
1291 used++;
1292 });
1293
1294 rc = used <= *nfds_io ? 0 : ERROR_BUFFERFULL;
1295
1296 *nfds_io = used;
1297
1298 poller->fds_deregistered = 0;
1299 poller->osevents_added = 0;
1300
1301 libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes);
1302 if (etime) {
1303 int our_timeout;
1304 struct timeval rel;
1305 static struct timeval zero;
1306
1307 timersub(&etime->abs, &now, &rel);
1308
1309 if (timercmp(&rel, &zero, <)) {
1310 our_timeout = 0;
1311 } else if (rel.tv_sec >= 2000000) {
1312 our_timeout = 2000000000;
1313 } else {
1314 our_timeout = rel.tv_sec * 1000 + (rel.tv_usec + 999) / 1000;
1315 }
1316 if (*timeout_upd < 0 || our_timeout < *timeout_upd)
1317 *timeout_upd = our_timeout;
1318 }
1319
1320 return rc;
1321 }
1322
libxl_osevent_beforepoll(libxl_ctx * ctx,int * nfds_io,struct pollfd * fds,int * timeout_upd,struct timeval now)1323 int libxl_osevent_beforepoll(libxl_ctx *ctx, int *nfds_io,
1324 struct pollfd *fds, int *timeout_upd,
1325 struct timeval now)
1326 {
1327 EGC_INIT(ctx);
1328 CTX_LOCK;
1329 int rc = beforepoll_internal(gc, ctx->poller_app,
1330 nfds_io, fds, timeout_upd, now);
1331 CTX_UNLOCK_EGC_FREE;
1332 return rc;
1333 }
1334
afterpoll_check_fd(libxl__poller * poller,const struct pollfd * fds,int nfds,int fd,int events)1335 static int afterpoll_check_fd(libxl__poller *poller,
1336 const struct pollfd *fds, int nfds,
1337 int fd, int events)
1338 /* Returns mask of events which were requested and occurred. Will
1339 * return nonzero only once for each (poller,fd,events)
1340 * combination, until the next beforepoll. If events from
1341 * different combinations overlap, between one such combination
1342 * and all distinct combinations will produce nonzero returns. */
1343 {
1344 if (fd >= poller->fd_rindices_allocd)
1345 /* added after we went into poll, have to try again */
1346 return 0;
1347
1348 events |= POLLERR | POLLHUP;
1349
1350 int i, revents = 0;
1351 for (i=0; i<3; i++) {
1352 int *slotp = &poller->fd_rindices[fd][i];
1353 int slot = *slotp;
1354
1355 if (slot >= nfds)
1356 /* stale slot entry (again, added afterwards), */
1357 /* or slot for which we have already returned nonzero */
1358 continue;
1359
1360 if (fds[slot].fd != fd)
1361 /* again, stale slot entry */
1362 continue;
1363
1364 assert(poller->fds_deregistered || !(fds[slot].revents & POLLNVAL));
1365
1366 /* we mask in case requested events have changed */
1367 int slot_revents = fds[slot].revents & events;
1368 if (!slot_revents)
1369 /* this slot is for a different set of events */
1370 continue;
1371
1372 revents |= slot_revents;
1373 *slotp = INT_MAX; /* so that next time we'll see slot >= nfds */
1374 }
1375
1376 return revents;
1377 }
1378
fd_occurs(libxl__egc * egc,libxl__ev_fd * efd,short revents_ign)1379 static void fd_occurs(libxl__egc *egc, libxl__ev_fd *efd, short revents_ign)
1380 {
1381 short revents_current = libxl__fd_poll_recheck(egc, efd->fd, efd->events);
1382 EGC_GC;
1383
1384 DBG("ev_fd=%p occurs fd=%d events=%x revents_ign=%x revents_current=%x",
1385 efd, efd->fd, efd->events, revents_ign, revents_current);
1386
1387 if (revents_current)
1388 efd->func(egc, efd, efd->fd, efd->events, revents_current);
1389 }
1390
afterpoll_internal(libxl__egc * egc,libxl__poller * poller,int nfds,const struct pollfd * fds,struct timeval now)1391 static void afterpoll_internal(libxl__egc *egc, libxl__poller *poller,
1392 int nfds, const struct pollfd *fds,
1393 struct timeval now)
1394 {
1395 /* May make callbacks into the application for child processes.
1396 * ctx must be locked exactly once */
1397 EGC_GC;
1398 libxl__ev_fd *efd;
1399
1400 /*
1401 * Warning! Reentrancy hazards!
1402 *
1403 * Many parts of this function eventually call arbitrary callback
1404 * functions which may modify the event handling data structures.
1405 *
1406 * Of the data structures used here:
1407 *
1408 * egc, poller, now
1409 * are allocated by our caller and relate to the
1410 * current thread and its call stack down into the
1411 * event machinery; it is not freed until we return.
1412 * So it is safe.
1413 *
1414 * fds is either what application passed into
1415 * libxl_osevent_afterpoll (which, although this
1416 * isn't explicitly stated, clearly must remain
1417 * valid until libxl_osevent_afterpoll returns) or
1418 * it's poller->fd_polls which is modified only by
1419 * our (non-recursive) caller eventloop_iteration.
1420 *
1421 * CTX comes from our caller, and applications are
1422 * forbidden from destroying it while we are running.
1423 * So the ctx pointer itself is safe to use; now
1424 * for its contents:
1425 *
1426 * CTX->etimes is used in a simple reentrancy-safe manner.
1427 *
1428 * CTX->efds is more complicated; see below.
1429 */
1430
1431 for (;;) {
1432 /* We restart our scan of fd events whenever we call a
1433 * callback function. This is necessary because such
1434 * a callback might make arbitrary changes to CTX->efds.
1435 * We invalidate the fd_rindices[] entries which were used
1436 * so that we don't call the same function again. */
1437 int revents;
1438
1439 LIBXL_LIST_FOREACH(efd, &CTX->efds, entry) {
1440
1441 if (!efd->events)
1442 continue;
1443
1444 revents = afterpoll_check_fd(poller,fds,nfds,
1445 efd->fd,efd->events);
1446 if (revents)
1447 goto found_fd_event;
1448 }
1449 /* no ordinary fd events, then */
1450 break;
1451
1452 found_fd_event:
1453 fd_occurs(egc, efd, revents);
1454 }
1455
1456 for (;;) {
1457 libxl__ev_time *etime = LIBXL_TAILQ_FIRST(&CTX->etimes);
1458 if (!etime)
1459 break;
1460
1461 assert(!etime->infinite);
1462
1463 if (timercmp(&etime->abs, &now, >))
1464 break;
1465
1466 time_deregister(gc, etime);
1467
1468 time_occurs(egc, etime, ERROR_TIMEDOUT);
1469 }
1470
1471 if (afterpoll_check_fd(poller,fds,nfds, poller->wakeup_pipe[0],POLLIN)) {
1472 poller->pipe_nonempty = 0;
1473 int e = libxl__self_pipe_eatall(poller->wakeup_pipe[0]);
1474 if (e) LIBXL__EVENT_DISASTER(gc, "read wakeup", e, 0);
1475 }
1476 }
1477
libxl_osevent_afterpoll(libxl_ctx * ctx,int nfds,const struct pollfd * fds,struct timeval now)1478 void libxl_osevent_afterpoll(libxl_ctx *ctx, int nfds, const struct pollfd *fds,
1479 struct timeval now)
1480 {
1481 EGC_INIT(ctx);
1482 CTX_LOCK;
1483 afterpoll_internal(egc, ctx->poller_app, nfds, fds, now);
1484 CTX_UNLOCK_EGC_FREE;
1485 }
1486
1487 /*
1488 * osevent hook and callback machinery
1489 */
1490
libxl_osevent_register_hooks(libxl_ctx * ctx,const libxl_osevent_hooks * hooks,void * user)1491 void libxl_osevent_register_hooks(libxl_ctx *ctx,
1492 const libxl_osevent_hooks *hooks,
1493 void *user)
1494 {
1495 GC_INIT(ctx);
1496 CTX_LOCK;
1497 assert(LIBXL_LIST_EMPTY(&ctx->efds));
1498 assert(LIBXL_TAILQ_EMPTY(&ctx->etimes));
1499 ctx->osevent_hooks = hooks;
1500 ctx->osevent_user = user;
1501 CTX_UNLOCK;
1502 GC_FREE;
1503 }
1504
1505
libxl_osevent_occurred_fd(libxl_ctx * ctx,void * for_libxl,int fd,short events_ign,short revents_ign)1506 void libxl_osevent_occurred_fd(libxl_ctx *ctx, void *for_libxl,
1507 int fd, short events_ign, short revents_ign)
1508 {
1509 EGC_INIT(ctx);
1510 CTX_LOCK;
1511 assert(!CTX->osevent_in_hook);
1512
1513 libxl__ev_fd *ev = osevent_ev_from_hook_nexus(ctx, for_libxl);
1514 if (!ev) goto out;
1515 if (ev->fd != fd) goto out;
1516
1517 fd_occurs(egc, ev, revents_ign);
1518
1519 out:
1520 CTX_UNLOCK_EGC_FREE;
1521 }
1522
libxl_osevent_occurred_timeout(libxl_ctx * ctx,void * for_libxl)1523 void libxl_osevent_occurred_timeout(libxl_ctx *ctx, void *for_libxl)
1524 {
1525 EGC_INIT(ctx);
1526 CTX_LOCK;
1527 assert(!CTX->osevent_in_hook);
1528
1529 libxl__osevent_hook_nexus *nexus = for_libxl;
1530 libxl__ev_time *ev = osevent_ev_from_hook_nexus(ctx, nexus);
1531
1532 osevent_release_nexus(gc, &CTX->hook_timeout_nexi_idle, nexus);
1533
1534 if (!ev) goto out;
1535 assert(!ev->infinite);
1536
1537 LIBXL_TAILQ_REMOVE(&CTX->etimes, ev, entry);
1538
1539 time_occurs(egc, ev, ERROR_TIMEDOUT);
1540
1541 out:
1542 CTX_UNLOCK_EGC_FREE;
1543 }
1544
libxl__event_disaster(libxl__gc * gc,const char * msg,int errnoval,libxl_event_type type,const char * file,int line,const char * func)1545 void libxl__event_disaster(libxl__gc *gc, const char *msg, int errnoval,
1546 libxl_event_type type /* may be 0 */,
1547 const char *file, int line, const char *func)
1548 {
1549 libxl__log(CTX, XTL_CRITICAL, errnoval, file, line, func, INVALID_DOMID,
1550 "DISASTER in event loop: %s%s%s%s",
1551 msg,
1552 type ? " (relates to event type " : "",
1553 type ? libxl_event_type_to_string(type) : "",
1554 type ? ")" : "");
1555
1556 if (CTX->event_hooks && CTX->event_hooks->disaster) {
1557 CTX->event_hooks->disaster(CTX->event_hooks_user, type, msg, errnoval);
1558 return;
1559 }
1560
1561 const char verybad[] =
1562 "DISASTER in event loop not handled by libxl application";
1563 LIBXL__LOG(CTX, XTL_CRITICAL, verybad);
1564 fprintf(stderr, "libxl: fatal error, exiting program: %s\n", verybad);
1565 exit(-1);
1566 }
1567
egc_run_callbacks(libxl__egc * egc)1568 static void egc_run_callbacks(libxl__egc *egc)
1569 {
1570 /*
1571 * The callbacks must happen with the ctx unlocked. See the
1572 * comment near #define EGC_GC in libxl_internal.h and those in
1573 * the definitions of libxl__egc, libxl__ao and libxl__aop.
1574 */
1575 EGC_GC;
1576 libxl_event *ev, *ev_tmp;
1577 libxl__aop_occurred *aop, *aop_tmp;
1578 libxl__ev_immediate *ei;
1579
1580 while (!LIBXL_STAILQ_EMPTY(&egc->ev_immediates)) {
1581 ei = LIBXL_STAILQ_FIRST(&egc->ev_immediates);
1582 LIBXL_STAILQ_REMOVE_HEAD(&egc->ev_immediates, entry);
1583 CTX_LOCK;
1584 /* This callback is internal to libxl and expects CTX to be
1585 * locked. */
1586 ei->callback(egc, ei);
1587 CTX_UNLOCK;
1588 }
1589
1590 LIBXL_TAILQ_FOREACH_SAFE(ev, &egc->occurred_for_callback, link, ev_tmp) {
1591 LIBXL_TAILQ_REMOVE(&egc->occurred_for_callback, ev, link);
1592 LOG(DEBUG,"event %p callback type=%s",
1593 ev, libxl_event_type_to_string(ev->type));
1594 CTX->event_hooks->event_occurs(CTX->event_hooks_user, ev);
1595 }
1596
1597 LIBXL_TAILQ_FOREACH_SAFE(aop, &egc->aops_for_callback, entry, aop_tmp) {
1598 LIBXL_TAILQ_REMOVE(&egc->aops_for_callback, aop, entry);
1599 LOG(DEBUG,"ao %p: progress report: callback aop=%p", aop->ao, aop);
1600 aop->how->callback(CTX, aop->ev, aop->how->for_callback);
1601
1602 CTX_LOCK;
1603 assert(aop->ao->magic == LIBXL__AO_MAGIC);
1604 aop->ao->progress_reports_outstanding--;
1605 libxl__ao_complete_check_progress_reports(egc, aop->ao);
1606 CTX_UNLOCK;
1607 }
1608
1609 libxl__ao *ao, *ao_tmp;
1610 LIBXL_TAILQ_FOREACH_SAFE(ao, &egc->aos_for_callback,
1611 entry_for_callback, ao_tmp) {
1612 LIBXL_TAILQ_REMOVE(&egc->aos_for_callback, ao, entry_for_callback);
1613 LOG(DEBUG,"ao %p: completion callback", ao);
1614 ao->how.callback(CTX, ao->rc, ao->how.u.for_callback);
1615 CTX_LOCK;
1616 ao->notified = 1;
1617 ao__check_destroy(CTX, ao);
1618 CTX_UNLOCK;
1619 }
1620 }
1621
libxl__egc_cleanup_2_ul_cb_gc(libxl__egc * egc)1622 void libxl__egc_cleanup_2_ul_cb_gc(libxl__egc *egc)
1623 {
1624 EGC_GC;
1625 egc_run_callbacks(egc);
1626
1627 libxl__free_all(gc);
1628 }
1629
1630 /*
1631 * Event retrieval etc.
1632 */
1633
libxl_event_register_callbacks(libxl_ctx * ctx,const libxl_event_hooks * hooks,void * user)1634 void libxl_event_register_callbacks(libxl_ctx *ctx,
1635 const libxl_event_hooks *hooks, void *user)
1636 {
1637 ctx->event_hooks = hooks;
1638 ctx->event_hooks_user = user;
1639 }
1640
libxl__event_occurred(libxl__egc * egc,libxl_event * event)1641 void libxl__event_occurred(libxl__egc *egc, libxl_event *event)
1642 {
1643 EGC_GC;
1644
1645 if (CTX->event_hooks &&
1646 (CTX->event_hooks->event_occurs_mask & (1UL << event->type))) {
1647 /* libxl__egc_cleanup will call the callback, just before exit
1648 * from libxl. This helps avoid reentrancy bugs: parts of
1649 * libxl that call libxl__event_occurred do not have to worry
1650 * that libxl might be reentered at that point. */
1651 LIBXL_TAILQ_INSERT_TAIL(&egc->occurred_for_callback, event, link);
1652 return;
1653 } else {
1654 libxl__poller *poller;
1655 LIBXL_TAILQ_INSERT_TAIL(&CTX->occurred, event, link);
1656 LIBXL_LIST_FOREACH(poller, &CTX->pollers_event, entry)
1657 libxl__poller_wakeup(gc, poller);
1658 }
1659 }
1660
libxl_event_free(libxl_ctx * ctx,libxl_event * event)1661 void libxl_event_free(libxl_ctx *ctx, libxl_event *event)
1662 {
1663 /* Exceptionally, this function may be called from libxl, with ctx==0 */
1664 libxl_event_dispose(event);
1665 free(event);
1666 }
1667
libxl__event_new(libxl__egc * egc,libxl_event_type type,uint32_t domid,libxl_ev_user for_user)1668 libxl_event *libxl__event_new(libxl__egc *egc,
1669 libxl_event_type type, uint32_t domid,
1670 libxl_ev_user for_user)
1671 {
1672 EGC_GC;
1673 libxl_event *ev;
1674
1675 ev = libxl__zalloc(NOGC,sizeof(*ev));
1676
1677 libxl_event_init(ev);
1678 libxl_event_init_type(ev, type);
1679
1680 ev->domid = domid;
1681 ev->for_user = for_user;
1682
1683 return ev;
1684 }
1685
event_check_internal(libxl__egc * egc,libxl_event ** event_r,unsigned long typemask,libxl_event_predicate * pred,void * pred_user)1686 static int event_check_internal(libxl__egc *egc, libxl_event **event_r,
1687 unsigned long typemask,
1688 libxl_event_predicate *pred, void *pred_user)
1689 {
1690 EGC_GC;
1691 libxl_event *ev;
1692 int rc;
1693
1694 LIBXL_TAILQ_FOREACH(ev, &CTX->occurred, link) {
1695 if (!(typemask & ((uint64_t)1 << ev->type)))
1696 continue;
1697
1698 if (pred && !pred(ev, pred_user))
1699 continue;
1700
1701 /* got one! */
1702 LIBXL_TAILQ_REMOVE(&CTX->occurred, ev, link);
1703 *event_r = ev;
1704 rc = 0;
1705 goto out;
1706 }
1707 rc = ERROR_NOT_READY;
1708
1709 out:
1710 return rc;
1711 }
1712
libxl_event_check(libxl_ctx * ctx,libxl_event ** event_r,uint64_t typemask,libxl_event_predicate * pred,void * pred_user)1713 int libxl_event_check(libxl_ctx *ctx, libxl_event **event_r,
1714 uint64_t typemask,
1715 libxl_event_predicate *pred, void *pred_user)
1716 {
1717 EGC_INIT(ctx);
1718 CTX_LOCK;
1719 int rc = event_check_internal(egc, event_r, typemask, pred, pred_user);
1720 CTX_UNLOCK_EGC_FREE;
1721 return rc;
1722 }
1723
1724 /*
1725 * Utilities for pipes (specifically, useful for self-pipes)
1726 */
1727
libxl__pipe_close(int fds[2])1728 void libxl__pipe_close(int fds[2])
1729 {
1730 if (fds[0] >= 0) close(fds[0]);
1731 if (fds[1] >= 0) close(fds[1]);
1732 fds[0] = fds[1] = -1;
1733 }
1734
libxl__pipe_nonblock(libxl_ctx * ctx,int fds[2])1735 int libxl__pipe_nonblock(libxl_ctx *ctx, int fds[2])
1736 {
1737 int r, rc;
1738
1739 r = libxl_pipe(ctx, fds);
1740 if (r) {
1741 fds[0] = fds[1] = -1;
1742 rc = ERROR_FAIL;
1743 goto out;
1744 }
1745
1746 rc = libxl_fd_set_nonblock(ctx, fds[0], 1);
1747 if (rc) goto out;
1748
1749 rc = libxl_fd_set_nonblock(ctx, fds[1], 1);
1750 if (rc) goto out;
1751
1752 return 0;
1753
1754 out:
1755 libxl__pipe_close(fds);
1756 return rc;
1757 }
1758
libxl__self_pipe_wakeup(int fd)1759 int libxl__self_pipe_wakeup(int fd)
1760 {
1761 /* Called from signal handlers, so needs to be async-signal-safe */
1762 static const char buf[1] = "";
1763
1764 for (;;) {
1765 int r = write(fd, buf, 1);
1766 if (r==1) return 0;
1767 assert(r==-1);
1768 if (errno == EINTR) continue;
1769 if (errno == EWOULDBLOCK) return 0;
1770 if (!errno) abort();
1771 return errno;
1772 }
1773 }
1774
libxl__self_pipe_eatall(int fd)1775 int libxl__self_pipe_eatall(int fd)
1776 {
1777 char buf[256];
1778 for (;;) {
1779 int r = read(fd, buf, sizeof(buf));
1780 if (r == sizeof(buf)) continue;
1781 if (r >= 0) return 0;
1782 assert(r == -1);
1783 if (errno == EINTR) continue;
1784 if (errno == EWOULDBLOCK) return 0;
1785 assert(errno);
1786 return errno;
1787 }
1788 }
1789
1790 /*
1791 * Manipulation of pollers
1792 */
1793
libxl__poller_init(libxl__gc * gc,libxl__poller * p)1794 int libxl__poller_init(libxl__gc *gc, libxl__poller *p)
1795 {
1796 int rc;
1797 p->fd_polls = 0;
1798 p->fd_rindices = 0;
1799 p->fds_deregistered = 0;
1800
1801 rc = libxl__pipe_nonblock(CTX, p->wakeup_pipe);
1802 if (rc) goto out;
1803
1804 return 0;
1805
1806 out:
1807 libxl__poller_dispose(p);
1808 return rc;
1809 }
1810
libxl__poller_dispose(libxl__poller * p)1811 void libxl__poller_dispose(libxl__poller *p)
1812 {
1813 libxl__pipe_close(p->wakeup_pipe);
1814 free(p->fd_polls);
1815 free(p->fd_rindices);
1816 }
1817
libxl__poller_get(libxl__gc * gc)1818 libxl__poller *libxl__poller_get(libxl__gc *gc)
1819 {
1820 /* must be called with ctx locked */
1821 int rc;
1822
1823 libxl__poller *p = LIBXL_LIST_FIRST(&CTX->pollers_idle);
1824 if (p) {
1825 LIBXL_LIST_REMOVE(p, entry);
1826 } else {
1827 p = libxl__zalloc(NOGC, sizeof(*p));
1828
1829 rc = libxl__poller_init(gc, p);
1830 if (rc) {
1831 free(p);
1832 return NULL;
1833 }
1834 }
1835
1836 LIBXL_LIST_INSERT_HEAD(&CTX->pollers_active, p,
1837 active_entry);
1838 return p;
1839 }
1840
libxl__poller_put(libxl_ctx * ctx,libxl__poller * p)1841 void libxl__poller_put(libxl_ctx *ctx, libxl__poller *p)
1842 {
1843 if (!p) return;
1844 LIBXL_LIST_REMOVE(p, active_entry);
1845 LIBXL_LIST_INSERT_HEAD(&ctx->pollers_idle, p, entry);
1846 }
1847
libxl__poller_wakeup(libxl__gc * gc,libxl__poller * p)1848 void libxl__poller_wakeup(libxl__gc *gc, libxl__poller *p)
1849 {
1850 if (p->pipe_nonempty) return;
1851 p->pipe_nonempty = 1;
1852 int e = libxl__self_pipe_wakeup(p->wakeup_pipe[1]);
1853 if (e) LIBXL__EVENT_DISASTER(gc, "cannot poke watch pipe", e, 0);
1854 }
1855
1856 /*
1857 * Main event loop iteration
1858 */
1859
eventloop_iteration(libxl__egc * egc,libxl__poller * poller)1860 static int eventloop_iteration(libxl__egc *egc, libxl__poller *poller) {
1861 /* The CTX must be locked EXACTLY ONCE so that this function
1862 * can unlock it when it polls.
1863 */
1864 EGC_GC;
1865 int rc, nfds;
1866 struct timeval now;
1867
1868 rc = libxl__gettimeofday(gc, &now);
1869 if (rc) goto out;
1870
1871 int timeout;
1872
1873 for (;;) {
1874 nfds = poller->fd_polls_allocd;
1875 timeout = -1;
1876 rc = beforepoll_internal(gc, poller, &nfds, poller->fd_polls,
1877 &timeout, now);
1878 if (!rc) break;
1879 if (rc != ERROR_BUFFERFULL) goto out;
1880
1881 struct pollfd *newarray =
1882 (nfds > INT_MAX / sizeof(struct pollfd) / 2) ? 0 :
1883 libxl__realloc(NOGC, poller->fd_polls, sizeof(*newarray) * nfds);
1884
1885 if (!newarray) { rc = ERROR_NOMEM; goto out; }
1886
1887 poller->fd_polls = newarray;
1888 poller->fd_polls_allocd = nfds;
1889 }
1890
1891 CTX_UNLOCK;
1892 rc = poll(poller->fd_polls, nfds, timeout);
1893 CTX_LOCK;
1894
1895 if (rc < 0) {
1896 if (errno == EINTR)
1897 return 0; /* will go round again if caller requires */
1898
1899 LOGEV(ERROR, errno, "poll failed");
1900 rc = ERROR_FAIL;
1901 goto out;
1902 }
1903
1904 rc = libxl__gettimeofday(gc, &now);
1905 if (rc) goto out;
1906
1907 afterpoll_internal(egc, poller, nfds, poller->fd_polls, now);
1908
1909 rc = 0;
1910 out:
1911 return rc;
1912 }
1913
libxl_event_wait(libxl_ctx * ctx,libxl_event ** event_r,uint64_t typemask,libxl_event_predicate * pred,void * pred_user)1914 int libxl_event_wait(libxl_ctx *ctx, libxl_event **event_r,
1915 uint64_t typemask,
1916 libxl_event_predicate *pred, void *pred_user)
1917 {
1918 int rc;
1919 libxl__poller *poller = NULL;
1920
1921 EGC_INIT(ctx);
1922 CTX_LOCK;
1923
1924 poller = libxl__poller_get(gc);
1925 if (!poller) { rc = ERROR_FAIL; goto out; }
1926
1927 for (;;) {
1928 rc = event_check_internal(egc, event_r, typemask, pred, pred_user);
1929 if (rc != ERROR_NOT_READY) goto out;
1930
1931 rc = eventloop_iteration(egc, poller);
1932 if (rc) goto out;
1933
1934 /* we unlock and cleanup the egc each time we go through this
1935 * loop, so that (a) we don't accumulate garbage and (b) any
1936 * events which are to be dispatched by callback are actually
1937 * delivered in a timely fashion. _1_baton will be
1938 * called to pass the baton iff we actually leave; otherwise
1939 * we are still carrying it.
1940 */
1941 CTX_UNLOCK;
1942 libxl__egc_cleanup_2_ul_cb_gc(egc);
1943 CTX_LOCK;
1944 }
1945
1946 out:
1947 libxl__poller_put(ctx, poller);
1948
1949 CTX_UNLOCK_EGC_FREE;
1950 return rc;
1951 }
1952
1953
1954
1955 /*
1956 * The two possible state flow of an ao:
1957 *
1958 * Completion before initiator return:
1959 *
1960 * Initiator thread Possible other threads
1961 *
1962 * * ao_create allocates memory and
1963 * initialises the struct
1964 *
1965 * * the initiator function does its
1966 * work, setting up various internal
1967 * asynchronous operations -----------> * asynchronous operations
1968 * start to take place and
1969 * might cause ao completion
1970 * |
1971 * * initiator calls ao_inprogress |
1972 * - if synchronous, run event loop |
1973 * until the ao completes |
1974 * - ao completes on some thread
1975 * - completing thread releases the lock
1976 * <--------------'
1977 * - ao_inprogress takes the lock
1978 * - destroy the ao
1979 *
1980 *
1981 * Completion after initiator return (asynch. only):
1982 *
1983 *
1984 * Initiator thread Possible other threads
1985 *
1986 * * ao_create allocates memory and
1987 * initialises the struct
1988 *
1989 * * the initiator function does its
1990 * work, setting up various internal
1991 * asynchronous operations -----------> * asynchronous operations
1992 * start to take place and
1993 * might cause ao completion
1994 * |
1995 * * initiator calls ao_inprogress |
1996 * - observes event not yet done, |
1997 * - returns to caller |
1998 * |
1999 * - ao completes on some thread
2000 * - generate the event or call the callback
2001 * - destroy the ao
2002 */
2003
2004
2005 /*
2006 * A "manip" is a libxl public function manipulating this ao, which
2007 * has a pointer to it. We have to not destroy it while that's the
2008 * case, obviously. Callers must have the ctx locked, obviously.
2009 */
ao__manip_enter(libxl__ao * ao)2010 static void ao__manip_enter(libxl__ao *ao)
2011 {
2012 assert(ao->manip_refcnt < INT_MAX);
2013 ao->manip_refcnt++;
2014 }
2015
ao__manip_leave(libxl_ctx * ctx,libxl__ao * ao)2016 static void ao__manip_leave(libxl_ctx *ctx, libxl__ao *ao)
2017 {
2018 assert(ao->manip_refcnt > 0);
2019 ao->manip_refcnt--;
2020 ao__check_destroy(ctx, ao);
2021 }
2022
ao__check_destroy(libxl_ctx * ctx,libxl__ao * ao)2023 static void ao__check_destroy(libxl_ctx *ctx, libxl__ao *ao)
2024 {
2025 if (!ao->manip_refcnt && ao->notified) {
2026 assert(ao->complete);
2027 libxl__ao__destroy(ctx, ao);
2028 }
2029 }
2030
libxl__ao__destroy(libxl_ctx * ctx,libxl__ao * ao)2031 void libxl__ao__destroy(libxl_ctx *ctx, libxl__ao *ao)
2032 {
2033 AO_GC;
2034 if (!ao) return;
2035 LOG(DEBUG,"ao %p: destroy",ao);
2036 libxl__poller_put(ctx, ao->poller);
2037 ao->magic = LIBXL__AO_MAGIC_DESTROYED;
2038 libxl__free_all(&ao->gc);
2039 free(ao);
2040 }
2041
libxl__ao_create_fail(libxl__ao * ao)2042 void libxl__ao_create_fail(libxl__ao *ao)
2043 {
2044 AO_GC;
2045 LOG(DEBUG,"ao %p: create fail",ao);
2046 assert(ao->magic == LIBXL__AO_MAGIC);
2047 assert(ao->in_initiator);
2048 assert(!ao->complete);
2049 assert(!ao->progress_reports_outstanding);
2050 assert(!ao->aborting);
2051 LIBXL_LIST_REMOVE(ao, inprogress_entry);
2052 libxl__ao__destroy(CTX, ao);
2053 }
2054
libxl__ao_inprogress_gc(libxl__ao * ao)2055 libxl__gc *libxl__ao_inprogress_gc(libxl__ao *ao)
2056 {
2057 assert(ao);
2058 assert(ao->magic == LIBXL__AO_MAGIC);
2059 assert(!ao->complete);
2060 return &ao->gc;
2061 }
2062
libxl__ao_complete(libxl__egc * egc,libxl__ao * ao,int rc)2063 void libxl__ao_complete(libxl__egc *egc, libxl__ao *ao, int rc)
2064 {
2065 AO_GC;
2066 LOG(DEBUG,"ao %p: complete, rc=%d",ao,rc);
2067 assert(ao->magic == LIBXL__AO_MAGIC);
2068 assert(!ao->complete);
2069 assert(!ao->nested_root);
2070 assert(!ao->nested_progeny);
2071 ao->complete = 1;
2072 ao->rc = rc;
2073 LIBXL_LIST_REMOVE(ao, inprogress_entry);
2074 if (ao->outstanding_killed_child)
2075 LOG(DEBUG, "ao %p: .. but waiting for %d fork to exit",
2076 ao, ao->outstanding_killed_child);
2077 libxl__ao_complete_check_progress_reports(egc, ao);
2078 }
2079
ao_work_outstanding(libxl__ao * ao)2080 static bool ao_work_outstanding(libxl__ao *ao)
2081 {
2082 /*
2083 * We don't consider an ao complete if it has any outstanding
2084 * callbacks. These callbacks might be outstanding on other
2085 * threads, queued up in the other threads' egc's. Those threads
2086 * will, after making the callback, take out the lock again,
2087 * decrement progress_reports_outstanding, and call
2088 * libxl__ao_complete_check_progress_reports.
2089 */
2090 return !ao->complete || ao->progress_reports_outstanding
2091 || ao->outstanding_killed_child;
2092 }
2093
libxl__ao_complete_check_progress_reports(libxl__egc * egc,libxl__ao * ao)2094 void libxl__ao_complete_check_progress_reports(libxl__egc *egc, libxl__ao *ao)
2095 {
2096 EGC_GC;
2097 libxl_ctx *ctx = libxl__gc_owner(&egc->gc);
2098 assert(ao->progress_reports_outstanding >= 0);
2099
2100 if (ao_work_outstanding(ao))
2101 return;
2102
2103 if (ao->poller) {
2104 assert(ao->in_initiator);
2105 if (!ao->constructing)
2106 /* don't bother with this if we're not in the event loop */
2107 libxl__poller_wakeup(gc, ao->poller);
2108 } else if (ao->how.callback) {
2109 LOG(DEBUG, "ao %p: complete for callback", ao);
2110 LIBXL_TAILQ_INSERT_TAIL(&egc->aos_for_callback, ao, entry_for_callback);
2111 } else {
2112 libxl_event *ev;
2113 ev = NEW_EVENT(egc, OPERATION_COMPLETE, ao->domid, ao->how.u.for_event);
2114 if (ev) {
2115 ev->u.operation_complete.rc = ao->rc;
2116 libxl__event_occurred(egc, ev);
2117 }
2118 ao->notified = 1;
2119 }
2120
2121 ao__check_destroy(ctx, ao);
2122 }
2123
libxl__ao_create(libxl_ctx * ctx,uint32_t domid,const libxl_asyncop_how * how,const char * file,int line,const char * func)2124 libxl__ao *libxl__ao_create(libxl_ctx *ctx, uint32_t domid,
2125 const libxl_asyncop_how *how,
2126 const char *file, int line, const char *func)
2127 {
2128 libxl__ao *ao;
2129
2130 ao = calloc(1, sizeof(*ao));
2131 if (!ao) goto out;
2132
2133 ao->magic = LIBXL__AO_MAGIC;
2134 ao->constructing = 1;
2135 ao->in_initiator = 1;
2136 ao__manip_enter(ao);
2137 ao->poller = 0;
2138 ao->domid = domid;
2139 LIBXL_INIT_GC(ao->gc, ctx);
2140
2141 if (how) {
2142 ao->how = *how;
2143 } else {
2144 ao->poller = libxl__poller_get(&ao->gc);
2145 if (!ao->poller) goto out;
2146 }
2147 libxl__log(ctx,XTL_DEBUG,-1,file,line,func,domid,
2148 "ao %p: create: how=%p callback=%p poller=%p",
2149 ao, how, ao->how.callback, ao->poller);
2150
2151 LIBXL_LIST_INSERT_HEAD(&ctx->aos_inprogress, ao, inprogress_entry);
2152
2153 return ao;
2154
2155 out:
2156 if (ao) libxl__ao__destroy(ctx, ao);
2157 return NULL;
2158 }
2159
2160
libxl__ao_inprogress(libxl__ao * ao,const char * file,int line,const char * func)2161 int libxl__ao_inprogress(libxl__ao *ao,
2162 const char *file, int line, const char *func)
2163 {
2164 AO_GC;
2165 int rc;
2166 uint32_t domid = ao->domid;
2167
2168 assert(ao->magic == LIBXL__AO_MAGIC);
2169 assert(ao->constructing);
2170 assert(ao->in_initiator);
2171 ao->constructing = 0;
2172
2173 if (ao->nested_root)
2174 domid = ao->nested_root->domid;
2175
2176 libxl__log(CTX,XTL_DEBUG,-1,file,line,func,domid,
2177 "ao %p: inprogress: poller=%p, flags=%s%s%s%s",
2178 ao, ao->poller,
2179 ao->constructing ? "o" : "",
2180 ao->in_initiator ? "i" : "",
2181 ao->complete ? "c" : "",
2182 ao->notified ? "n" : "");
2183
2184 if (ao->poller) {
2185 /* Caller wants it done synchronously. */
2186 /* We use a fresh gc, so that we can free things
2187 * each time round the loop. */
2188 libxl__egc egc;
2189 LIBXL_INIT_EGC(egc,CTX);
2190
2191 for (;;) {
2192 assert(ao->magic == LIBXL__AO_MAGIC);
2193
2194 if (!ao_work_outstanding(ao)) {
2195 rc = ao->rc;
2196 ao->notified = 1;
2197 break;
2198 }
2199
2200 DBG("ao %p: not ready, waiting",ao);
2201
2202 rc = eventloop_iteration(&egc,ao->poller);
2203 if (rc) {
2204 /* Oh dear, this is quite unfortunate. */
2205 LOG(ERROR,
2206 "Error waiting for"" event during long-running operation (rc=%d)",
2207 rc);
2208 sleep(1);
2209 /* It's either this or return ERROR_I_DONT_KNOW_WHETHER
2210 * _THE_THING_YOU_ASKED_FOR_WILL_BE_DONE_LATER_WHEN
2211 * _YOU_DIDNT_EXPECT_IT, since we don't have a
2212 * synchronous cancellation ability. */
2213 }
2214
2215 /* The call to egc..1_baton is below, only if we are leaving. */
2216 CTX_UNLOCK;
2217 libxl__egc_cleanup_2_ul_cb_gc(&egc);
2218 CTX_LOCK;
2219 }
2220
2221 /* Dispose of this early so libxl__egc_ao_cleanup_1_baton
2222 * doesn't mistake us for a baton-holder. No-one much is
2223 * going to look at this ao now so setting this to 0 is fine.
2224 * We can't call _baton below _leave because _leave destroys
2225 * our gc, which _baton needs. */
2226 libxl__poller_put(CTX, ao->poller);
2227 ao->poller = 0;
2228 } else {
2229 rc = 0;
2230 }
2231
2232 libxl__egc_ao_cleanup_1_baton(gc);
2233 ao->in_initiator = 0;
2234 ao__manip_leave(CTX, ao);
2235
2236 return rc;
2237 }
2238
2239
2240 /* abort requests */
2241
ao__abort(libxl_ctx * ctx,libxl__ao * parent)2242 static int ao__abort(libxl_ctx *ctx, libxl__ao *parent)
2243 /* Temporarily unlocks ctx, which must be locked exactly once on entry. */
2244 {
2245 libxl__egc egc;
2246 LIBXL_INIT_EGC(egc,ctx);
2247
2248 int rc;
2249 ao__manip_enter(parent);
2250
2251 if (parent->aborting) {
2252 rc = ERROR_ABORTED;
2253 goto out;
2254 }
2255
2256 parent->aborting = 1;
2257
2258 if (LIBXL_LIST_EMPTY(&parent->abortables)) {
2259 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG,
2260 "ao %p: abort requested and noted, but no-one interested",
2261 parent);
2262 rc = 0;
2263 goto out;
2264 }
2265
2266 /* We keep calling abort hooks until there are none left */
2267 while (!LIBXL_LIST_EMPTY(&parent->abortables)) {
2268 assert(!parent->complete);
2269
2270 libxl__ao_abortable *abrt = LIBXL_LIST_FIRST(&parent->abortables);
2271 assert(parent == ao_nested_root(abrt->ao));
2272
2273 LIBXL_LIST_REMOVE(abrt, entry);
2274 abrt->registered = 0;
2275
2276 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG,
2277 "ao %p: abrt=%p: aborting", parent, abrt->ao);
2278 abrt->callback(&egc, abrt, ERROR_ABORTED);
2279
2280 /* The call to egc..1_baton is in the out block below. */
2281 libxl__ctx_unlock(ctx);
2282 libxl__egc_cleanup_2_ul_cb_gc(&egc);
2283 libxl__ctx_lock(ctx);
2284 }
2285
2286 rc = 0;
2287
2288 out:
2289 libxl__egc_ao_cleanup_1_baton(&egc.gc);
2290 ao__manip_leave(ctx, parent);
2291 /* The call to egc..2_ul_cb_gc is above. This is sufficient
2292 * because only code inside the loop adds anything to the egc, and
2293 * we ensures that the egc is clean when we leave the loop. */
2294 return rc;
2295 }
2296
libxl_ao_abort(libxl_ctx * ctx,const libxl_asyncop_how * how)2297 int libxl_ao_abort(libxl_ctx *ctx, const libxl_asyncop_how *how)
2298 {
2299 libxl__ao *search;
2300 libxl__ctx_lock(ctx);
2301 int rc;
2302
2303 LIBXL_LIST_FOREACH(search, &ctx->aos_inprogress, inprogress_entry) {
2304 if (how) {
2305 /* looking for ao to be reported by callback or event */
2306 if (search->poller)
2307 /* sync */
2308 continue;
2309 if (how->callback != search->how.callback)
2310 continue;
2311 if (how->callback
2312 ? (how->u.for_callback != search->how.u.for_callback)
2313 : (how->u.for_event != search->how.u.for_event))
2314 continue;
2315 } else {
2316 /* looking for synchronous call */
2317 if (!search->poller)
2318 /* async */
2319 continue;
2320 }
2321 goto found;
2322 }
2323 rc = ERROR_NOTFOUND;
2324 goto out;
2325
2326 found:
2327 rc = ao__abort(ctx, search);
2328 out:
2329 libxl__ctx_unlock(ctx);
2330 return rc;
2331 }
2332
libxl__ao_aborting(libxl__ao * ao)2333 int libxl__ao_aborting(libxl__ao *ao)
2334 {
2335 libxl__ao *root = ao_nested_root(ao);
2336 AO_GC;
2337
2338 if (root->aborting) {
2339 DBG("ao=%p: aborting at explicit check (root=%p)", ao, root);
2340 return ERROR_ABORTED;
2341 }
2342
2343 return 0;
2344 }
2345
libxl__ao_abortable_register(libxl__ao_abortable * abrt)2346 int libxl__ao_abortable_register(libxl__ao_abortable *abrt)
2347 {
2348 libxl__ao *ao = abrt->ao;
2349 libxl__ao *root = ao_nested_root(ao);
2350 AO_GC;
2351
2352 if (root->aborting) {
2353 DBG("ao=%p: preemptively aborting ao_abortable registration %p (root=%p)",
2354 ao, abrt, root);
2355 return ERROR_ABORTED;
2356 }
2357
2358 DBG("ao=%p, abrt=%p: registering (root=%p)", ao, abrt, root);
2359 LIBXL_LIST_INSERT_HEAD(&root->abortables, abrt, entry);
2360 abrt->registered = 1;
2361
2362 return 0;
2363 }
2364
libxl__ao_abortable_deregister(libxl__ao_abortable * abrt)2365 _hidden void libxl__ao_abortable_deregister(libxl__ao_abortable *abrt)
2366 {
2367 if (!abrt->registered)
2368 return;
2369
2370 libxl__ao *ao = abrt->ao;
2371 libxl__ao *root __attribute__((unused)) = ao_nested_root(ao);
2372 AO_GC;
2373
2374 DBG("ao=%p, abrt=%p: deregistering (root=%p)", ao, abrt, root);
2375 LIBXL_LIST_REMOVE(abrt, entry);
2376 abrt->registered = 0;
2377 }
2378
2379
2380 /* progress reporting */
2381
2382 /* The application indicates a desire to ignore events by passing NULL
2383 * for how. But we want to copy *how. So we have this dummy function
2384 * whose address is stored in callback if the app passed how==NULL. */
dummy_asyncprogress_callback_ignore(libxl_ctx * ctx,libxl_event * ev,void * for_callback)2385 static void dummy_asyncprogress_callback_ignore
2386 (libxl_ctx *ctx, libxl_event *ev, void *for_callback) { }
2387
libxl__ao_progress_gethow(libxl_asyncprogress_how * in_state,const libxl_asyncprogress_how * from_app)2388 void libxl__ao_progress_gethow(libxl_asyncprogress_how *in_state,
2389 const libxl_asyncprogress_how *from_app) {
2390 if (from_app)
2391 *in_state = *from_app;
2392 else
2393 in_state->callback = dummy_asyncprogress_callback_ignore;
2394 }
2395
libxl__ao_progress_report(libxl__egc * egc,libxl__ao * ao,const libxl_asyncprogress_how * how,libxl_event * ev)2396 void libxl__ao_progress_report(libxl__egc *egc, libxl__ao *ao,
2397 const libxl_asyncprogress_how *how, libxl_event *ev)
2398 {
2399 AO_GC;
2400 assert(!ao->nested_root);
2401 if (how->callback == dummy_asyncprogress_callback_ignore) {
2402 LOG(DEBUG,"ao %p: progress report: ignored",ao);
2403 libxl_event_free(CTX,ev);
2404 /* ignore */
2405 } else if (how->callback) {
2406 libxl__aop_occurred *aop = libxl__zalloc(&egc->gc, sizeof(*aop));
2407 ao->progress_reports_outstanding++;
2408 aop->ao = ao;
2409 aop->ev = ev;
2410 aop->how = how;
2411 LIBXL_TAILQ_INSERT_TAIL(&egc->aops_for_callback, aop, entry);
2412 LOG(DEBUG,"ao %p: progress report: callback queued aop=%p",ao,aop);
2413 } else {
2414 LOG(DEBUG,"ao %p: progress report: event queued ev=%p type=%s",
2415 ao, ev, libxl_event_type_to_string(ev->type));
2416 libxl__event_occurred(egc, ev);
2417 }
2418 }
2419
2420
2421 /* nested ao */
2422
ao_nested_root(libxl__ao * ao)2423 static libxl__ao *ao_nested_root(libxl__ao *ao) {
2424 libxl__ao *root = ao->nested_root ? : ao;
2425 assert(!root->nested_root);
2426 return root;
2427 }
2428
libxl__nested_ao_create(libxl__ao * parent)2429 _hidden libxl__ao *libxl__nested_ao_create(libxl__ao *parent)
2430 {
2431 libxl__ao *child = NULL, *root;
2432 libxl_ctx *ctx = libxl__gc_owner(&parent->gc);
2433
2434 assert(parent->magic == LIBXL__AO_MAGIC);
2435 root = ao_nested_root(parent);
2436
2437 child = libxl__zalloc(&ctx->nogc_gc, sizeof(*child));
2438 child->magic = LIBXL__AO_MAGIC;
2439 child->nested_root = root;
2440 assert(root->nested_progeny < INT_MAX);
2441 root->nested_progeny++;
2442 LIBXL_INIT_GC(child->gc, ctx);
2443 libxl__gc *gc = &child->gc;
2444
2445 LOG(DEBUG,"ao %p: nested ao, parent %p", child, parent);
2446 return child;
2447 }
2448
libxl__nested_ao_free(libxl__ao * child)2449 _hidden void libxl__nested_ao_free(libxl__ao *child)
2450 {
2451 assert(child->magic == LIBXL__AO_MAGIC);
2452 libxl__ao *root = child->nested_root;
2453 assert(root);
2454 assert(root->nested_progeny > 0);
2455 root->nested_progeny--;
2456 libxl_ctx *ctx = libxl__gc_owner(&child->gc);
2457 libxl__ao__destroy(ctx, child);
2458 }
2459
2460
2461 /*
2462 * Local variables:
2463 * mode: C
2464 * c-basic-offset: 4
2465 * indent-tabs-mode: nil
2466 * End:
2467 */
2468