diff options
author | 2012-10-07 17:21:37 +0000 | |
---|---|---|
committer | 2012-10-07 17:21:37 +0000 | |
commit | 81781bd8a48fc0955f9274c7795ddeb919b1198d (patch) | |
tree | 79284aad4800cd4508f8ecf24dbf5b276be3f188 | |
parent | We need to provide a sendmail-like interface to makemap so that some tools (diff) | |
download | wireguard-openbsd-81781bd8a48fc0955f9274c7795ddeb919b1198d.tar.xz wireguard-openbsd-81781bd8a48fc0955f9274c7795ddeb919b1198d.zip |
Implement a simple wait queue API. The idea is to allow multiple "waiters"
to wait on the same "tag" for a deferred result.
A waiter is a callback and a void *argument. The first waiter (the one for
which waitq_wait() returns true) is supposed to run some code that leads to
waitq_run() being run, which will destroy that waitq and call all callbacks
in turn.
Not used at the moment, but will be soon.
ok gilles@ chl@
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 6 | ||||
-rw-r--r-- | usr.sbin/smtpd/waitq.c | 100 |
2 files changed, 105 insertions, 1 deletions
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index 0011942ed9a..d508227392c 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.379 2012/10/07 15:46:38 chl Exp $ */ +/* $OpenBSD: smtpd.h,v 1.380 2012/10/07 17:21:37 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -1170,3 +1170,7 @@ void log_envelope(const struct envelope *, const char *, const char *); void session_socket_blockmode(int, enum blockmodes); void session_socket_no_linger(int); int session_socket_error(int); + +/* waitq.c */ +int waitq_wait(void *, void (*)(void *, void *, void *), void *); +void waitq_run(void *, void *); diff --git a/usr.sbin/smtpd/waitq.c b/usr.sbin/smtpd/waitq.c new file mode 100644 index 00000000000..da6519a6506 --- /dev/null +++ b/usr.sbin/smtpd/waitq.c @@ -0,0 +1,100 @@ +/* $OpenBSD: waitq.c,v 1.1 2012/10/07 17:21:37 eric Exp $ */ + +/* + * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/tree.h> +#include <sys/queue.h> +#include <sys/uio.h> + +#include <imsg.h> +#include <stdio.h> +#include <stdlib.h> + +#include "smtpd.h" + +struct waiter { + TAILQ_ENTRY(waiter) entry; + void (*cb)(void *, void *, void *); + void *arg; +}; + +struct waitq { + SPLAY_ENTRY(waitq) entry; + void *tag; + TAILQ_HEAD(, waiter) waiters; +}; + +static int waitq_cmp(struct waitq *, struct waitq *); + +SPLAY_HEAD(waitqtree, waitq); +SPLAY_PROTOTYPE(waitqtree, waitq, entry, waitq_cmp); + +static struct waitqtree waitqs = SPLAY_INITIALIZER(&waitqs); + +static int +waitq_cmp(struct waitq *a, struct waitq *b) +{ + if (a->tag < b->tag) + return (-1); + if (a->tag > b->tag) + return (1); + return (0); +} + +SPLAY_GENERATE(waitqtree, waitq, entry, waitq_cmp); + +int +waitq_wait(void *tag, void (*cb)(void *, void *, void *), void *arg) +{ + struct waitq *wq, key; + struct waiter *w; + + key.tag = tag; + wq = SPLAY_FIND(waitqtree, &waitqs, &key); + if (wq == NULL) { + wq = xmalloc(sizeof *wq, "waitq_wait"); + wq->tag = tag; + TAILQ_INIT(&wq->waiters); + SPLAY_INSERT(waitqtree, &waitqs, wq); + } + + w = xmalloc(sizeof *w, "waitq_wait"); + w->cb = cb; + w->arg = arg; + TAILQ_INSERT_TAIL(&wq->waiters, w, entry); + + return (w == TAILQ_FIRST(&wq->waiters)); +} + +void +waitq_run(void *tag, void *result) +{ + struct waitq *wq, key; + struct waiter *w; + + key.tag = tag; + wq = SPLAY_FIND(waitqtree, &waitqs, &key); + SPLAY_REMOVE(waitqtree, &waitqs, wq); + + while((w = TAILQ_FIRST(&wq->waiters))) { + TAILQ_REMOVE(&wq->waiters, w, entry); + w->cb(tag, w->arg, result); + free(w); + } + free(wq); +} |