1 /* $OpenBSD: waitq.c,v 1.5 2015/01/20 17:37:54 deraadt 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/socket.h> 21 #include <sys/queue.h> 22 #include <sys/tree.h> 23 #include <sys/uio.h> 24 25 #include <imsg.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <limits.h> 29 30 #include "smtpd.h" 31 32 struct waiter { 33 TAILQ_ENTRY(waiter) entry; 34 void (*cb)(void *, void *, void *); 35 void *arg; 36 }; 37 38 struct waitq { 39 SPLAY_ENTRY(waitq) entry; 40 void *tag; 41 TAILQ_HEAD(, waiter) waiters; 42 }; 43 44 static int waitq_cmp(struct waitq *, struct waitq *); 45 46 SPLAY_HEAD(waitqtree, waitq); 47 SPLAY_PROTOTYPE(waitqtree, waitq, entry, waitq_cmp); 48 49 static struct waitqtree waitqs = SPLAY_INITIALIZER(&waitqs); 50 51 static int 52 waitq_cmp(struct waitq *a, struct waitq *b) 53 { 54 if (a->tag < b->tag) 55 return (-1); 56 if (a->tag > b->tag) 57 return (1); 58 return (0); 59 } 60 61 SPLAY_GENERATE(waitqtree, waitq, entry, waitq_cmp); 62 63 int 64 waitq_wait(void *tag, void (*cb)(void *, void *, void *), void *arg) 65 { 66 struct waitq *wq, key; 67 struct waiter *w; 68 69 key.tag = tag; 70 wq = SPLAY_FIND(waitqtree, &waitqs, &key); 71 if (wq == NULL) { 72 wq = xmalloc(sizeof *wq, "waitq_wait"); 73 wq->tag = tag; 74 TAILQ_INIT(&wq->waiters); 75 SPLAY_INSERT(waitqtree, &waitqs, wq); 76 } 77 78 w = xmalloc(sizeof *w, "waitq_wait"); 79 w->cb = cb; 80 w->arg = arg; 81 TAILQ_INSERT_TAIL(&wq->waiters, w, entry); 82 83 return (w == TAILQ_FIRST(&wq->waiters)); 84 } 85 86 void 87 waitq_run(void *tag, void *result) 88 { 89 struct waitq *wq, key; 90 struct waiter *w; 91 92 key.tag = tag; 93 wq = SPLAY_FIND(waitqtree, &waitqs, &key); 94 SPLAY_REMOVE(waitqtree, &waitqs, wq); 95 96 while ((w = TAILQ_FIRST(&wq->waiters))) { 97 TAILQ_REMOVE(&wq->waiters, w, entry); 98 w->cb(tag, w->arg, result); 99 free(w); 100 } 101 free(wq); 102 } 103