event_poll.c 21.3 KB
Newer Older
D
Daniel P. Berrange 已提交
1
/*
2
 * event.c: event loop for monitoring file handles
D
Daniel P. Berrange 已提交
3
 *
E
Eric Blake 已提交
4
 * Copyright (C) 2007, 2010-2011 Red Hat, Inc.
D
Daniel P. Berrange 已提交
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
 *
 * 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"
35
#include "event_poll.h"
36
#include "memory.h"
37
#include "util.h"
38
#include "ignore-value.h"
D
Daniel P. Berrange 已提交
39

40
#define EVENT_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__)
41

42
static int virEventPollInterruptLocked(void);
43

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

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

66
/* Allocate extra slots for virEventPollHandle/virEventPollTimeout
D
Daniel P. Berrange 已提交
67 68 69 70
   records in this multiple */
#define EVENT_ALLOC_EXTENT 10

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

/* Only have one event loop */
85
static struct virEventPollLoop eventLoop;
D
Daniel P. Berrange 已提交
86

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

D
Daniel P. Berrange 已提交
90
/* Unique ID for the next timer to be registered */
91
static int nextTimer = 1;
D
Daniel P. Berrange 已提交
92 93 94 95 96 97

/*
 * 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.
 */
98
int virEventPollAddHandle(int fd, int events,
99 100 101
                          virEventHandleCallback cb,
                          void *opaque,
                          virFreeCallback ff) {
102
    int watch;
103
    EVENT_DEBUG("Add handle fd=%d events=%d cb=%p opaque=%p", fd, events, cb, opaque);
104
    virMutexLock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
105
    if (eventLoop.handlesCount == eventLoop.handlesAlloc) {
106
        EVENT_DEBUG("Used %zu handle slots, adding at least %d more",
107
                    eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT);
108 109
        if (VIR_RESIZE_N(eventLoop.handles, eventLoop.handlesAlloc,
                         eventLoop.handlesCount, EVENT_ALLOC_EXTENT) < 0) {
110
            virMutexUnlock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
111
            return -1;
112
        }
D
Daniel P. Berrange 已提交
113 114
    }

115 116 117
    watch = nextWatch++;

    eventLoop.handles[eventLoop.handlesCount].watch = watch;
D
Daniel P. Berrange 已提交
118
    eventLoop.handles[eventLoop.handlesCount].fd = fd;
119
    eventLoop.handles[eventLoop.handlesCount].events =
120
                                         virEventPollToNativeEvents(events);
D
Daniel P. Berrange 已提交
121
    eventLoop.handles[eventLoop.handlesCount].cb = cb;
122
    eventLoop.handles[eventLoop.handlesCount].ff = ff;
D
Daniel P. Berrange 已提交
123 124 125 126 127
    eventLoop.handles[eventLoop.handlesCount].opaque = opaque;
    eventLoop.handles[eventLoop.handlesCount].deleted = 0;

    eventLoop.handlesCount++;

128
    virEventPollInterruptLocked();
129
    virMutexUnlock(&eventLoop.lock);
130 131

    return watch;
D
Daniel P. Berrange 已提交
132 133
}

134
void virEventPollUpdateHandle(int watch, int events) {
135
    int i;
136 137 138 139 140 141 142
    EVENT_DEBUG("Update handle w=%d e=%d", watch, events);

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

143
    virMutexLock(&eventLoop.lock);
144
    for (i = 0 ; i < eventLoop.handlesCount ; i++) {
145
        if (eventLoop.handles[i].watch == watch) {
146
            eventLoop.handles[i].events =
147 148
                    virEventPollToNativeEvents(events);
            virEventPollInterruptLocked();
149 150 151
            break;
        }
    }
152
    virMutexUnlock(&eventLoop.lock);
153 154
}

D
Daniel P. Berrange 已提交
155 156 157 158 159 160
/*
 * 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
 */
