2 Unix SMB/CIFS implementation.
4 Coroutine abstraction for tevent.
6 Copyright (C) Stefan Metzmacher 2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "tevent_coroutine.h"
29 typedef void *coroutine_t;
32 coroutine_t co_create(void (*func)(void *), void *data, void *stack, int size);
33 void co_delete(coroutine_t coro);
34 void co_call(coroutine_t coro);
36 void co_exit_to(coroutine_t coro);
38 coroutine_t co_current(void);
41 struct tevent_coroutine;
43 struct tevent_coroutine_result {
45 TEVENT_COROUTINE_INIT = 0,
46 TEVENT_COROUTINE_IN_PROGRESS,
47 TEVENT_COROUTINE_YIELD,
48 TEVENT_COROUTINE_DONE,
49 TEVENT_COROUTINE_NO_MEMORY,
50 TEVENT_COROUTINE_USER_ERROR
54 const char *return_location;
57 struct tevent_coroutine {
58 struct tevent_req *req;
59 struct tevent_context *ev;
60 const char *create_location;
61 struct tevent_immediate *trigger;
62 tevent_coroutine_fn_t fn;
63 struct tevent_coroutine_result result;
68 static void tevent_coroutine_body(void *data);
70 static void tevent_couroutine_start_callback(struct tevent_context *ctx,
71 struct tevent_immediate *im,
74 struct tevent_coroutine *_tevent_coroutine_create(
75 struct tevent_req *req,
76 struct tevent_context *ev,
77 tevent_coroutine_fn_t fn,
80 void *state = _tevent_req_data(req);
81 struct tevent_coroutine *tco;
83 tco = talloc(state, struct tevent_coroutine);
90 tco->create_location = location;
91 tco->trigger = tevent_create_immediate(tco);
92 if (tco->trigger == NULL) {
97 ZERO_STRUCT(tco->result);
98 tco->coro = co_create(tevent_coroutine_body, tco,
99 tco->stack, sizeof(tco->stack));
100 if (tco->coro == NULL) {
105 tevent_schedule_immediate(tco->trigger,
106 tevent_coroutine_start_callback,
111 static void tevent_coroutine_body(void *data)
113 struct tevent_coroutine *tco = talloc_get_type_abort(data,
114 struct tevent_coroutine);
115 void *fn_state = _tevent_req_data(tco->req);
116 struct tevent_coroutine_result *res;
118 /* now call the real implementation */
119 res = tco->fn(tco, tco->ev, fn_state);
122 * now destroy the coroutine_t handle and jump back to
123 * tevent_coroutine_run() after co_call().
129 static void tevent_coroutine_run(struct tevent_coroutine *tco)
131 coroutine_t cur = co_current();
132 if (tco->coro == cur) {
133 /* this should never happen */
137 tco->result.state = TEVENT_COROUTINE_IN_PROGRESS;
139 * now start or continue the given coroutine
140 * on its own stack. co_call() returns when
141 * the coroutine has called co_resume() (via tevent_coroutine_yield())
142 * or co_exit() (via tevent_coroutine_return()
145 /* now we're back on the original stack */
147 switch (tco->result.state) {
148 case TEVENT_COROUTINE_INIT:
149 case TEVENT_COROUTINE_IN_PROGRESS:
150 /* this should never be reached */
153 case TEVENT_COROUTINE_YIELD:
154 /* we'll resume later */
157 case TEVENT_COROUTINE_DONE:
158 _tevent_req_done(tco->req, tco->result.location);
161 case TEVENT_COROUTINE_NO_MEMORY:
162 _tevent_req_nomem(NULL, tco->req, tco->result.location);
165 case TEVENT_COROUTINE_USER_ERROR:
166 _tevent_req_error(tco->req, tco->result.error,
167 tco->result.location);
171 /* this should never be reached */
175 static void tevent_couroutine_start_callback(struct tevent_context *ctx,
176 struct tevent_immediate *im,
179 struct tevent_coroutine *tco = talloc_get_type_abort(private_data,
180 struct tevent_coroutine);
181 tevent_coroutine_run(tco);
184 static void tevent_coroutine_yield_callback(struct tevent_req *subreq);
186 bool _tevent_coroutine_yield(struct tevent_coroutine *tco,
187 struct tevent_req *subreq,
188 const char *location)
192 ok = _tevent_coroutine_nomem(subreq, tco, location);
197 tco->result.state = TEVENT_COROUTINE_YIELD;
198 tco->result.location = location;
200 tevent_req_set_callback(subreq,
201 tevent_coroutine_yield_callback,
205 * this jumps back to tevent_coroutine_run() after
213 static void tevent_coroutine_yield_callback(struct tevent_req *subreq)
215 struct tevent_coroutine *tco = tevent_req_callback_data(subreq,
216 struct tevent_coroutine);
217 tevent_coroutine_run(tco);
220 void _tevent_coroutine_done(struct tevent_coroutine *tco,
221 const char *location)
223 tco->result.state = TEVENT_COROUTINE_DONE;
224 tco->result.location = location;
227 bool _tevent_coroutine_nomem(const void *ptr,
228 struct tevent_coroutine *tco,
229 const char *location)
235 tco->result.state = TEVENT_COROUTINE_NO_MEMORY;
236 tco->result.location = location;
240 bool _tevent_coroutine_error(struct tevent_coroutine *tco,
242 const char *location)
248 tco->result.state = TEVENT_COROUTINE_USER_ERROR;
249 tco->result.error = error;
250 tco->result.location = location;
254 struct tevent_coroutine_result *_tevent_coroutine_return(
255 struct tevent_coroutine *tco,
256 const char *location)
258 tco->result.return_location = location;