xref: /openbmc/qemu/util/qemu-co-timeout.c (revision e1878eb5)
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