161
int virEventPollRemoveHandle(int watch) {
D
Daniel P. Berrange 已提交
162
    int i;
163
    EVENT_DEBUG("Remove handle w=%d", watch);
164 165 166 167 168 169

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

170
    virMutexLock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
171 172 173 174
    for (i = 0 ; i < eventLoop.handlesCount ; i++) {
        if (eventLoop.handles[i].deleted)
            continue;

175 176
        if (eventLoop.handles[i].watch == watch) {
            EVENT_DEBUG("mark delete %d %d", i, eventLoop.handles[i].fd);
D
Daniel P. Berrange 已提交
177
            eventLoop.handles[i].deleted = 1;
178
            virEventPollInterruptLocked();
179
            virMutexUnlock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
180 181 182
            return 0;
        }
    }
183
    virMutexUnlock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
184 185 186 187 188 189 190 191 192
    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.
 */
193
int virEventPollAddTimeout(int frequency,
194 195 196
                           virEventTimeoutCallback cb,
                           void *opaque,
                           virFreeCallback ff) {
197
    struct timeval now;
198
    int ret;
199 200
    EVENT_DEBUG("Adding timer %d with %d ms freq", nextTimer, frequency);
    if (gettimeofday(&now, NULL) < 0) {
D
Daniel P. Berrange 已提交
201 202 203
        return -1;
    }

204
    virMutexLock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
205
    if (eventLoop.timeoutsCount == eventLoop.timeoutsAlloc) {
206
        EVENT_DEBUG("Used %zu timeout slots, adding at least %d more",
207
                    eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT);
208 209
        if (VIR_RESIZE_N(eventLoop.timeouts, eventLoop.timeoutsAlloc,
                         eventLoop.timeoutsCount, EVENT_ALLOC_EXTENT) < 0) {
210
            virMutexUnlock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
211
            return -1;
212
        }
D
Daniel P. Berrange 已提交
213 214 215
    }

    eventLoop.timeouts[eventLoop.timeoutsCount].timer = nextTimer++;
216
    eventLoop.timeouts[eventLoop.timeoutsCount].frequency = frequency;
D
Daniel P. Berrange 已提交
217
    eventLoop.timeouts[eventLoop.timeoutsCount].cb = cb;
218
    eventLoop.timeouts[eventLoop.timeoutsCount].ff = ff;
D
Daniel P. Berrange 已提交
219 220 221
    eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque;
    eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0;
    eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt =
222 223 224
        frequency >= 0 ? frequency +
        (((unsigned long long)now.tv_sec)*1000) +
        (((unsigned long long)now.tv_usec)/1000) : 0;
D
Daniel P. Berrange 已提交
225 226

    eventLoop.timeoutsCount++;
227
    ret = nextTimer-1;
228
    virEventPollInterruptLocked();
229
    virMutexUnlock(&eventLoop.lock);
230
    return ret;
D
Daniel P. Berrange 已提交
231 232
}

233
void virEventPollUpdateTimeout(int timer, int frequency) {
234 235 236
    struct timeval tv;
    int i;
    EVENT_DEBUG("Updating timer %d timeout with %d ms freq", timer, frequency);
237 238 239 240 241 242

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

243 244 245 246
    if (gettimeofday(&tv, NULL) < 0) {
        return;
    }

247
    virMutexLock(&eventLoop.lock);
248 249 250 251 252 253 254
    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;
255
            virEventPollInterruptLocked();
256 257 258
            break;
        }
    }
259
    virMutexUnlock(&eventLoop.lock);
260 261
}

D
Daniel P. Berrange 已提交
262 263 264 265 266 267
/*
 * 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
 */
268
int virEventPollRemoveTimeout(int timer) {
D
Daniel P. Berrange 已提交
269
    int i;
270
    EVENT_DEBUG("Remove timer %d", timer);
271 272 273 274 275 276

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

277
    virMutexLock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
278 279 280 281 282 283
    for (i = 0 ; i < eventLoop.timeoutsCount ; i++) {
        if (eventLoop.timeouts[i].deleted)
            continue;

        if (eventLoop.timeouts[i].timer == timer) {
            eventLoop.timeouts[i].deleted = 1;
284
            virEventPollInterruptLocked();
285
            virMutexUnlock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
286 287 288
            return 0;
        }
    }
289
    virMutexUnlock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
290 291 292 293 294 295 296 297 298
    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
 */
299
static int virEventPollCalculateTimeout(int *timeout) {
D
Daniel P. Berrange 已提交
300 301
    unsigned long long then = 0;
    int i;
302
    EVENT_DEBUG("Calculate expiry of %zu timers", eventLoop.timeoutsCount);
D
Daniel P. Berrange 已提交
303 304
    /* Figure out if we need a timeout */
    for (i = 0 ; i < eventLoop.timeoutsCount ; i++) {
305
        if (eventLoop.timeouts[i].frequency < 0)
D
Daniel P. Berrange 已提交
306 307
            continue;

308
        EVENT_DEBUG("Got a timeout scheduled for %llu", eventLoop.timeouts[i].expiresAt);
D
Daniel P. Berrange 已提交
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
        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)
327
            *timeout = 0;
D
Daniel P. Berrange 已提交
328 329 330 331
    } else {
        *timeout = -1;
    }

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

D
Daniel P. Berrange 已提交
334 335 336 337 338 339 340 341
    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
 */
342
static struct pollfd *virEventPollMakePollFDs(int *nfds) {
D
Daniel P. Berrange 已提交
343
    struct pollfd *fds;
344
    int i;
D
Daniel P. Berrange 已提交
345

346 347 348 349 350 351
    *nfds = 0;
    for (i = 0 ; i < eventLoop.handlesCount ; i++) {
        if (eventLoop.handles[i].events)
            (*nfds)++;
    }

D
Daniel P. Berrange 已提交
352
    /* Setup the poll file handle data structs */
353
    if (VIR_ALLOC_N(fds, *nfds) < 0)
354
        return NULL;
D
Daniel P. Berrange 已提交
355

356
    *nfds = 0;
357 358 359 360 361
    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);
362 363 364 365 366 367
        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)++;
