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