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