368
        //EVENT_DEBUG("Wait for %d %d", eventLoop.handles[i].fd, eventLoop.handles[i].events);
D
Daniel P. Berrange 已提交
369 370
    }

371
    return fds;
D
Daniel P. Berrange 已提交
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
}


/*
 * 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
 */
387
static int virEventPollDispatchTimeouts(void) {
D
Daniel P. Berrange 已提交
388 389 390 391 392
    struct timeval tv;
    unsigned long long now;
    int i;
    /* Save this now - it may be changed during dispatch */
    int ntimeouts = eventLoop.timeoutsCount;
393
    VIR_DEBUG("Dispatch %d", ntimeouts);
D
Daniel P. Berrange 已提交
394 395 396 397 398 399 400 401

    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++) {
402
        if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequency < 0)
D
Daniel P. Berrange 已提交
403 404
            continue;

405 406 407 408 409 410
        /* 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)) {
411 412 413
            virEventTimeoutCallback cb = eventLoop.timeouts[i].cb;
            int timer = eventLoop.timeouts[i].timer;
            void *opaque = eventLoop.timeouts[i].opaque;
D
Daniel P. Berrange 已提交
414
            eventLoop.timeouts[i].expiresAt =
415
                now + eventLoop.timeouts[i].frequency;
416

417
            virMutexUnlock(&eventLoop.lock);
418
            (cb)(timer, opaque);
419
            virMutexLock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
        }
    }
    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
 */
436
static int virEventPollDispatchHandles(int nfds, struct pollfd *fds) {
437
    int i, n;
438
    VIR_DEBUG("Dispatch %d", nfds);
D
Daniel P. Berrange 已提交
439

440 441 442
    /* 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 */
443 444 445 446 447 448 449 450 451
    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;

452
        VIR_DEBUG("i=%d w=%d", i, eventLoop.handles[i].watch);
D
Daniel P. Berrange 已提交
453
        if (eventLoop.handles[i].deleted) {
454 455
            EVENT_DEBUG("Skip deleted n=%d w=%d f=%d", i,
                        eventLoop.handles[i].watch, eventLoop.handles[i].fd);
D
Daniel P. Berrange 已提交
456 457 458
            continue;
        }

459
        if (fds[n].revents) {
460
            virEventHandleCallback cb = eventLoop.handles[i].cb;
E
Eric Blake 已提交
461
            int watch = eventLoop.handles[i].watch;
462
            void *opaque = eventLoop.handles[i].opaque;
463
            int hEvents = virEventPollFromNativeEvents(fds[n].revents);
464
            EVENT_DEBUG("Dispatch n=%d f=%d w=%d e=%d %p", i,
E
Eric Blake 已提交
465
                        fds[n].fd, watch, fds[n].revents, opaque);
466
            virMutexUnlock(&eventLoop.lock);
E
Eric Blake 已提交
467
            (cb)(watch, fds[n].fd, hEvents, opaque);
468
            virMutexLock(&eventLoop.lock);
D
Daniel P. Berrange 已提交
469 470 471 472 473 474 475 476 477 478 479
        }
    }

    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.
 */
