PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/src/event_poll.c

https://gitlab.com/libvirt/libvirt-snmp
C | 724 lines | 509 code | 97 blank | 118 comment | 90 complexity | 468215867e722a6b46f9a28fa370c6bb MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * event.c: event loop for monitoring file handles
  3. *
  4. * Copyright (C) 2007, 2010-2011 Red Hat, Inc.
  5. * Copyright (C) 2007 Daniel P. Berrange
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. * Author: Daniel P. Berrange <berrange@redhat.com>
  22. */
  23. #include <config.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <poll.h>
  27. #include <sys/time.h>
  28. #include <errno.h>
  29. #include <unistd.h>
  30. #include "threads.h"
  31. #include "event_poll.h"
  32. #include "memory.h"
  33. #include "util.h"
  34. #include "ignore-value.h"
  35. #define EVENT_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__)
  36. static int virEventPollInterruptLocked(void);
  37. /* State for a single file handle being monitored */
  38. struct virEventPollHandle {
  39. int watch;
  40. int fd;
  41. int events;
  42. virEventHandleCallback cb;
  43. virFreeCallback ff;
  44. void *opaque;
  45. int deleted;
  46. };
  47. /* State for a single timer being generated */
  48. struct virEventPollTimeout {
  49. int timer;
  50. int frequency;
  51. unsigned long long expiresAt;
  52. virEventTimeoutCallback cb;
  53. virFreeCallback ff;
  54. void *opaque;
  55. int deleted;
  56. };
  57. /* Allocate extra slots for virEventPollHandle/virEventPollTimeout
  58. records in this multiple */
  59. #define EVENT_ALLOC_EXTENT 10
  60. /* State for the main event loop */
  61. struct virEventPollLoop {
  62. virMutex lock;
  63. int running;
  64. virThread leader;
  65. int wakeupfd[2];
  66. size_t handlesCount;
  67. size_t handlesAlloc;
  68. struct virEventPollHandle *handles;
  69. size_t timeoutsCount;
  70. size_t timeoutsAlloc;
  71. struct virEventPollTimeout *timeouts;
  72. };
  73. /* Only have one event loop */
  74. static struct virEventPollLoop eventLoop;
  75. /* Unique ID for the next FD watch to be registered */
  76. static int nextWatch = 1;
  77. /* Unique ID for the next timer to be registered */
  78. static int nextTimer = 1;
  79. /*
  80. * Register a callback for monitoring file handle events.
  81. * NB, it *must* be safe to call this from within a callback
  82. * For this reason we only ever append to existing list.
  83. */
  84. int virEventPollAddHandle(int fd, int events,
  85. virEventHandleCallback cb,
  86. void *opaque,
  87. virFreeCallback ff) {
  88. int watch;
  89. EVENT_DEBUG("Add handle fd=%d events=%d cb=%p opaque=%p", fd, events, cb, opaque);
  90. virMutexLock(&eventLoop.lock);
  91. if (eventLoop.handlesCount == eventLoop.handlesAlloc) {
  92. EVENT_DEBUG("Used %zu handle slots, adding at least %d more",
  93. eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT);
  94. if (VIR_RESIZE_N(eventLoop.handles, eventLoop.handlesAlloc,
  95. eventLoop.handlesCount, EVENT_ALLOC_EXTENT) < 0) {
  96. virMutexUnlock(&eventLoop.lock);
  97. return -1;
  98. }
  99. }
  100. watch = nextWatch++;
  101. eventLoop.handles[eventLoop.handlesCount].watch = watch;
  102. eventLoop.handles[eventLoop.handlesCount].fd = fd;
  103. eventLoop.handles[eventLoop.handlesCount].events =
  104. virEventPollToNativeEvents(events);
  105. eventLoop.handles[eventLoop.handlesCount].cb = cb;
  106. eventLoop.handles[eventLoop.handlesCount].ff = ff;
  107. eventLoop.handles[eventLoop.handlesCount].opaque = opaque;
  108. eventLoop.handles[eventLoop.handlesCount].deleted = 0;
  109. eventLoop.handlesCount++;
  110. virEventPollInterruptLocked();
  111. virMutexUnlock(&eventLoop.lock);
  112. return watch;
  113. }
  114. void virEventPollUpdateHandle(int watch, int events) {
  115. int i;
  116. EVENT_DEBUG("Update handle w=%d e=%d", watch, events);
  117. if (watch <= 0) {
  118. VIR_WARN("Ignoring invalid update watch %d", watch);
  119. return;
  120. }
  121. virMutexLock(&eventLoop.lock);
  122. for (i = 0 ; i < eventLoop.handlesCount ; i++) {
  123. if (eventLoop.handles[i].watch == watch) {
  124. eventLoop.handles[i].events =
  125. virEventPollToNativeEvents(events);
  126. virEventPollInterruptLocked();
  127. break;
  128. }
  129. }
  130. virMutexUnlock(&eventLoop.lock);
  131. }
  132. /*
  133. * Unregister a callback from a file handle
  134. * NB, it *must* be safe to call this from within a callback
  135. * For this reason we only ever set a flag in the existing list.
  136. * Actual deletion will be done out-of-band
  137. */
  138. int virEventPollRemoveHandle(int watch) {
  139. int i;
  140. EVENT_DEBUG("Remove handle w=%d", watch);
  141. if (watch <= 0) {
  142. VIR_WARN("Ignoring invalid remove watch %d", watch);
  143. return -1;
  144. }
  145. virMutexLock(&eventLoop.lock);
  146. for (i = 0 ; i < eventLoop.handlesCount ; i++) {
  147. if (eventLoop.handles[i].deleted)
  148. continue;
  149. if (eventLoop.handles[i].watch == watch) {
  150. EVENT_DEBUG("mark delete %d %d", i, eventLoop.handles[i].fd);
  151. eventLoop.handles[i].deleted = 1;
  152. virEventPollInterruptLocked();
  153. virMutexUnlock(&eventLoop.lock);
  154. return 0;
  155. }
  156. }
  157. virMutexUnlock(&eventLoop.lock);
  158. return -1;
  159. }
  160. /*
  161. * Register a callback for a timer event
  162. * NB, it *must* be safe to call this from within a callback
  163. * For this reason we only ever append to existing list.
  164. */
  165. int virEventPollAddTimeout(int frequency,
  166. virEventTimeoutCallback cb,
  167. void *opaque,
  168. virFreeCallback ff) {
  169. struct timeval now;
  170. int ret;
  171. EVENT_DEBUG("Adding timer %d with %d ms freq", nextTimer, frequency);
  172. if (gettimeofday(&now, NULL) < 0) {
  173. return -1;
  174. }
  175. virMutexLock(&eventLoop.lock);
  176. if (eventLoop.timeoutsCount == eventLoop.timeoutsAlloc) {
  177. EVENT_DEBUG("Used %zu timeout slots, adding at least %d more",
  178. eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT);
  179. if (VIR_RESIZE_N(eventLoop.timeouts, eventLoop.timeoutsAlloc,
  180. eventLoop.timeoutsCount, EVENT_ALLOC_EXTENT) < 0) {
  181. virMutexUnlock(&eventLoop.lock);
  182. return -1;
  183. }
  184. }
  185. eventLoop.timeouts[eventLoop.timeoutsCount].timer = nextTimer++;
  186. eventLoop.timeouts[eventLoop.timeoutsCount].frequency = frequency;
  187. eventLoop.timeouts[eventLoop.timeoutsCount].cb = cb;
  188. eventLoop.timeouts[eventLoop.timeoutsCount].ff = ff;
  189. eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque;
  190. eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0;
  191. eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt =
  192. frequency >= 0 ? frequency +
  193. (((unsigned long long)now.tv_sec)*1000) +
  194. (((unsigned long long)now.tv_usec)/1000) : 0;
  195. eventLoop.timeoutsCount++;
  196. ret = nextTimer-1;
  197. virEventPollInterruptLocked();
  198. virMutexUnlock(&eventLoop.lock);
  199. return ret;
  200. }
  201. void virEventPollUpdateTimeout(int timer, int frequency) {
  202. struct timeval tv;
  203. int i;
  204. EVENT_DEBUG("Updating timer %d timeout with %d ms freq", timer, frequency);
  205. if (timer <= 0) {
  206. VIR_WARN("Ignoring invalid update timer %d", timer);
  207. return;
  208. }
  209. if (gettimeofday(&tv, NULL) < 0) {
  210. return;
  211. }
  212. virMutexLock(&eventLoop.lock);
  213. for (i = 0 ; i < eventLoop.timeoutsCount ; i++) {
  214. if (eventLoop.timeouts[i].timer == timer) {
  215. eventLoop.timeouts[i].frequency = frequency;
  216. eventLoop.timeouts[i].expiresAt =
  217. frequency >= 0 ? frequency +
  218. (((unsigned long long)tv.tv_sec)*1000) +
  219. (((unsigned long long)tv.tv_usec)/1000) : 0;
  220. virEventPollInterruptLocked();
  221. break;
  222. }
  223. }
  224. virMutexUnlock(&eventLoop.lock);
  225. }
  226. /*
  227. * Unregister a callback for a timer
  228. * NB, it *must* be safe to call this from within a callback
  229. * For this reason we only ever set a flag in the existing list.
  230. * Actual deletion will be done out-of-band
  231. */
  232. int virEventPollRemoveTimeout(int timer) {
  233. int i;
  234. EVENT_DEBUG("Remove timer %d", timer);
  235. if (timer <= 0) {
  236. VIR_WARN("Ignoring invalid remove timer %d", timer);
  237. return -1;
  238. }
  239. virMutexLock(&eventLoop.lock);
  240. for (i = 0 ; i < eventLoop.timeoutsCount ; i++) {
  241. if (eventLoop.timeouts[i].deleted)
  242. continue;
  243. if (eventLoop.timeouts[i].timer == timer) {
  244. eventLoop.timeouts[i].deleted = 1;
  245. virEventPollInterruptLocked();
  246. virMutexUnlock(&eventLoop.lock);
  247. return 0;
  248. }
  249. }
  250. virMutexUnlock(&eventLoop.lock);
  251. return -1;
  252. }
  253. /* Iterates over all registered timeouts and determine which
  254. * will be the first to expire.
  255. * @timeout: filled with expiry time of soonest timer, or -1 if
  256. * no timeout is pending
  257. * returns: 0 on success, -1 on error
  258. */
  259. static int virEventPollCalculateTimeout(int *timeout) {
  260. unsigned long long then = 0;
  261. int i;
  262. EVENT_DEBUG("Calculate expiry of %zu timers", eventLoop.timeoutsCount);
  263. /* Figure out if we need a timeout */
  264. for (i = 0 ; i < eventLoop.timeoutsCount ; i++) {
  265. if (eventLoop.timeouts[i].frequency < 0)
  266. continue;
  267. EVENT_DEBUG("Got a timeout scheduled for %llu", eventLoop.timeouts[i].expiresAt);
  268. if (then == 0 ||
  269. eventLoop.timeouts[i].expiresAt < then)
  270. then = eventLoop.timeouts[i].expiresAt;
  271. }
  272. /* Calculate how long we should wait for a timeout if needed */
  273. if (then > 0) {
  274. struct timeval tv;
  275. if (gettimeofday(&tv, NULL) < 0) {
  276. perror("Unable to get current time");
  277. return -1;
  278. }
  279. *timeout = then -
  280. ((((unsigned long long)tv.tv_sec)*1000) +
  281. (((unsigned long long)tv.tv_usec)/1000));
  282. if (*timeout < 0)
  283. *timeout = 0;
  284. } else {
  285. *timeout = -1;
  286. }
  287. EVENT_DEBUG("Timeout at %llu due in %d ms", then, *timeout);
  288. return 0;
  289. }
  290. /*
  291. * Allocate a pollfd array containing data for all registered
  292. * file handles. The caller must free the returned data struct
  293. * returns: the pollfd array, or NULL on error
  294. */
  295. static struct pollfd *virEventPollMakePollFDs(int *nfds) {
  296. struct pollfd *fds;
  297. int i;
  298. *nfds = 0;
  299. for (i = 0 ; i < eventLoop.handlesCount ; i++) {
  300. if (eventLoop.handles[i].events && !eventLoop.handles[i].deleted)
  301. (*nfds)++;
  302. }
  303. /* Setup the poll file handle data structs */
  304. if (VIR_ALLOC_N(fds, *nfds) < 0) {
  305. perror("unable to allocate memory");
  306. return NULL;
  307. }
  308. *nfds = 0;
  309. for (i = 0 ; i < eventLoop.handlesCount ; i++) {
  310. EVENT_DEBUG("Prepare n=%d w=%d, f=%d e=%d d=%d", i,
  311. eventLoop.handles[i].watch,
  312. eventLoop.handles[i].fd,
  313. eventLoop.handles[i].events,
  314. eventLoop.handles[i].deleted);
  315. if (!eventLoop.handles[i].events || eventLoop.handles[i].deleted)
  316. continue;
  317. fds[*nfds].fd = eventLoop.handles[i].fd;
  318. fds[*nfds].events = eventLoop.handles[i].events;
  319. fds[*nfds].revents = 0;
  320. (*nfds)++;
  321. //EVENT_DEBUG("Wait for %d %d", eventLoop.handles[i].fd, eventLoop.handles[i].events);
  322. }
  323. return fds;
  324. }
  325. /*
  326. * Iterate over all timers and determine if any have expired.
  327. * Invoke the user supplied callback for each timer whose
  328. * expiry time is met, and schedule the next timeout. Does
  329. * not try to 'catch up' on time if the actual expiry time
  330. * was later than the requested time.
  331. *
  332. * This method must cope with new timers being registered
  333. * by a callback, and must skip any timers marked as deleted.
  334. *
  335. * Returns 0 upon success, -1 if an error occurred
  336. */
  337. static int virEventPollDispatchTimeouts(void) {
  338. struct timeval tv;
  339. unsigned long long now;
  340. int i;
  341. /* Save this now - it may be changed during dispatch */
  342. int ntimeouts = eventLoop.timeoutsCount;
  343. VIR_DEBUG("Dispatch %d", ntimeouts);
  344. if (gettimeofday(&tv, NULL) < 0) {
  345. perror("Unable to get current time");
  346. return -1;
  347. }
  348. now = (((unsigned long long)tv.tv_sec)*1000) +
  349. (((unsigned long long)tv.tv_usec)/1000);
  350. for (i = 0 ; i < ntimeouts ; i++) {
  351. if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequency < 0)
  352. continue;
  353. /* Add 20ms fuzz so we don't pointlessly spin doing
  354. * <10ms sleeps, particularly on kernels with low HZ
  355. * it is fine that a timer expires 20ms earlier than
  356. * requested
  357. */
  358. if (eventLoop.timeouts[i].expiresAt <= (now+20)) {
  359. virEventTimeoutCallback cb = eventLoop.timeouts[i].cb;
  360. int timer = eventLoop.timeouts[i].timer;
  361. void *opaque = eventLoop.timeouts[i].opaque;
  362. eventLoop.timeouts[i].expiresAt =
  363. now + eventLoop.timeouts[i].frequency;
  364. virMutexUnlock(&eventLoop.lock);
  365. (cb)(timer, opaque);
  366. virMutexLock(&eventLoop.lock);
  367. }
  368. }
  369. return 0;
  370. }
  371. /* Iterate over all file handles and dispatch any which
  372. * have pending events listed in the poll() data. Invoke
  373. * the user supplied callback for each handle which has
  374. * pending events
  375. *
  376. * This method must cope with new handles being registered
  377. * by a callback, and must skip any handles marked as deleted.
  378. *
  379. * Returns 0 upon success, -1 if an error occurred
  380. */
  381. static int virEventPollDispatchHandles(int nfds, struct pollfd *fds) {
  382. int i, n;
  383. VIR_DEBUG("Dispatch %d", nfds);
  384. /* NB, use nfds not eventLoop.handlesCount, because new
  385. * fds might be added on end of list, and they're not
  386. * in the fds array we've got */
  387. for (i = 0, n = 0 ; n < nfds && i < eventLoop.handlesCount ; n++) {
  388. while ((eventLoop.handles[i].fd != fds[n].fd ||
  389. eventLoop.handles[i].events == 0) &&
  390. i < eventLoop.handlesCount) {
  391. i++;
  392. }
  393. if (i == eventLoop.handlesCount)
  394. break;
  395. VIR_DEBUG("i=%d w=%d", i, eventLoop.handles[i].watch);
  396. if (eventLoop.handles[i].deleted) {
  397. EVENT_DEBUG("Skip deleted n=%d w=%d f=%d", i,
  398. eventLoop.handles[i].watch, eventLoop.handles[i].fd);
  399. continue;
  400. }
  401. if (fds[n].revents) {
  402. virEventHandleCallback cb = eventLoop.handles[i].cb;
  403. int watch = eventLoop.handles[i].watch;
  404. void *opaque = eventLoop.handles[i].opaque;
  405. int hEvents = virEventPollFromNativeEvents(fds[n].revents);
  406. EVENT_DEBUG("Dispatch n=%d f=%d w=%d e=%d %p", i,
  407. fds[n].fd, watch, fds[n].revents, opaque);
  408. virMutexUnlock(&eventLoop.lock);
  409. (cb)(watch, fds[n].fd, hEvents, opaque);
  410. virMutexLock(&eventLoop.lock);
  411. }
  412. }
  413. return 0;
  414. }
  415. /* Used post dispatch to actually remove any timers that
  416. * were previously marked as deleted. This asynchronous
  417. * cleanup is needed to make dispatch re-entrant safe.
  418. */
  419. static void virEventPollCleanupTimeouts(void) {
  420. int i;
  421. size_t gap;
  422. VIR_DEBUG("Cleanup %zu", eventLoop.timeoutsCount);
  423. /* Remove deleted entries, shuffling down remaining
  424. * entries as needed to form contiguous series
  425. */
  426. for (i = 0 ; i < eventLoop.timeoutsCount ; ) {
  427. if (!eventLoop.timeouts[i].deleted) {
  428. i++;
  429. continue;
  430. }
  431. EVENT_DEBUG("Purging timeout %d with id %d", i,
  432. eventLoop.timeouts[i].timer);
  433. if (eventLoop.timeouts[i].ff) {
  434. virFreeCallback ff = eventLoop.timeouts[i].ff;
  435. void *opaque = eventLoop.timeouts[i].opaque;
  436. virMutexUnlock(&eventLoop.lock);
  437. ff(opaque);
  438. virMutexLock(&eventLoop.lock);
  439. }
  440. if ((i+1) < eventLoop.timeoutsCount) {
  441. memmove(eventLoop.timeouts+i,
  442. eventLoop.timeouts+i+1,
  443. sizeof(struct virEventPollTimeout)*(eventLoop.timeoutsCount
  444. -(i+1)));
  445. }
  446. eventLoop.timeoutsCount--;
  447. }
  448. /* Release some memory if we've got a big chunk free */
  449. gap = eventLoop.timeoutsAlloc - eventLoop.timeoutsCount;
  450. if (eventLoop.timeoutsCount == 0 ||
  451. (gap > eventLoop.timeoutsCount && gap > EVENT_ALLOC_EXTENT)) {
  452. EVENT_DEBUG("Found %zu out of %zu timeout slots used, releasing %zu",
  453. eventLoop.timeoutsCount, eventLoop.timeoutsAlloc, gap);
  454. VIR_SHRINK_N(eventLoop.timeouts, eventLoop.timeoutsAlloc, gap);
  455. }
  456. }
  457. /* Used post dispatch to actually remove any handles that
  458. * were previously marked as deleted. This asynchronous
  459. * cleanup is needed to make dispatch re-entrant safe.
  460. */
  461. static void virEventPollCleanupHandles(void) {
  462. int i;
  463. size_t gap;
  464. VIR_DEBUG("Cleanup %zu", eventLoop.handlesCount);
  465. /* Remove deleted entries, shuffling down remaining
  466. * entries as needed to form contiguous series
  467. */
  468. for (i = 0 ; i < eventLoop.handlesCount ; ) {
  469. if (!eventLoop.handles[i].deleted) {
  470. i++;
  471. continue;
  472. }
  473. if (eventLoop.handles[i].ff) {
  474. virFreeCallback ff = eventLoop.handles[i].ff;
  475. void *opaque = eventLoop.handles[i].opaque;
  476. virMutexUnlock(&eventLoop.lock);
  477. ff(opaque);
  478. virMutexLock(&eventLoop.lock);
  479. }
  480. if ((i+1) < eventLoop.handlesCount) {
  481. memmove(eventLoop.handles+i,
  482. eventLoop.handles+i+1,
  483. sizeof(struct virEventPollHandle)*(eventLoop.handlesCount
  484. -(i+1)));
  485. }
  486. eventLoop.handlesCount--;
  487. }
  488. /* Release some memory if we've got a big chunk free */
  489. gap = eventLoop.handlesAlloc - eventLoop.handlesCount;
  490. if (eventLoop.handlesCount == 0 ||
  491. (gap > eventLoop.handlesCount && gap > EVENT_ALLOC_EXTENT)) {
  492. EVENT_DEBUG("Found %zu out of %zu handles slots used, releasing %zu",
  493. eventLoop.handlesCount, eventLoop.handlesAlloc, gap);
  494. VIR_SHRINK_N(eventLoop.handles, eventLoop.handlesAlloc, gap);
  495. }
  496. }
  497. /*
  498. * Run a single iteration of the event loop, blocking until
  499. * at least one file handle has an event, or a timer expires
  500. */
  501. int virEventPollRunOnce(void) {
  502. struct pollfd *fds = NULL;
  503. int ret, timeout, nfds;
  504. virMutexLock(&eventLoop.lock);
  505. eventLoop.running = 1;
  506. virThreadSelf(&eventLoop.leader);
  507. virEventPollCleanupTimeouts();
  508. virEventPollCleanupHandles();
  509. if (!(fds = virEventPollMakePollFDs(&nfds)) ||
  510. virEventPollCalculateTimeout(&timeout) < 0)
  511. goto error;
  512. virMutexUnlock(&eventLoop.lock);
  513. retry:
  514. EVENT_DEBUG("Poll on %d handles %p timeout %d", nfds, fds, timeout);
  515. ret = poll(fds, nfds, timeout);
  516. if (ret < 0) {
  517. EVENT_DEBUG("Poll got error event %d", errno);
  518. if (errno == EINTR) {
  519. goto retry;
  520. }
  521. perror("Unable to poll on file handles");
  522. goto error_unlocked;
  523. }
  524. EVENT_DEBUG("Poll got %d event(s)", ret);
  525. virMutexLock(&eventLoop.lock);
  526. if (virEventPollDispatchTimeouts() < 0)
  527. goto error;
  528. if (ret > 0 &&
  529. virEventPollDispatchHandles(nfds, fds) < 0)
  530. goto error;
  531. virEventPollCleanupTimeouts();
  532. virEventPollCleanupHandles();
  533. eventLoop.running = 0;
  534. virMutexUnlock(&eventLoop.lock);
  535. VIR_FREE(fds);
  536. return 0;
  537. error:
  538. virMutexUnlock(&eventLoop.lock);
  539. error_unlocked:
  540. VIR_FREE(fds);
  541. return -1;
  542. }
  543. static void virEventPollHandleWakeup(int watch ATTRIBUTE_UNUSED,
  544. int fd,
  545. int events ATTRIBUTE_UNUSED,
  546. void *opaque ATTRIBUTE_UNUSED)
  547. {
  548. char c;
  549. virMutexLock(&eventLoop.lock);
  550. ignore_value(saferead(fd, &c, sizeof(c)));
  551. virMutexUnlock(&eventLoop.lock);
  552. }
  553. int virEventPollInit(void)
  554. {
  555. if (virMutexInit(&eventLoop.lock) < 0) {
  556. perror("Unable to initialize mutex");
  557. return -1;
  558. }
  559. if (pipe(eventLoop.wakeupfd) < 0 ||
  560. virSetNonBlock(eventLoop.wakeupfd[0]) < 0 ||
  561. virSetNonBlock(eventLoop.wakeupfd[1]) < 0 ||
  562. virSetCloseExec(eventLoop.wakeupfd[0]) < 0 ||
  563. virSetCloseExec(eventLoop.wakeupfd[1]) < 0) {
  564. perror("Unable to setup wakeup pipe");
  565. return -1;
  566. }
  567. if (virEventPollAddHandle(eventLoop.wakeupfd[0],
  568. VIR_EVENT_HANDLE_READABLE,
  569. virEventPollHandleWakeup, NULL, NULL) < 0) {
  570. fprintf(stderr, "Unable to add handle %d to event loop",
  571. eventLoop.wakeupfd[0]);
  572. return -1;
  573. }
  574. return 0;
  575. }
  576. static int virEventPollInterruptLocked(void)
  577. {
  578. char c = '\0';
  579. if (!eventLoop.running ||
  580. virThreadIsSelf(&eventLoop.leader)) {
  581. VIR_DEBUG("Skip interrupt, %d %d", eventLoop.running,
  582. virThreadID(&eventLoop.leader));
  583. return 0;
  584. }
  585. VIR_DEBUG0("Interrupting");
  586. if (safewrite(eventLoop.wakeupfd[1], &c, sizeof(c)) != sizeof(c))
  587. return -1;
  588. return 0;
  589. }
  590. int virEventPollInterrupt(void)
  591. {
  592. int ret;
  593. virMutexLock(&eventLoop.lock);
  594. ret = virEventPollInterruptLocked();
  595. virMutexUnlock(&eventLoop.lock);
  596. return ret;
  597. }
  598. int
  599. virEventPollToNativeEvents(int events)
  600. {
  601. int ret = 0;
  602. if(events & VIR_EVENT_HANDLE_READABLE)
  603. ret |= POLLIN;
  604. if(events & VIR_EVENT_HANDLE_WRITABLE)
  605. ret |= POLLOUT;
  606. if(events & VIR_EVENT_HANDLE_ERROR)
  607. ret |= POLLERR;
  608. if(events & VIR_EVENT_HANDLE_HANGUP)
  609. ret |= POLLHUP;
  610. return ret;
  611. }
  612. int
  613. virEventPollFromNativeEvents(int events)
  614. {
  615. int ret = 0;
  616. if(events & POLLIN)
  617. ret |= VIR_EVENT_HANDLE_READABLE;
  618. if(events & POLLOUT)
  619. ret |= VIR_EVENT_HANDLE_WRITABLE;
  620. if(events & POLLERR)
  621. ret |= VIR_EVENT_HANDLE_ERROR;
  622. if(events & POLLNVAL) /* Treat NVAL as error, since libvirt doesn't distinguish */
  623. ret |= VIR_EVENT_HANDLE_ERROR;
  624. if(events & POLLHUP)
  625. ret |= VIR_EVENT_HANDLE_HANGUP;
  626. return ret;
  627. }