--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ Coroutine abstraction for tevent.
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include <tevent.h>
+#include "tevent_coroutine.h"
+#include <pcl.h>
+
+/*
+
+typedef void *coroutine_t;
+
+
+coroutine_t co_create(void (*func)(void *), void *data, void *stack, int size);
+void co_delete(coroutine_t coro);
+void co_call(coroutine_t coro);
+void co_resume(void);
+void co_exit_to(coroutine_t coro);
+void co_exit(void);
+coroutine_t co_current(void);
+*/
+
+struct tevent_coroutine;
+
+struct tevent_coroutine_result {
+ enum {
+ TEVENT_COROUTINE_INIT = 0,
+ TEVENT_COROUTINE_IN_PROGRESS,
+ TEVENT_COROUTINE_YIELD,
+ TEVENT_COROUTINE_DONE,
+ TEVENT_COROUTINE_NO_MEMORY,
+ TEVENT_COROUTINE_USER_ERROR
+ } state;
+ uint64_t error;
+ const char *location;
+ const char *return_location;
+};
+
+struct tevent_coroutine {
+ struct tevent_req *req;
+ struct tevent_context *ev;
+ const char *create_location;
+ tevent_coroutine_fn_t fn;
+ struct tevent_coroutine_result result;
+ coroutine_t coro;
+ uint8_t stack[4196];
+};
+
+static void tevent_coroutine_body(void *data);
+
+struct tevent_coroutine *_tevent_coroutine_create(
+ struct tevent_req *req,
+ struct tevent_context *ev,
+ tevent_coroutine_fn_t fn,
+ const char *location)
+{
+ void *state = _tevent_req_data(req);
+ struct tevent_coroutine *tco;
+
+ tco = talloc(state, struct tevent_coroutine);
+ if (tco == NULL) {
+ return NULL;
+ }
+
+ tco->req = req;
+ tco->ev = ev;
+ tco->create_location = location;
+ tco->fn = fn;
+ ZERO_STRUCT(tco->result);
+ tco->coro = co_create(tevent_coroutine_body, tco,
+ tco->stack, sizeof(tco->stack));
+ if (tco->coro == NULL) {
+ talloc_free(tco);
+ return NULL;
+ }
+
+ return tco;
+}
+
+static void tevent_coroutine_body(void *data)
+{
+ struct tevent_coroutine *tco = talloc_get_type_abort(data,
+ struct tevent_coroutine);
+ void *fn_state = _tevent_req_data(tco->req);
+ struct tevent_coroutine_result *res;
+
+ /* now call the real implementation */
+ res = tco->fn(tco, tco->ev, fn_state);
+
+ /*
+ * now destroy the coroutine_t handle and jump back to
+ * tevent_coroutine_run() after co_call().
+ */
+ tco->coro = NULL;
+ co_exit();
+}
+
+void tevent_coroutine_run(struct tevent_coroutine *tco)
+{
+ coroutine_t cur = co_current();
+ if (tco->coro == cur) {
+ /* this should never happen */
+ abort();
+ }
+
+ tco->result.state = TEVENT_COROUTINE_IN_PROGRESS;
+ /*
+ * now start or continue the given coroutine
+ * on its own stack. co_call() returns when
+ * the coroutine has called co_resume() (via tevent_coroutine_yield())
+ * or co_exit() (via tevent_coroutine_return()
+ */
+ co_call(tco->coro);
+ /* now we're back on the original stack */
+
+ switch (tco->result.state) {
+ case TEVENT_COROUTINE_INIT:
+ case TEVENT_COROUTINE_IN_PROGRESS:
+ /* this should never be reached */
+ abort();
+
+ case TEVENT_COROUTINE_YIELD:
+ /* we'll resume later */
+ return;
+
+ case TEVENT_COROUTINE_DONE:
+ _tevent_req_done(tco->req, tco->result.location);
+ return;
+
+ case TEVENT_COROUTINE_NO_MEMORY:
+ _tevent_req_nomem(NULL, tco->req, tco->result.location);
+ return;
+
+ case TEVENT_COROUTINE_USER_ERROR:
+ _tevent_req_error(tco->req, tco->result.error,
+ tco->result.location);
+ return;
+ }
+
+ /* this should never be reached */
+ abort();
+}
+
+static void tevent_coroutine_yield_callback(struct tevent_req *subreq);
+
+void _tevent_coroutine_yield(struct tevent_coroutine *tco,
+ struct tevent_req *subreq,
+ const char *location)
+{
+ tco->result.state = TEVENT_COROUTINE_YIELD;
+ tco->result.location = location;
+
+ tevent_req_set_callback(subreq,
+ tevent_coroutine_yield_callback,
+ tco);
+
+ /*
+ * this jumps back to tevent_coroutine_run() after
+ * co_call().
+ */
+ co_resume();
+}
+
+static void tevent_coroutine_yield_callback(struct tevent_req *subreq)
+{
+ struct tevent_coroutine *tco = tevent_req_callback_data(subreq,
+ struct tevent_coroutine);
+ tevent_coroutine_run(tco);
+}
+
+void _tevent_coroutine_done(struct tevent_coroutine *tco,
+ const char *location)
+{
+ tco->result.state = TEVENT_COROUTINE_DONE;
+ tco->result.location = location;
+}
+
+bool _tevent_coroutine_nomem(const void *ptr,
+ struct tevent_coroutine *tco,
+ const char *location)
+{
+ if (ptr != NULL) {
+ return false;
+ }
+
+ tco->result.state = TEVENT_COROUTINE_NO_MEMORY;
+ tco->result.location = location;
+ return true;
+}
+
+bool _tevent_coroutine_error(struct tevent_coroutine *tco,
+ uint64_t error,
+ const char *location)
+{
+ if (error == 0) {
+ return false;
+ }
+
+ tco->result.state = TEVENT_COROUTINE_USER_ERROR;
+ tco->result.error = error;
+ tco->result.location = location;
+ return true;
+}
+
+struct tevent_coroutine_result *_tevent_coroutine_return(
+ struct tevent_coroutine *tco,
+ const char *location)
+{
+ tco->result.return_location = location;
+ return &tco->result;
+}
+
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+
+ Coroutine abstraction for tevent.
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TEVENT_COROUTINE_H_
+#define _TEVENT_COROUTINE_H_
+
+struct tevent_coroutine;
+struct tevent_coroutine_result;
+
+typedef struct tevent_coroutine_result *(*tevent_coroutine_fn_t)(
+ struct tevent_coroutine *co,
+ struct tevent_context *ev,
+ void *private_data);
+
+struct tevent_coroutine *_tevent_coroutine_create(
+ struct tevent_req *req,
+ struct tevent_context *ev,
+ tevent_coroutine_fn_t fn,
+ const char *location);
+#define tevent_coroutine_create(req, ev, fn) \
+ _tevent_coroutine_create(req, ev, fn, __location__)
+
+void tevent_coroutine_run(struct tevent_coroutine *tco);
+
+void _tevent_coroutine_yield(struct tevent_coroutine *tco,
+ struct tevent_req *subreq,
+ const char *location);
+#define tevent_coroutine_yield(tco, subreq) \
+ _tevent_coroutine_yield(tco, subreq, __location__)
+
+void _tevent_coroutine_done(struct tevent_coroutine *tco,
+ const char *location);
+#define tevent_coroutine_done(tco) \
+ _tevent_coroutine_done(tco, __location__) \
+
+bool _tevent_coroutine_nomem(const void *ptr,
+ struct tevent_coroutine *tco,
+ const char *location);
+#define tevent_coroutine_nomem(ptr, tco) \
+ _tevent_coroutine_nomem(ptr, tco, __location__)
+
+bool _tevent_coroutine_error(struct tevent_coroutine *tco,
+ uint64_t error,
+ const char *location);
+#define tevent_coroutine_error(tco, error) \
+ _tevent_coroutine_error(tco, error, __location__)
+
+struct tevent_coroutine_result *_tevent_coroutine_return(
+ struct tevent_coroutine *tco,
+ const char *location);
+#define tevent_coroutine_return(tco) \
+ _tevent_coroutine_return(tco, __location__)
+
+#endif /* _TEVENT_COROUTINE_H_ */
+