1 /*
2  * Copyright 2003 by Sun Microsystems, Inc. All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 1996-1999 by Internet Software Consortium
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
14  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
16  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
17  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20  * SOFTWARE.
21  */
22 
23 #pragma ident	"%Z%%M%	%I%	%E% SMI"
24 
25 /* ev_waits.c - implement deferred function calls for the eventlib
26  * vix 05dec95 [initial]
27  */
28 
29 #if !defined(LINT) && !defined(CODECENTER)
30 static const char rcsid[] = "$Id: ev_waits.c,v 8.12 2002/07/08 05:50:10 marka Exp $";
31 #endif
32 
33 #include "port_before.h"
34 #include "fd_setsize.h"
35 
36 #include <errno.h>
37 
38 #include <isc/eventlib.h>
39 #include <isc/assertions.h>
40 #include "eventlib_p.h"
41 
42 #include "port_after.h"
43 
44 /* Forward. */
45 
46 static void		print_waits(evContext_p *ctx);
47 static evWaitList *	evNewWaitList(evContext_p *);
48 static void		evFreeWaitList(evContext_p *, evWaitList *);
49 static evWaitList *	evGetWaitList(evContext_p *, const void *, int);
50 
51 
52 /* Public. */
53 
54 /*
55  * Enter a new wait function on the queue.
56  */
57 int
58 evWaitFor(evContext opaqueCtx, const void *tag,
59 	  evWaitFunc func, void *uap, evWaitID *id)
60 {
61 	evContext_p *ctx = opaqueCtx.opaque;
62 	evWait *new;
63 	evWaitList *wl = evGetWaitList(ctx, tag, 1);
64 
65 	OKNEW(new);
66 	new->func = func;
67 	new->uap = uap;
68 	new->tag = tag;
69 	new->next = NULL;
70 	if (wl->last != NULL)
71 		wl->last->next = new;
72 	else
73 		wl->first = new;
74 	wl->last = new;
75 	if (id != NULL)
76 		id->opaque = new;
77 	if (ctx->debug >= 9)
78 		print_waits(ctx);
79 	return (0);
80 }
81 
82 /*
83  * Mark runnable all waiting functions having a certain tag.
84  */
85 int
86 evDo(evContext opaqueCtx, const void *tag) {
87 	evContext_p *ctx = opaqueCtx.opaque;
88 	evWaitList *wl = evGetWaitList(ctx, tag, 0);
89 	evWait *first;
90 
91 	if (!wl) {
92 		errno = ENOENT;
93 		return (-1);
94 	}
95 
96 	first = wl->first;
97 	INSIST(first != NULL);
98 
99 	if (ctx->waitDone.last != NULL)
100 		ctx->waitDone.last->next = first;
101 	else
102 		ctx->waitDone.first = first;
103 	ctx->waitDone.last = wl->last;
104 	evFreeWaitList(ctx, wl);
105 
106 	return (0);
107 }
108 
109 /*
110  * Remove a waiting (or ready to run) function from the queue.
111  */
112 int
113 evUnwait(evContext opaqueCtx, evWaitID id) {
114 	evContext_p *ctx = opaqueCtx.opaque;
115 	evWait *this, *prev;
116 	evWaitList *wl;
117 	int found = 0;
118 
119 	this = id.opaque;
120 	INSIST(this != NULL);
121 	wl = evGetWaitList(ctx, this->tag, 0);
122 	if (wl != NULL) {
123 		for (prev = NULL, this = wl->first;
124 		     this != NULL;
125 		     prev = this, this = this->next)
126 			if (this == (evWait *)id.opaque) {
127 				found = 1;
128 				if (prev != NULL)
129 					prev->next = this->next;
130 				else
131 					wl->first = this->next;
132 				if (wl->last == this)
133 					wl->last = prev;
134 				if (wl->first == NULL)
135 					evFreeWaitList(ctx, wl);
136 				break;
137 			}
138 	}
139 
140 	if (!found) {
141 		/* Maybe it's done */
142 		for (prev = NULL, this = ctx->waitDone.first;
143 		     this != NULL;
144 		     prev = this, this = this->next)
145 			if (this == (evWait *)id.opaque) {
146 				found = 1;
147 				if (prev != NULL)
148 					prev->next = this->next;
149 				else
150 					ctx->waitDone.first = this->next;
151 				if (ctx->waitDone.last == this)
152 					ctx->waitDone.last = prev;
153 				break;
154 			}
155 	}
156 
157 	if (!found) {
158 		errno = ENOENT;
159 		return (-1);
160 	}
161 
162 	FREE(this);
163 
164 	if (ctx->debug >= 9)
165 		print_waits(ctx);
166 
167 	return (0);
168 }
169 
170 int
171 evDefer(evContext opaqueCtx, evWaitFunc func, void *uap) {
172 	evContext_p *ctx = opaqueCtx.opaque;
173 	evWait *new;
174 
175 	OKNEW(new);
176 	new->func = func;
177 	new->uap = uap;
178 	new->tag = NULL;
179 	new->next = NULL;
180 	if (ctx->waitDone.last != NULL)
181 		ctx->waitDone.last->next = new;
182 	else
183 		ctx->waitDone.first = new;
184 	ctx->waitDone.last = new;
185 	if (ctx->debug >= 9)
186 		print_waits(ctx);
187 	return (0);
188 }
189 
190 /* Private. */
191 
192 static void
193 print_waits(evContext_p *ctx) {
194 	evWaitList *wl;
195 	evWait *this;
196 
197 	evPrintf(ctx, 9, "wait waiting:\n");
198 	for (wl = ctx->waitLists; wl != NULL; wl = wl->next) {
199 		INSIST(wl->first != NULL);
200 		evPrintf(ctx, 9, "  tag %p:", wl->first->tag);
201 		for (this = wl->first; this != NULL; this = this->next)
202 			evPrintf(ctx, 9, " %p", this);
203 		evPrintf(ctx, 9, "\n");
204 	}
205 	evPrintf(ctx, 9, "wait done:");
206 	for (this = ctx->waitDone.first; this != NULL; this = this->next)
207 		evPrintf(ctx, 9, " %p", this);
208 	evPrintf(ctx, 9, "\n");
209 }
210 
211 static evWaitList *
212 evNewWaitList(evContext_p *ctx) {
213 	evWaitList *new;
214 
215 	NEW(new);
216 	if (new == NULL)
217 		return (NULL);
218 	new->first = new->last = NULL;
219 	new->prev = NULL;
220 	new->next = ctx->waitLists;
221 	if (new->next != NULL)
222 		new->next->prev = new;
223 	ctx->waitLists = new;
224 	return (new);
225 }
226 
227 static void
228 evFreeWaitList(evContext_p *ctx, evWaitList *this) {
229 
230 	INSIST(this != NULL);
231 
232 	if (this->prev != NULL)
233 		this->prev->next = this->next;
234 	else
235 		ctx->waitLists = this->next;
236 	if (this->next != NULL)
237 		this->next->prev = this->prev;
238 	FREE(this);
239 }
240 
241 static evWaitList *
242 evGetWaitList(evContext_p *ctx, const void *tag, int should_create) {
243 	evWaitList *this;
244 
245 	for (this = ctx->waitLists; this != NULL; this = this->next) {
246 		if (this->first != NULL && this->first->tag == tag)
247 			break;
248 	}
249 	if (this == NULL && should_create)
250 		this = evNewWaitList(ctx);
251 	return (this);
252 }
253