event.c 20.8 KB
Newer Older
D
Daniel P. Berrange 已提交
1
/*
2
 * event.c: event loop for monitoring file handles
D
Daniel P. Berrange 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * Copyright (C) 2007 Daniel P. Berrange
 * Copyright (C) 2007 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

24
#include <config.h>
D
Daniel P. Berrange 已提交
25 26 27 28 29 30

#include <stdlib.h>
#include <string.h>
#include <poll.h>
#include <sys/time.h>
#include <errno.h>
31
#include <unistd.h>
D
Daniel P. Berrange 已提交
32

33 34
#include "threads.h"
#include "logging.h"
D
Daniel P. Berrange 已提交
35
#include "event.h"
36
#include "memory.h"
37
#include "util.h"
D
Daniel P. Berrange 已提交
38

39
#define EVENT_DEBUG(fmt, ...) DEBUG(fmt, __VA_ARGS__)
40

41 42
static int virEventInterruptLocked(void);

D
Daniel P. Berrange 已提交
43 44
/* State for a single file handle being monitored */
struct virEventHandle {
45
    int watch;
D
Daniel P. Berrange 已提交
46 47 48
    int fd;
    int events;
    virEventHandleCallback cb;
49
    virFreeCallback ff;
D
Daniel P. Berrange 已提交
50 51 52 53 54 55 56
    void *opaque;
    int deleted;
};

/* State for a single timer being generated */
struct virEventTimeout {
    int timer;
57
    int frequency;
D
Daniel P. Berrange 已提交
58 59
    unsigned long long expiresAt;
    virEventTimeoutCallback cb;
60
    virFreeCallback ff;
D
Daniel P. Berrange 已提交
61 62 63 64 65 66 67 68 69 70
    void *opaque;
    int deleted;
};

/* Allocate extra slots for virEventHandle/virEventTimeout
   records in this multiple */
#define EVENT_ALLOC_EXTENT 10

/* State for the main event loop */
struct virEventLoop {
71
    pthread_mutex_t lock;
72
    int running;
73 74
    pthread_t leader;
    int wakeupfd[2];
D
Daniel P. Berrange 已提交
75 76 77 78 79 80 81 82 83 84 85
    int handlesCount;
    int handlesAlloc;
    struct virEventHandle *handles;
    int timeoutsCount;
    int timeoutsAlloc;
    struct virEventTimeout *timeouts;
};

/* Only have one event loop */
static struct virEventLoop eventLoop;

86
/* Unique ID for the next FD watch to be registered */
87
static int nextWatch = 1;
88

D
Daniel P. Berrange 已提交
89
/* Unique ID for the next timer to be registered */
90
static int nextTimer = 1;
D
Daniel P. Berrange 已提交
91

92 93 94 95 96 97 98 99 100 101
static void virEventLock(void)
{
    pthread_mutex_lock(&eventLoop.lock);
}

static void virEventUnlock(void)
{
    pthread_mutex_unlock(&eventLoop.lock);
}

D
Daniel P. Berrange 已提交
102 103 104 105 106
/*
 * Register a callback for monitoring file handle events.
 * NB, it *must* be safe to call this from within a callback
 * For this reason we only ever append to existing list.
 */
107 108 109 110
int virEventAddHandleImpl(int fd, int events,
                          virEventHandleCallback cb,
                          void *opaque,
                          virFreeCallback ff) {
111
    int watch;
112
    EVENT_DEBUG("Add handle fd=%d events=%d cb=%p opaque=%p", fd, events, cb, opaque);
113
    virEventLock();
D
Daniel P. Berrange 已提交
114
    if (eventLoop.handlesCount == eventLoop.handlesAlloc) {
115 116
        EVENT_DEBUG("Used %d handle slots, adding %d more",
                    eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT);
117
        if (VIR_REALLOC_N(eventLoop.handles,
118 119
                          (eventLoop.handlesAlloc + EVENT_ALLOC_EXTENT)) < 0) {
            virEventUnlock();
D
Daniel P. Berrange 已提交
120
            return -1;
121
        }
D
Daniel P. Berrange 已提交
122 123 124
        eventLoop.handlesAlloc += EVENT_ALLOC_EXTENT;
    }

125 126 127
    watch = nextWatch++;

    eventLoop.handles[eventLoop.handlesCount].watch = watch;
D
Daniel P. Berrange 已提交
128
    eventLoop.handles[eventLoop.handlesCount].fd = fd;
129 130
    eventLoop.handles[eventLoop.handlesCount].events =
                                         virEventHandleTypeToPollEvent(events);
D
Daniel P. Berrange 已提交
131
    eventLoop.handles[eventLoop.handlesCount].cb = cb;
132
    eventLoop.handles[eventLoop.handlesCount].ff = ff;
D
Daniel P. Berrange 已提交
133 134 135 136 137
    eventLoop.handles[eventLoop.handlesCount].opaque = opaque;
    eventLoop.handles[eventLoop.handlesCount].deleted = 0;

    eventLoop.handlesCount++;

138 139 140 141
    virEventInterruptLocked();
    virEventUnlock();

    return watch;
D
Daniel P. Berrange 已提交
142 143
}