480
static void virEventPollCleanupTimeouts(void) {
D
Daniel P. Berrange 已提交
481
    int i;
482
    size_t gap;
483
    VIR_DEBUG("Cleanup %zu", eventLoop.timeoutsCount);
D
Daniel P. Berrange 已提交
484 485

    /* Remove deleted entries, shuffling down remaining
486
     * entries as needed to form contiguous series
D
Daniel P. Berrange 已提交
487 488 489 490 491 492 493
     */
    for (i = 0 ; i < eventLoop.timeoutsCount ; ) {
        if (!eventLoop.timeouts[i].deleted) {
            i++;
            continue;
        }

494 495
        EVENT_DEBUG("Purging timeout %d with id %d", i,
                    eventLoop.timeouts[i].timer);
496 497 498
        if (eventLoop.timeouts[i].ff)
            (eventLoop.timeouts[i].ff)(eventLoop.timeouts[i].opaque);

D
Daniel P. Berrange 已提交
499 500 501
        if ((i+1) < eventLoop.timeoutsCount) {
            memmove(eventLoop.timeouts+i,
                    eventLoop.timeouts+i+1,
502
                    sizeof(struct virEventPollTimeout)*(eventLoop.timeoutsCount
503
                                                    -(i+1)));
D
Daniel P. Berrange 已提交
504 505 506 507 508
        }
        eventLoop.timeoutsCount--;
    }

    /* Release some memory if we've got a big chunk free */
509 510 511 512 513 514
    gap = eventLoop.timeoutsAlloc - eventLoop.timeoutsCount;
    if (eventLoop.timeoutsCount == 0 ||
        (gap > eventLoop.timeoutsCount && gap > EVENT_ALLOC_EXTENT)) {
        EVENT_DEBUG("Found %zu out of %zu timeout slots used, releasing %zu",
                    eventLoop.timeoutsCount, eventLoop.timeoutsAlloc, gap);
        VIR_SHRINK_N(eventLoop.timeouts, eventLoop.timeoutsAlloc, gap);
D
Daniel P. Berrange 已提交
515 516 517 518 519 520 521
    }
}

/* 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.
 */
522
static void virEventPollCleanupHandles(void) {
D
Daniel P. Berrange 已提交
523
    int i;
524
    size_t gap;
525
    VIR_DEBUG("Cleanup %zu", eventLoop.handlesCount);
D
Daniel P. Berrange 已提交
526 527

    /* Remove deleted entries, shuffling down remaining
528
     * entries as needed to form contiguous series
D
Daniel P. Berrange 已提交
529 530 531 532 533 534 535
     */
    for (i = 0 ; i < eventLoop.handlesCount ; ) {
        if (!eventLoop.handles[i].deleted) {
            i++;
            continue;
        }

536 537 538
        if (eventLoop.handles[i].ff)
            (eventLoop.handles[i].ff)(eventLoop.handles[i].opaque);

D
Daniel P. Berrange 已提交
539 540 541
        if ((i+1) < eventLoop.handlesCount) {
            memmove(eventLoop.handles+i,
                    eventLoop.handles+i+1,
542
                    sizeof(struct virEventPollHandle)*(eventLoop.handlesCount
543
                                                   -(i+1)));
D
Daniel P. Berrange 已提交
544 545 546 547 548
        }
        eventLoop.handlesCount--;
    }

    /* Release some memory if we've got a big chunk free */
549 550 551 552 553 554
    gap = eventLoop.handlesAlloc - eventLoop.handlesCount;
    if (eventLoop.handlesCount == 0 ||
        (gap > eventLoop.handlesCount && gap > EVENT_ALLOC_EXTENT)) {
        EVENT_DEBUG("Found %zu out of %zu handles slots used, releasing %zu",
                    eventLoop.handlesCount, eventLoop.handlesAlloc, gap);
        VIR_SHRINK_N(eventLoop.handles, eventLoop.handlesAlloc, gap);
D
Daniel P. Berrange 已提交
555 556 557 558 559 560 561
    }
}

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

566
    virMutexLock(&eventLoop.lock);
567
    eventLoop.running = 1;
568
    virThreadSelf(&eventLoop.leader);
D
Daniel P. Berrange 已提交
569

570 571
    virEventPollCleanupTimeouts();
    virEventPollCleanupHandles();
572

573 574
    if (!(fds = virEventPollMakePollFDs(&nfds)) ||
        virEventPollCalculateTimeout(&timeout) < 0)
575
        goto error;
D
Daniel P. Berrange 已提交
576

577
    virMutexUnlock(&eventLoop.lock);
578

D
Daniel P. Berrange 已提交
579
 retry:
580
    EVENT_DEBUG("Poll on %d handles %p timeout %d", nfds, fds, timeout);
