1 /* $OpenBSD: waitq.c,v 1.4 2013/05/24 17:03:14 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/tree.h> 22 #include <sys/uio.h> 23 24 #include <imsg.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 28 #include "smtpd.h" 29 30 struct waiter { 31 TAILQ_ENTRY(waiter) entry; 32 void (*cb)(void *, void *, void *); 33 void *arg; 34 }; 35 36 struct waitq { 37 SPLAY_ENTRY(waitq) entry; 38 void *tag; 39 TAILQ_HEAD(, waiter) waiters; 40 }; 41 42 static int waitq_cmp(struct waitq *, struct waitq *); 43 44 SPLAY_HEAD(waitqtree, waitq); 45 SPLAY_PROTOTYPE(waitqtree, waitq, entry, waitq_cmp); 46 47 static struct waitqtree waitqs = SPLAY_INITIALIZER(&waitqs); 48 49 static int 50 waitq_cmp(struct waitq *a, struct waitq *b) 51 { 52 if (a->tag < b->tag) 53 return (-1); 54 if (a->tag > b->tag) 55 return (1); 56 return (0); 57 } 58 59 SPLAY_GENERATE(waitqtree, waitq, entry, waitq_cmp); 60 61 int 62 waitq_wait(void *tag, void (*cb)(void *, void *, void *), void *arg) 63 { 64 struct waitq *wq, key; 65 struct waiter *w; 66 67 key.tag = tag; 68 wq = SPLAY_FIND(waitqtree, &waitqs, &key); 69 if (wq == NULL) { 70 wq = xmalloc(sizeof *wq, "waitq_wait"); 71 wq->tag = tag; 72 TAILQ_INIT(&wq->waiters); 73 SPLAY_INSERT(waitqtree, &waitqs, wq); 74 } 75 76 w = xmalloc(sizeof *w, "waitq_wait"); 77 w->cb = cb; 78 w->arg = arg; 79 TAILQ_INSERT_TAIL(&wq->waiters, w, entry); 80 81 return (w == TAILQ_FIRST(&wq->waiters)); 82 } 83 84 void 85 waitq_run(void *tag, void *result) 86 { 87 struct waitq *wq, key; 88 struct waiter *w; 89 90 key.tag = tag; 91 wq = SPLAY_FIND(waitqtree, &waitqs, &key); 92 SPLAY_REMOVE(waitqtree, &waitqs, wq); 93 94 while ((w = TAILQ_FIRST(&wq->waiters))) { 95 TAILQ_REMOVE(&wq->waiters, w, entry); 96 w->cb(tag, w->arg, result); 97 free(w); 98 } 99 free(wq); 100 } 101