4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
32 /* ********************************************************************** */
33 /* * General-Purpose Event List Manager * */
34 /* ********************************************************************** */
36 * description: These routines maintain a time-ordered list of events.
37 * functions available:
38 * init : Creates and initializes the data structure.
39 * See the reference for parameters to init.
40 * add(&event, time, id) : Adds an event to the list.
41 * Returns: 0 if success,
42 * -2 if event time is lower
43 * than Lower Bound time LB
45 * remove(id) : Removes events (with appropriate id).
46 * empty : Returns true if the list is empty, false otherwise.
47 * first : Removes the element at the head of the list.
48 * Returns a pointer to the event.
49 * delete : Frees up all allocated storage associated
50 * with the event list.
51 * reference: Franta, W. R. and Maly, K.,
52 * "An efficient data structure for the
53 * simulation event set ", CACM Vol. 20(8),
54 * Aug 1977, pp. 596-602.
55 * machine dependant: the constant INFINITY
57 /* ********************************************************************** */
60 #include <sys/types.h>
63 extern void *xmalloc(size_t);
65 #define INFINITY 2147483647L /* upper bound on time */
69 /* the following parameters are set in init */
70 static int DU
; /* number of time intervals */
71 static time_t LB
; /* lower bound on time */
72 static time_t DT
; /* width of interval */
73 static int NLIM
; /* max notices per sublist */
76 * a notice points to an event. a notice has the following fields:
77 * time = time of the event.
78 * id = identifier for an event or class of events that may need
79 * to be removed (other than at the front of the list).
80 * event = pointer to the event.
81 * isdummy = tells whether this notice points to a real event or
82 * is just a dummy notice (one that is used to "mark off"
83 * the time intervals that the user specifies in init).
84 * key = points back to the key that points to this notice,
86 * left = points to the notice immediately preceding this one.
87 * right = points to the notice immediately following this one.
89 struct notice
{ time_t time
;
95 struct notice
*right
; };
97 /* current points to the front of the list of notices (events) */
98 struct notice
*current
= NULL
;
101 * a key points to a sublist of notices. a key has the following fields:
102 * time = max time of notices in sublist.
103 * numnote = number of notices in sublist.
104 * notice = pointer to the notice with max time.
105 * left = points to the key immediately preceding this one.
106 * right = points to the key immediately following this one.
108 struct key
{ time_t time
;
110 struct notice
*notice
;
112 struct key
*right
; };
115 * the index list breaks the keys into time intervals as specified in init.
116 * the index is "shifted" one time interval whenever el_first returns an
117 * event with a time greater than the max time of the first interval
118 * (eg. with intervals of a day which span one week (MTWTFSS),
119 * if el_first finds the next event is on tuesday, then
120 * the intervals of the event list get shifted (TWTFSSM).
122 struct index
{ struct key
*key
;
123 struct index
*right
; };
125 /* index pts to the front of the index list */
126 static struct index
*index
= NULL
;
128 /* ******************* */
130 el_init(du
, lb
, dt
, nlim
)
131 /* ******************* */
137 struct index
*indprev
, *ind
;
138 struct key
*kprev
, *k
;
139 struct notice
*nprev
, *n
;
141 if ((du
< 1) || (dt
< 1) || (nlim
< 1))
149 * initialize index, keys, and notices
152 /* create first dummy notice */
153 n
= (struct notice
*)xmalloc(sizeof (struct notice
));
158 /* create first dummy key */
159 k
= (struct key
*)xmalloc(sizeof (struct key
));
165 /* make notice point to key */
167 /* no index element to allocate this time */
169 /* create dummy notices, dummy keys, and index elements */
171 for (i
= 1; i
< DU
; i
++) {
173 n
= (struct notice
*)xmalloc(sizeof (struct notice
));
179 k
= (struct key
*)xmalloc(sizeof (struct key
));
187 ind
= (struct index
*)xmalloc(sizeof (struct index
));
192 indprev
->right
= ind
;
194 /* create last dummy notice */
195 n
= (struct notice
*)xmalloc(sizeof (struct notice
));
201 /* create last dummy key */
202 k
= (struct key
*)xmalloc(sizeof (struct key
));
210 /* create last index element */
211 ind
= (struct index
*)xmalloc(sizeof (struct index
));
214 indprev
->right
= ind
;
220 /* ********************** */
222 el_add(event
, time
, id
)
223 /* ********************** */
229 * add works slightly differently than in the reference. if the
230 * sublist to be inserted into is full (numnote = NLIM),
231 * the sublist is split in half. thus the size of the sublists
232 * in this implementation normally ranges from NLIM/2 to NLIM.
237 struct notice
*n
, *n2
;
241 * time may be 0 when set by next_time() on error or an
242 * invalid time specification of job
244 if ((index
== NULL
) || (time
<= 0)) {
251 /* allocate new notice */
252 n
= (struct notice
*)xmalloc(sizeof (struct notice
));
259 /* find the right interval */
261 while ((ind
->key
)->time
<= time
) ind
= ind
->right
;
263 /* find the right key */
264 k
= (ind
->key
)->left
;
265 while (k
->time
> time
) k
= k
->left
;
268 /* (k->time>time) and ((k->left)->time<=time) */
269 if (k
->numnote
== NLIM
) {
270 /* k's sublist is full, so split it */
271 k
->numnote
= NLIM
/ 2;
273 for (i
= 1; i
<= NLIM
/2; i
++) n2
= n2
->left
;
274 /* create a key which will point to notice n2 */
275 k2
= (struct key
*)xmalloc(sizeof (struct key
));
277 k2
->numnote
= NLIM
- NLIM
/2;
282 (k2
->left
)->right
= k2
;
283 n2
->key
= k2
; /* have n2 point back to k2 */
284 /* which of the new sublists will hold the new notice? */
285 if (k2
->time
> time
) k
= k2
; }
288 * the new notice n is ready to be inserted
289 * k points to the appropriate sublist
291 k
->numnote
= k
->numnote
+ 1;
293 while (n2
->time
> time
) n2
= n2
->left
;
294 n
->right
= n2
->right
;
296 (n2
->right
)->left
= n
;
299 if ((current
== NULL
) || (current
->time
> time
))
306 /* ******************** */
309 /* ******************** */
313 * remove finds notices n that need to be removed by traversing thru
314 * the notice list. if n is the sole element of a sublist, the
315 * sublist is deleted. if not, an adjacent sublist is merged with
316 * n's sublist, if that is possible. after these checks, n is removed.
319 struct notice
*n
, *n2
;
320 struct key
*k
, *kl
, *kr
;
322 if ((index
== NULL
) || (current
== NULL
))
327 while ((n
!= NULL
) && ((n
->isdummy
) || (n
->id
!= id
)))
330 /* n should be deleted */
331 if ((n
->key
!= NULL
) && ((n
->key
)->numnote
== 1)) {
332 /* n = sole element of a sublist */
334 (k
->left
)->right
= k
->right
;
335 (k
->right
)->left
= k
->left
;
337 } else { if (n
->key
!= NULL
) {
338 /* n has a key pointing to it */
339 (n
->left
)->key
= n
->key
;
340 (n
->key
)->time
= (n
->left
)->time
;
341 (n
->key
)->notice
= n
->left
; }
342 /* find the key that points to this sublist */
344 while (n2
->key
== NULL
) n2
= n2
->right
;
346 k
->numnote
= k
->numnote
- 1;
348 * check if two adjacent sublists can be merged
349 * first check left, then check right
353 if ((!(kl
->notice
)->isdummy
) &&
354 ((kl
->numnote
+k
->numnote
) <= NLIM
)) {
355 /* delete the key to the left */
356 (kl
->notice
)->key
= NULL
;
357 k
->numnote
+= kl
->numnote
;
358 (kl
->left
)->right
= k
;
361 } else if ((!(k
->notice
)->isdummy
) &&
362 ((kr
->numnote
+k
->numnote
)
364 /* delete this key */
365 (k
->notice
)->key
= NULL
;
366 kr
->numnote
+= k
->numnote
;
367 (k
->left
)->right
= kr
;
371 /* delete n, then advance n down the list */
372 (n
->left
)->right
= n
->right
;
373 (n
->right
)->left
= n
->left
;
380 /* now reset current */
381 k
= (index
->key
)->left
;
382 while (k
->left
!= NULL
) k
= k
->left
;
383 n
= (k
->notice
)->right
;
384 while ((n
!= NULL
) && (n
->isdummy
)) n
= n
->right
;
389 /* ********************* */
392 /* ********************* */
401 /* ********************* */
404 /* ********************* */
406 struct notice
*n
, *fn
;
408 struct index
*ind
, *fi
;
412 if ((index
== NULL
) || (current
== NULL
))
415 while ((index
->key
)->time
< current
->time
) {
417 /* only two intervals, so relabel first one */
420 (k
->notice
)->time
+= DT
;
423 * remove the notice, key, and index corresponding
424 * to the first time interval. Then split the
425 * overflow interval into a normal interval
426 * plus an overflow interval.
431 (fn
->left
)->right
= fn
->right
;
432 (fn
->right
)->left
= fn
->left
;
433 (fk
->left
)->right
= fk
->right
;
434 (fk
->right
)->left
= fk
->left
;
435 index
= index
->right
;
436 /* find where to split */
438 while ((ind
->right
)->right
!= NULL
) ind
= ind
->right
;
439 /* ind points to the next to last index interval */
441 next_int
= k
->time
+ DT
; /* upper bound on new inter. */
442 while (k
->time
< next_int
) k
= k
->right
;
443 /* k points to the appropriate sublist of notices */
444 n
= (k
->notice
)->left
;
446 while (n
->time
>= next_int
) {
451 * n points to first notice of the new overflow interval
452 * ctr tells how many notices are in the first sublist
453 * of the new overflow interval
454 * insert the new index element
456 fi
->right
= ind
->right
;
458 /* insert the new dummy key */
460 fk
->numnote
= k
->numnote
- ctr
+ 1;
463 (k
->left
)->right
= fk
;
466 /* insert the new dummy notice */
470 (n
->left
)->right
= fn
;
473 /* remove the first element of the list */
474 (current
->left
)->right
= current
->right
;
475 (current
->right
)->left
= current
->left
;
476 /* now update the numnote field in the appropriate key */
478 while (n
->key
== NULL
) n
= n
->right
;
480 k
->numnote
= k
->numnote
- 1;
481 /* if numnote = 0 then this key must be removed */
482 if (k
->numnote
== 0) {
483 (k
->left
)->right
= k
->right
;
484 (k
->right
)->left
= k
->left
;
487 /* now set current to be the head of the list */
489 while ((fn
!= NULL
) && (fn
->isdummy
))
491 val
= current
->event
;
504 /* el_delete frees up all the space associated with the event list */
506 struct index
*ind
, *ind2
;
508 struct notice
*n
, *n2
;
514 while (k
->left
!= NULL
) k
= k
->left
;
524 while (ind
!= NULL
) {