D
Daniel P. Berrange 已提交
581 582
    ret = poll(fds, nfds, timeout);
    if (ret < 0) {
583
        EVENT_DEBUG("Poll got error event %d", errno);
D
Daniel P. Berrange 已提交
584 585 586
        if (errno == EINTR) {
            goto retry;
        }
587
        goto error_unlocked;
D
Daniel P. Berrange 已提交
588
    }
589
    EVENT_DEBUG("Poll got %d event(s)", ret);
590

591
    virMutexLock(&eventLoop.lock);
592
    if (virEventPollDispatchTimeouts() < 0)
593
        goto error;
D
Daniel P. Berrange 已提交
594 595

    if (ret > 0 &&
596
        virEventPollDispatchHandles(nfds, fds) < 0)
597
        goto error;
598

599 600
    virEventPollCleanupTimeouts();
    virEventPollCleanupHandles();
601

602
    eventLoop.running = 0;
603
    virMutexUnlock(&eventLoop.lock);
604
    VIR_FREE(fds);
605
    return 0;
606 607

error:
608
    virMutexUnlock(&eventLoop.lock);
609 610 611
error_unlocked:
    VIR_FREE(fds);
    return -1;
612 613
}

614

615 616 617 618
static void virEventPollHandleWakeup(int watch ATTRIBUTE_UNUSED,
                                     int fd,
                                     int events ATTRIBUTE_UNUSED,
                                     void *opaque ATTRIBUTE_UNUSED)
619 620
{
    char c;
621
    virMutexLock(&eventLoop.lock);
622
    ignore_value(saferead(fd, &c, sizeof(c)));
623 624 625
    virMutexUnlock(&eventLoop.lock);
}

626
int virEventPollInit(void)
627
{
628
    if (virMutexInit(&eventLoop.lock) < 0) {
629
        return -1;
630
    }
631 632

    if (pipe(eventLoop.wakeupfd) < 0 ||
633 634 635
        virSetNonBlock(eventLoop.wakeupfd[0]) < 0 ||
        virSetNonBlock(eventLoop.wakeupfd[1]) < 0 ||
        virSetCloseExec(eventLoop.wakeupfd[0]) < 0 ||
636
        virSetCloseExec(eventLoop.wakeupfd[1]) < 0) {
D
Daniel P. Berrange 已提交
637
        return -1;
638
    }
D
Daniel P. Berrange 已提交
639

640
    if (virEventPollAddHandle(eventLoop.wakeupfd[0],
641
                              VIR_EVENT_HANDLE_READABLE,
642
                              virEventPollHandleWakeup, NULL, NULL) < 0) {
D
Daniel P. Berrange 已提交
643
        return -1;
644
    }
D
Daniel P. Berrange 已提交
645 646 647

    return 0;
}
648

649
static int virEventPollInterruptLocked(void)
650 651
{
    char c = '\0';
652 653

    if (!eventLoop.running ||
654
        virThreadIsSelf(&eventLoop.leader)) {
655 656
        VIR_DEBUG("Skip interrupt, %d %d", eventLoop.running,
                  virThreadID(&eventLoop.leader));
657
        return 0;
658
    }
659

660
    VIR_DEBUG0("Interrupting");
661 662 663 664 665
    if (safewrite(eventLoop.wakeupfd[1], &c, sizeof(c)) != sizeof(c))
        return -1;
    return 0;
}

666
int virEventPollInterrupt(void)
667 668
{
    int ret;
669
    virMutexLock(&eventLoop.lock);
670
    ret = virEventPollInterruptLocked();
671
    virMutexUnlock(&eventLoop.lock);
672 673 674
    return ret;
}

675
int
676
virEventPollToNativeEvents(int events)
677 678 679 680 681 682 683 684 685 686 687 688 689
{
    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;
}

690
int
691
virEventPollFromNativeEvents(int events)
692
{
693
    int ret = 0;
694 695 696 697 698 699
    if(events & POLLIN)
        ret |= VIR_EVENT_HANDLE_READABLE;
    if(events & POLLOUT)
        ret |= VIR_EVENT_HANDLE_WRITABLE;
    if(events & POLLERR)
        ret |= VIR_EVENT_HANDLE_ERROR;
700 701
    if(events & POLLNVAL) /* Treat NVAL as error, since libvirt doesn't distinguish */
        ret |= VIR_EVENT_HANDLE_ERROR;
702 703 704 705
    if(events & POLLHUP)
        ret |= VIR_EVENT_HANDLE_HANGUP;
    return ret;
}