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