144
void virEventUpdateHandleImpl(int watch, int events) {
145
    int i;
146 147 148 149 150 151 152
    EVENT_DEBUG("Update handle w=%d e=%d", watch, events);

    if (watch <= 0) {
        VIR_WARN("Ignoring invalid update watch %d", watch);
        return;
    }

153
    virEventLock();
154
    for (i = 0 ; i < eventLoop.handlesCount ; i++) {
155
        if (eventLoop.handles[i].watch == watch) {
156 157
            eventLoop.handles[i].events =
                    virEventHandleTypeToPollEvent(events);
158
            virEventInterruptLocked();
159 160 161
            break;
        }
    }
162
    virEventUnlock();
163 164
}

D
Daniel P. Berrange 已提交
165 166 167 168 169 170
/*
 * Unregister a callback from a file handle
 * NB, it *must* be safe to call this from within a callback
 * For this reason we only ever set a flag in the existing list.
 * Actual deletion will be done out-of-band
 */
171
int virEventRemoveHandleImpl(int watch) {
D
Daniel P. Berrange 已提交
172
    int i;
173
    EVENT_DEBUG("Remove handle w=%d", watch);
174 175 176 177 178 179

    if (watch <= 0) {
        VIR_WARN("Ignoring invalid remove watch %d", watch);
        return -1;
    }

180
    virEventLock();
D
Daniel P. Berrange 已提交
181 182 183 184
    for (i = 0 ; i < eventLoop.handlesCount ; i++) {
        if (eventLoop.handles[i].deleted)
            continue;

185 186
        if (eventLoop.handles[i].watch == watch) {
            EVENT_DEBUG("mark delete %d %d", i, eventLoop.handles[i].fd);
D
Daniel P. Berrange 已提交
187
            eventLoop.handles[i].deleted = 1;
188
            virEventInterruptLocked();
189
            virEventUnlock();
D
Daniel P. Berrange 已提交
190 191 192
            return 0;
        }
    }
193
    virEventUnlock();
D
Daniel P. Berrange 已提交
194 195 196 197 198 199 200 201 202
    return -1;
}


/*
 * Register a callback for a timer event
 * NB, it *must* be safe to call this from within a callback
 * For this reason we only ever append to existing list.
 */
