]> Git Repo - qemu.git/blob - async.c
target-arm: Override do_interrupt for ARMv7-M profile
[qemu.git] / async.c
1 /*
2  * QEMU System Emulator
3  *
4  * Copyright (c) 2003-2008 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 #include "qemu-common.h"
26 #include "block/aio.h"
27 #include "qemu/main-loop.h"
28
29 /***********************************************************/
30 /* bottom halves (can be seen as timers which expire ASAP) */
31
32 struct QEMUBH {
33     AioContext *ctx;
34     QEMUBHFunc *cb;
35     void *opaque;
36     QEMUBH *next;
37     bool scheduled;
38     bool idle;
39     bool deleted;
40 };
41
42 QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
43 {
44     QEMUBH *bh;
45     bh = g_malloc0(sizeof(QEMUBH));
46     bh->ctx = ctx;
47     bh->cb = cb;
48     bh->opaque = opaque;
49     bh->next = ctx->first_bh;
50     ctx->first_bh = bh;
51     return bh;
52 }
53
54 int aio_bh_poll(AioContext *ctx)
55 {
56     QEMUBH *bh, **bhp, *next;
57     int ret;
58
59     ctx->walking_bh++;
60
61     ret = 0;
62     for (bh = ctx->first_bh; bh; bh = next) {
63         next = bh->next;
64         if (!bh->deleted && bh->scheduled) {
65             bh->scheduled = 0;
66             if (!bh->idle)
67                 ret = 1;
68             bh->idle = 0;
69             bh->cb(bh->opaque);
70         }
71     }
72
73     ctx->walking_bh--;
74
75     /* remove deleted bhs */
76     if (!ctx->walking_bh) {
77         bhp = &ctx->first_bh;
78         while (*bhp) {
79             bh = *bhp;
80             if (bh->deleted) {
81                 *bhp = bh->next;
82                 g_free(bh);
83             } else {
84                 bhp = &bh->next;
85             }
86         }
87     }
88
89     return ret;
90 }
91
92 void qemu_bh_schedule_idle(QEMUBH *bh)
93 {
94     if (bh->scheduled)
95         return;
96     bh->scheduled = 1;
97     bh->idle = 1;
98 }
99
100 void qemu_bh_schedule(QEMUBH *bh)
101 {
102     if (bh->scheduled)
103         return;
104     bh->scheduled = 1;
105     bh->idle = 0;
106     aio_notify(bh->ctx);
107 }
108
109 void qemu_bh_cancel(QEMUBH *bh)
110 {
111     bh->scheduled = 0;
112 }
113
114 void qemu_bh_delete(QEMUBH *bh)
115 {
116     bh->scheduled = 0;
117     bh->deleted = 1;
118 }
119
120 static gboolean
121 aio_ctx_prepare(GSource *source, gint    *timeout)
122 {
123     AioContext *ctx = (AioContext *) source;
124     QEMUBH *bh;
125
126     for (bh = ctx->first_bh; bh; bh = bh->next) {
127         if (!bh->deleted && bh->scheduled) {
128             if (bh->idle) {
129                 /* idle bottom halves will be polled at least
130                  * every 10ms */
131                 *timeout = 10;
132             } else {
133                 /* non-idle bottom halves will be executed
134                  * immediately */
135                 *timeout = 0;
136                 return true;
137             }
138         }
139     }
140
141     return false;
142 }
143
144 static gboolean
145 aio_ctx_check(GSource *source)
146 {
147     AioContext *ctx = (AioContext *) source;
148     QEMUBH *bh;
149
150     for (bh = ctx->first_bh; bh; bh = bh->next) {
151         if (!bh->deleted && bh->scheduled) {
152             return true;
153         }
154     }
155     return aio_pending(ctx);
156 }
157
158 static gboolean
159 aio_ctx_dispatch(GSource     *source,
160                  GSourceFunc  callback,
161                  gpointer     user_data)
162 {
163     AioContext *ctx = (AioContext *) source;
164
165     assert(callback == NULL);
166     aio_poll(ctx, false);
167     return true;
168 }
169
170 static void
171 aio_ctx_finalize(GSource     *source)
172 {
173     AioContext *ctx = (AioContext *) source;
174
175     aio_set_event_notifier(ctx, &ctx->notifier, NULL, NULL);
176     event_notifier_cleanup(&ctx->notifier);
177     g_array_free(ctx->pollfds, TRUE);
178 }
179
180 static GSourceFuncs aio_source_funcs = {
181     aio_ctx_prepare,
182     aio_ctx_check,
183     aio_ctx_dispatch,
184     aio_ctx_finalize
185 };
186
187 GSource *aio_get_g_source(AioContext *ctx)
188 {
189     g_source_ref(&ctx->source);
190     return &ctx->source;
191 }
192
193 void aio_notify(AioContext *ctx)
194 {
195     event_notifier_set(&ctx->notifier);
196 }
197
198 AioContext *aio_context_new(void)
199 {
200     AioContext *ctx;
201     ctx = (AioContext *) g_source_new(&aio_source_funcs, sizeof(AioContext));
202     ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
203     event_notifier_init(&ctx->notifier, false);
204     aio_set_event_notifier(ctx, &ctx->notifier, 
205                            (EventNotifierHandler *)
206                            event_notifier_test_and_clear, NULL);
207
208     return ctx;
209 }
210
211 void aio_context_ref(AioContext *ctx)
212 {
213     g_source_ref(&ctx->source);
214 }
215
216 void aio_context_unref(AioContext *ctx)
217 {
218     g_source_unref(&ctx->source);
219 }
This page took 0.035685 seconds and 4 git commands to generate.