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