203 204 205 206
int virEventAddTimeoutImpl(int frequency,
                           virEventTimeoutCallback cb,
                           void *opaque,
                           virFreeCallback ff) {
207
    struct timeval now;
208
    int ret;
209 210
    EVENT_DEBUG("Adding timer %d with %d ms freq", nextTimer, frequency);
    if (gettimeofday(&now, NULL) < 0) {
D
Daniel P. Berrange 已提交
211 212 213
        return -1;
    }

214
    virEventLock();
D
Daniel P. Berrange 已提交
215
    if (eventLoop.timeoutsCount == eventLoop.timeoutsAlloc) {
216 217
        EVENT_DEBUG("Used %d timeout slots, adding %d more",
                    eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT);
218
        if (VIR_REALLOC_N(eventLoop.timeouts,
219 220
                          (eventLoop.timeoutsAlloc + EVENT_ALLOC_EXTENT)) < 0) {
            virEventUnlock();
D
Daniel P. Berrange 已提交
221
            return -1;
222
        }
D
Daniel P. Berrange 已提交
223 224 225 226
        eventLoop.timeoutsAlloc += EVENT_ALLOC_EXTENT;
    }

    eventLoop.timeouts[eventLoop.timeoutsCount].timer = nextTimer++;
227
    eventLoop.timeouts[eventLoop.timeoutsCount].frequency = frequency;
D
Daniel P. Berrange 已提交
228
    eventLoop.timeouts[eventLoop.timeoutsCount].cb = cb;
229
    eventLoop.timeouts[eventLoop.timeoutsCount].ff = ff;
D
Daniel P. Berrange 已提交
230 231 232
    eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque;
    eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0;
    eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt =
233 234 235
        frequency >= 0 ? frequency +
        (((unsigned long long)now.tv_sec)*1000) +
        (((unsigned long long)now.tv_usec)/1000) : 0;
D
Daniel P. Berrange 已提交
236 237

    eventLoop.timeoutsCount++;
238 239 240 241
    ret = nextTimer-1;
    virEventInterruptLocked();
    virEventUnlock();
    return ret;
D
Daniel P. Berrange 已提交
242 243
}

244 245 246 247
void virEventUpdateTimeoutImpl(int timer, int frequency) {
    struct timeval tv;
    int i;
    EVENT_DEBUG("Updating timer %d timeout with %d ms freq", timer, frequency);
248 249 250 251 252 253

    if (timer <= 0) {
        VIR_WARN("Ignoring invalid update timer %d", timer);
        return;
    }

254 255 256 257
    if (gettimeofday(&tv, NULL) < 0) {
        return;
    }

258
    virEventLock();
259 260 261 262 263 264 265
    for (i = 0 ; i < eventLoop.timeoutsCount ; i++) {
        if (eventLoop.timeouts[i].timer == timer) {
            eventLoop.timeouts[i].frequency = frequency;
            eventLoop.timeouts[i].expiresAt =
                frequency >= 0 ? frequency +
                (((unsigned long long)tv.tv_sec)*1000) +
                (((unsigned long long)tv.tv_usec)/1000) : 0;
266
            virEventInterruptLocked();
267 268 269
            break;
        }
    }
270
    virEventUnlock();
271 272
}

D
Daniel P. Berrange 已提交
273 274 275 276 277 278
/*
 * Unregister a callback for a timer
 * NB, it *must* be safe to call this from within a callback
 * For this reason we only ever set a flag in the existing list.
 * Actual deletion will be done out-of-band
 */
279
int virEventRemoveTimeoutImpl(int timer) {
D
Daniel P. Berrange 已提交
280
    int i;
281
    EVENT_DEBUG("Remove timer %d", timer);
282 283 284 285 286 287

    if (timer <= 0) {
        VIR_WARN("Ignoring invalid remove timer %d", timer);
        return -1;
    }

288
    virEventLock();
D
Daniel P. Berrange 已提交
289 290 291 292 293 294
    for (i = 0 ; i < eventLoop.timeoutsCount ; i++) {
        if (eventLoop.timeouts[i].deleted)
            continue;

        if (eventLoop.timeouts[i].timer == timer) {
            eventLoop.timeouts[i].deleted = 1;
295
            virEventInterruptLocked();
296
            virEventUnlock();
D
Daniel P. Berrange 已提交
297 298 299
            return 0;
        }
    }
300
    virEventUnlock();
D
Daniel P. Berrange 已提交
301 302 303 304 305 306 307 308 309 310 311 312
    return -1;
}

/* Iterates over all registered timeouts and determine which
 * will be the first to expire.
 * @timeout: filled with expiry time of soonest timer, or -1 if
 *           no timeout is pending
 * returns: 0 on success, -1 on error
 */
