2
0

qemu-co-timeout.c 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /*
  2. * Helper functionality for distributing a fixed total amount of
  3. * an abstract resource among multiple coroutines.
  4. *
  5. * Copyright (c) 2022 Virtuozzo International GmbH
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. */
  25. #include "qemu/osdep.h"
  26. #include "qemu/coroutine.h"
  27. #include "block/aio.h"
  28. typedef struct QemuCoTimeoutState {
  29. CoroutineEntry *entry;
  30. void *opaque;
  31. QemuCoSleep sleep_state;
  32. bool marker;
  33. CleanupFunc *clean;
  34. } QemuCoTimeoutState;
  35. static void coroutine_fn qemu_co_timeout_entry(void *opaque)
  36. {
  37. QemuCoTimeoutState *s = opaque;
  38. s->entry(s->opaque);
  39. if (s->marker) {
  40. assert(!s->sleep_state.to_wake);
  41. /* .marker set by qemu_co_timeout, it have been failed */
  42. if (s->clean) {
  43. s->clean(s->opaque);
  44. }
  45. g_free(s);
  46. } else {
  47. s->marker = true;
  48. qemu_co_sleep_wake(&s->sleep_state);
  49. }
  50. }
  51. int coroutine_fn qemu_co_timeout(CoroutineEntry *entry, void *opaque,
  52. uint64_t timeout_ns, CleanupFunc clean)
  53. {
  54. QemuCoTimeoutState *s;
  55. Coroutine *co;
  56. if (timeout_ns == 0) {
  57. entry(opaque);
  58. return 0;
  59. }
  60. s = g_new(QemuCoTimeoutState, 1);
  61. *s = (QemuCoTimeoutState) {
  62. .entry = entry,
  63. .opaque = opaque,
  64. .clean = clean
  65. };
  66. co = qemu_coroutine_create(qemu_co_timeout_entry, s);
  67. aio_co_enter(qemu_get_current_aio_context(), co);
  68. qemu_co_sleep_ns_wakeable(&s->sleep_state, QEMU_CLOCK_REALTIME, timeout_ns);
  69. if (s->marker) {
  70. /* .marker set by qemu_co_timeout_entry, success */
  71. g_free(s);
  72. return 0;
  73. }
  74. /* Don't free s, as we can't cancel qemu_co_timeout_entry execution */
  75. s->marker = true;
  76. return -ETIMEDOUT;
  77. }