static int virEventCalculateTimeout(int *timeout) {
    unsigned long long then = 0;
    int i;
313
    EVENT_DEBUG("Calculate expiry of %d timers", eventLoop.timeoutsCount);
D
Daniel P. Berrange 已提交
314 315
    /* Figure out if we need a timeout */
    for (i = 0 ; i < eventLoop.timeoutsCount ; i++) {
316
        if (eventLoop.timeouts[i].frequency < 0)
D
Daniel P. Berrange 已提交
317 318
            continue;

319
        EVENT_DEBUG("Got a timeout scheduled for %llu", eventLoop.timeouts[i].expiresAt);
D
Daniel P. Berrange 已提交
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
        if (then == 0 ||
            eventLoop.timeouts[i].expiresAt < then)
            then = eventLoop.timeouts[i].expiresAt;
    }

    /* Calculate how long we should wait for a timeout if needed */
    if (then > 0) {
        struct timeval tv;

        if (gettimeofday(&tv, NULL) < 0) {
            return -1;
        }

        *timeout = then -
            ((((unsigned long long)tv.tv_sec)*1000) +
             (((unsigned long long)tv.tv_usec)/1000));

        if (*timeout < 0)
338
            *timeout = 0;
D
Daniel P. Berrange 已提交
339 340 341 342
    } else {
        *timeout = -1;
    }

343 344
    EVENT_DEBUG("Timeout at %llu due in %d ms", then, *timeout);

D
Daniel P. Berrange 已提交
345 346 347 348 349 350 351 352
    return 0;
}

/*
 * Allocate a pollfd array containing data for all registered
 * file handles. The caller must free the returned data struct
 * returns: the pollfd array, or NULL on error
 */
353
static struct pollfd *virEventMakePollFDs(int *nfds) {
D
Daniel P. Berrange 已提交
354
    struct pollfd *fds;
355
    int i;
D
Daniel P. Berrange 已提交
356

357 358 359 360 361 362
    *nfds = 0;
    for (i = 0 ; i < eventLoop.handlesCount ; i++) {
        if (eventLoop.handles[i].events)
            (*nfds)++;
    }

D
Daniel P. Berrange 已提交
363
    /* Setup the poll file handle data structs */
364
    if (VIR_ALLOC_N(fds, *nfds) < 0)
365
        return NULL;
D
Daniel P. Berrange 已提交
366

367
    *nfds = 0;
368 369 370 371 372
    for (i = 0 ; i < eventLoop.handlesCount ; i++) {
        EVENT_DEBUG("Prepare n=%d w=%d, f=%d e=%d", i,
                    eventLoop.handles[i].watch,
                    eventLoop.handles[i].fd,
                    eventLoop.handles[i].events);
373 374 375 376 377 378
        if (!eventLoop.handles[i].events)
            continue;
        fds[*nfds].fd = eventLoop.handles[i].fd;
        fds[*nfds].events = eventLoop.handles[i].events;
        fds[*nfds].revents = 0;
        (*nfds)++;
379
        //EVENT_DEBUG("Wait for %d %d", eventLoop.handles[i].fd, eventLoop.handles[i].events);
D
Daniel P. Berrange 已提交
380 381
    }

382
    return fds;
D
Daniel P. Berrange 已提交
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
}


/*
 * Iterate over all timers and determine if any have expired.
 * Invoke the user supplied callback for each timer whose
 * expiry time is met, and schedule the next timeout. Does
 * not try to 'catch up' on time if the actual expiry time
 * was later than the requested time.
 *
 * This method must cope with new timers being registered
 * by a callback, and must skip any timers marked as deleted.
 *
 * Returns 0 upon success, -1 if an error occurred
 */
static int virEventDispatchTimeouts(void) {
    struct timeval tv;
    unsigned long long now;
    int i;
    /* Save this now - it may be changed during dispatch */
    int ntimeouts = eventLoop.timeoutsCount;
404
    DEBUG("Dispatch %d", ntimeouts);
D
Daniel P. Berrange 已提交
405 406 407 408 409 410 411 412

    if (gettimeofday(&tv, NULL) < 0) {
        return -1;
    }
    now = (((unsigned long long)tv.tv_sec)*1000) +
        (((unsigned long long)tv.tv_usec)/1000);

    for (i = 0 ; i < ntimeouts ; i++) {
413
        if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequency < 0)
D
Daniel P. Berrange 已提交
414 415
            continue;

416 417 418 419 420 421
        /* Add 20ms fuzz so we don't pointlessly spin doing
         * <10ms sleeps, particularly on kernels with low HZ
         * it is fine that a timer expires 20ms earlier than
         * requested
         */
        if (eventLoop.timeouts[i].expiresAt <= (now+20)) {
422 423 424
            virEventTimeoutCallback cb = eventLoop.timeouts[i].cb;
            int timer = eventLoop.timeouts[i].timer;
            void *opaque = eventLoop.timeouts[i].opaque;
D
Daniel P. Berrange 已提交
425
            eventLoop.timeouts[i].expiresAt =
426
                now + eventLoop.timeouts[i].frequency;
427 428 429 430

            virEventUnlock();
            (cb)(timer, opaque);
            virEventLock();
D
Daniel P. Berrange 已提交
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
        }
    }
    return 0;
}


/* Iterate over all file handles and dispatch any which
 * have pending events listed in the poll() data. Invoke
 * the user supplied callback for each handle which has
 * pending events
 *
 * This method must cope with new handles being registered
 * by a callback, and must skip any handles marked as deleted.
 *
 * Returns 0 upon success, -1 if an error occurred
 */
447
static int virEventDispatchHandles(int nfds, struct pollfd *fds) {
448 449
    int i, n;
    DEBUG("Dispatch %d", nfds);
D
Daniel P. Berrange 已提交
450

451 452 453
    /* NB, use nfds not eventLoop.handlesCount, because new
     * fds might be added on end of list, and they're not
     * in the fds array we've got */
454 455 456 457 458 459 460 461 462 463
    for (i = 0, n = 0 ; n < nfds && i < eventLoop.handlesCount ; n++) {
        while ((eventLoop.handles[i].fd != fds[n].fd ||
                eventLoop.handles[i].events == 0) &&
               i < eventLoop.handlesCount) {
            i++;
        }
        if (i == eventLoop.handlesCount)
            break;

        DEBUG("i=%d w=%d", i, eventLoop.handles[i].watch);
D
Daniel P. Berrange 已提交
464
        if (eventLoop.handles[i].deleted) {
465 466
            EVENT_DEBUG("Skip deleted n=%d w=%d f=%d", i,
                        eventLoop.handles[i].watch, eventLoop.handles[i].fd);
D
Daniel P. Berrange 已提交
467 468 469
            continue;
        }

470
        if (fds[n].revents) {
471 472
            virEventHandleCallback cb = eventLoop.handles[i].cb;
            void *opaque = eventLoop.handles[i].opaque;
473
            int hEvents = virPollEventToEventHandleType(fds[n].revents);
474
            EVENT_DEBUG("Dispatch n=%d f=%d w=%d e=%d %p", i,
475 476
                        fds[n].fd, eventLoop.handles[i].watch,
                        fds[n].revents, eventLoop.handles[i].opaque);
477 478
            virEventUnlock();
            (cb)(eventLoop.handles[i].watch,
479
                 fds[n].fd, hEvents, opaque);
480
            virEventLock();
D
Daniel P. Berrange 已提交
481 482 483 484 485 486 487 488 489 490 491 492 493
        }
    }

    return 0;
}


/* Used post dispatch to actually remove any timers that
 * were previously marked as deleted. This asynchronous
 * cleanup is needed to make dispatch re-entrant safe.
 */
static int virEventCleanupTimeouts(void) {
    int i;
494
    DEBUG("Cleanup %d", eventLoop.timeoutsCount);
D
Daniel P. Berrange 已提交
495 496

    /* Remove deleted entries, shuffling down remaining
497
     * entries as needed to form contiguous series
D
Daniel P. Berrange 已提交
498 499 500 501 502 503 504
     */
    for (i = 0 ; i < eventLoop.timeoutsCount ; ) {
        if (!eventLoop.timeouts[i].deleted) {
            i++;
            continue;
        }

505
        EVENT_DEBUG("Purging timeout %d with id %d", i, eventLoop.timeouts[i].timer);
506 507 508
        if (eventLoop.timeouts[i].ff)
            (eventLoop.timeouts[i].ff)(eventLoop.timeouts[i].opaque);

D
Daniel P. Berrange 已提交
509 510 511 512 513 514 515 516 517 518
        if ((i+1) < eventLoop.timeoutsCount) {
            memmove(eventLoop.timeouts+i,
                    eventLoop.timeouts+i+1,
                    sizeof(struct virEventTimeout)*(eventLoop.timeoutsCount-(i+1)));
        }
        eventLoop.timeoutsCount--;
    }

    /* Release some memory if we've got a big chunk free */
    if ((eventLoop.timeoutsAlloc - EVENT_ALLOC_EXTENT) > eventLoop.timeoutsCount) {
519
        EVENT_DEBUG("Releasing %d out of %d timeout slots used, releasing %d",
D
Daniel P. Berrange 已提交
520
                   eventLoop.timeoutsCount, eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT);
521 522
        if (VIR_REALLOC_N(eventLoop.timeouts,
                          (eventLoop.timeoutsAlloc - EVENT_ALLOC_EXTENT)) < 0)
D
Daniel P. Berrange 已提交
523 524 525 526 527 528 529 530 531 532 533 534
            return -1;
        eventLoop.timeoutsAlloc -= EVENT_ALLOC_EXTENT;
    }
    return 0;
}

/* Used post dispatch to actually remove any handles that
 * were previously marked as deleted. This asynchronous
 * cleanup is needed to make dispatch re-entrant safe.
 */
static int virEventCleanupHandles(void) {
    int i;
535
    DEBUG("Cleanupo %d", eventLoop.handlesCount);
D
Daniel P. Berrange 已提交
536 537

    /* Remove deleted entries, shuffling down remaining
538
     * entries as needed to form contiguous series
D
Daniel P. Berrange 已提交
539 540 541 542 543 544 545
     */
    for (i = 0 ; i < eventLoop.handlesCount ; ) {
        if (!eventLoop.handles[i].deleted) {
            i++;
            continue;
        }

546 547 548
        if (eventLoop.handles[i].ff)
            (eventLoop.handles[i].ff)(eventLoop.handles[i].opaque);

D
Daniel P. Berrange 已提交
549 550 551 552 553 554 555 556 557 558
        if ((i+1) < eventLoop.handlesCount) {
            memmove(eventLoop.handles+i,
                    eventLoop.handles+i+1,
                    sizeof(struct virEventHandle)*(eventLoop.handlesCount-(i+1)));
        }
        eventLoop.handlesCount--;
    }

    /* Release some memory if we've got a big chunk free */
    if ((eventLoop.handlesAlloc - EVENT_ALLOC_EXTENT) > eventLoop.handlesCount) {
559
        EVENT_DEBUG("Releasing %d out of %d handles slots used, releasing %d",
D
Daniel P. Berrange 已提交
560
                   eventLoop.handlesCount, eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT);
561 562
        if (VIR_REALLOC_N(eventLoop.handles,
                          (eventLoop.handlesAlloc - EVENT_ALLOC_EXTENT)) < 0)
D
Daniel P. Berrange 已提交
563 564 565 566 567 568 569 570 571 572 573
            return -1;
        eventLoop.handlesAlloc -= EVENT_ALLOC_EXTENT;
    }
    return 0;
}

/*
 * Run a single iteration of the event loop, blocking until
 * at least one file handle has an event, or a timer expires
 */
int virEventRunOnce(void) {
574
    struct pollfd *fds = NULL;
D
Daniel P. Berrange 已提交
575 576
    int ret, timeout, nfds;

577
    virEventLock();
578
    eventLoop.running = 1;
579
    eventLoop.leader = pthread_self();
D
Daniel P. Berrange 已提交
580

581 582 583 584
    if (virEventCleanupTimeouts() < 0 ||
        virEventCleanupHandles() < 0)
        goto error;

585
    if (!(fds = virEventMakePollFDs(&nfds)) ||
586 587
        virEventCalculateTimeout(&timeout) < 0)
        goto error;
D
Daniel P. Berrange 已提交
588

589 590
    virEventUnlock();

D
Daniel P. Berrange 已提交
591
 retry:
592
    EVENT_DEBUG("Poll on %d handles %p timeout %d", nfds, fds, timeout);
D
Daniel P. Berrange 已提交
593
    ret = poll(fds, nfds, timeout);
594
    EVENT_DEBUG("Poll got %d event", ret);
D
Daniel P. Berrange 已提交
595 596 597 598
    if (ret < 0) {
        if (errno == EINTR) {
            goto retry;
        }
599
        goto error_unlocked;
D
Daniel P. Berrange 已提交
600
    }
601 602

    virEventLock();
603 604
    if (virEventDispatchTimeouts() < 0)
        goto error;
D
Daniel P. Berrange 已提交
605 606

    if (ret > 0 &&
607 608
        virEventDispatchHandles(nfds, fds) < 0)
        goto error;
609

610 611 612
    if (virEventCleanupTimeouts() < 0 ||
        virEventCleanupHandles() < 0)
        goto error;
613

614
    eventLoop.running = 0;
615
    virEventUnlock();
616
    VIR_FREE(fds);
617
    return 0;
618 619 620 621 622 623

error:
    virEventUnlock();
error_unlocked:
    VIR_FREE(fds);
    return -1;
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
}

static void virEventHandleWakeup(int watch ATTRIBUTE_UNUSED,
                                 int fd,
                                 int events ATTRIBUTE_UNUSED,
                                 void *opaque ATTRIBUTE_UNUSED)
{
    char c;
    virEventLock();
    saferead(fd, &c, sizeof(c));
    virEventUnlock();
}

int virEventInit(void)
{
    if (pthread_mutex_init(&eventLoop.lock, NULL) != 0)
        return -1;

    if (pipe(eventLoop.wakeupfd) < 0 ||
643 644 645 646
        virSetNonBlock(eventLoop.wakeupfd[0]) < 0 ||
        virSetNonBlock(eventLoop.wakeupfd[1]) < 0 ||
        virSetCloseExec(eventLoop.wakeupfd[0]) < 0 ||
        virSetCloseExec(eventLoop.wakeupfd[1]) < 0)
D
Daniel P. Berrange 已提交
647 648
        return -1;

649 650 651
    if (virEventAddHandleImpl(eventLoop.wakeupfd[0],
                              VIR_EVENT_HANDLE_READABLE,
                              virEventHandleWakeup, NULL, NULL) < 0)
D
Daniel P. Berrange 已提交
652 653 654 655
        return -1;

    return 0;
}
656

657 658 659
static int virEventInterruptLocked(void)
{
    char c = '\0';
660 661

    if (!eventLoop.running ||
662 663
        pthread_self() == eventLoop.leader) {
        VIR_DEBUG("Skip interrupt, %d %d", eventLoop.running, (int)eventLoop.leader);
664
        return 0;
665
    }
666

667
    VIR_DEBUG0("Interrupting");
668 669 670 671 672 673 674 675 676 677 678 679 680 681
    if (safewrite(eventLoop.wakeupfd[1], &c, sizeof(c)) != sizeof(c))
        return -1;
    return 0;
}

int virEventInterrupt(void)
{
    int ret;
    virEventLock();
    ret = virEventInterruptLocked();
    virEventUnlock();
    return ret;
}

682
int
683
virEventHandleTypeToPollEvent(int events)
684 685 686 687 688 689 690 691 692 693 694 695 696
{
    int ret = 0;
    if(events & VIR_EVENT_HANDLE_READABLE)
        ret |= POLLIN;
    if(events & VIR_EVENT_HANDLE_WRITABLE)
        ret |= POLLOUT;
    if(events & VIR_EVENT_HANDLE_ERROR)
        ret |= POLLERR;
    if(events & VIR_EVENT_HANDLE_HANGUP)
        ret |= POLLHUP;
    return ret;
}

697 698
int
virPollEventToEventHandleType(int events)
699
{
700
    int ret = 0;
701 702 703 704 705 706
    if(events & POLLIN)
        ret |= VIR_EVENT_HANDLE_READABLE;
    if(events & POLLOUT)
        ret |= VIR_EVENT_HANDLE_WRITABLE;
    if(events & POLLERR)
        ret |= VIR_EVENT_HANDLE_ERROR;
707 708
    if(events & POLLNVAL) /* Treat NVAL as error, since libvirt doesn't distinguish */
        ret |= VIR_EVENT_HANDLE_ERROR;
709 710 711 712
    if(events & POLLHUP)
        ret |= VIR_EVENT_HANDLE_HANGUP;
    return ret;
}