1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 /************************************************************************** 35 *** General-Purpose Event List Manager *** 36 ************************************************************************** 37 38 description: These routines maintain a time-ordered list of events. 39 functions available: 40 init : Creates and initializes the data structure. 41 See the reference for parameters to init. 42 add(&event,time,id) : Adds an event to the list. 43 remove(id) : Removes events (with appropriate id). 44 empty : Returns true if the list is empty, false otherwise. 45 first : Removes the element at the head of the list. 46 Returns a pointer to the event. 47 delete : Frees up all allocated storage associated 48 with the event list. 49 reference: Franta, W. R. and Maly, K., 50 "An efficient data structure for the 51 simulation event set ", CACM Vol. 20(8), 52 Aug 1977, pp. 596-602. 53 machine dependant: the constant INFINITY 54 55 *************************************************************************/ 56 57 58 #include <sys/types.h> 59 #include <stdlib.h> 60 61 extern void *xmalloc(size_t); 62 63 #define INFINITY 2147483647L /* upper bound on time */ 64 #define NULL 0 /* a null pointer */ 65 #define TRUE 1 66 #define FALSE 0 67 68 /* the following parameters are set in init */ 69 static int DU; /* number of time intervals */ 70 static time_t LB; /* lower bound on time */ 71 static time_t DT; /* width of interval */ 72 static int NLIM; /* max notices per sublist */ 73 74 /* a notice points to an event. a notice has the following fields: 75 time = time of the event. 76 id = identifier for an event or class of events that may need 77 to be removed (other than at the front of the list). 78 event = pointer to the event. 79 isdummy = tells whether this notice points to a real event or 80 is just a dummy notice (one that is used to "mark off" 81 the time intervals that the user specifies in init). 82 key = points back to the key that points to this notice, 83 if there is one. 84 left = points to the notice immediately preceding this one. 85 right = points to the notice immediately following this one. */ 86 struct notice { time_t time; 87 int id; 88 void *event; 89 short int isdummy; 90 struct key *key; 91 struct notice *left; 92 struct notice *right; }; 93 94 /* current points to the front of the list of notices (events) */ 95 struct notice *current=NULL; 96 97 /* a key points to a sublist of notices. a key has the following fields: 98 time = max time of notices in sublist. 99 numnote = number of notices in sublist. 100 notice = pointer to the notice with max time. 101 left = points to the key immediately preceding this one. 102 right = points to the key immediately following this one. */ 103 struct key { time_t time; 104 int numnote; 105 struct notice *notice; 106 struct key *left; 107 struct key *right; }; 108 109 /* the index list breaks the keys into time intervals as specified in init. 110 the index is "shifted" one time interval whenever el_first returns an 111 event with a time greater than the max time of the first interval 112 (eg. with intervals of a day which span one week (MTWTFSS), 113 if el_first finds the next event is on tuesday, then 114 the intervals of the event list get shifted (TWTFSSM). */ 115 struct index { struct key *key; 116 struct index *right; }; 117 118 static struct index *index=NULL; /* index pts to the front of the index list */ 119 120 /***********************/ 121 void 122 el_init(du,lb,dt,nlim) 123 /***********************/ 124 int du, nlim; 125 time_t lb, dt; 126 { 127 int i; 128 time_t t; 129 struct index *indprev,*ind; 130 struct key *kprev, *k; 131 struct notice *nprev, *n; 132 133 if ((du<1) || (dt<1) || (nlim<1)) return; 134 DU = du + 1; 135 LB = lb; 136 DT = dt; 137 NLIM = nlim; 138 139 /* 140 * initialize index, keys, and notices 141 */ 142 143 /* create first dummy notice */ 144 n= (struct notice *) xmalloc(sizeof(struct notice)); 145 n->time = LB; 146 n->isdummy = TRUE; 147 n->left = NULL; 148 nprev = n; 149 /* create first dummy key */ 150 k= (struct key *) xmalloc(sizeof(struct key)); 151 k->time = LB; 152 k->numnote = 1; 153 k->notice = n; 154 k->left = NULL; 155 kprev = k; 156 /* make notice point to key */ 157 n->key = k; 158 /* no index element to allocate this time */ 159 indprev = NULL; 160 /* create dummy notices, dummy keys, and index elements */ 161 t = LB; 162 for (i=1; i<DU; i++) { 163 t = t + DT; 164 n = (struct notice *) xmalloc(sizeof(struct notice)); 165 n->time = t; 166 n->isdummy = TRUE; 167 n->left = nprev; 168 nprev->right = n; 169 nprev = n; 170 k = (struct key *) xmalloc(sizeof(struct key)); 171 k->time = t; 172 k->numnote = 1; 173 k->notice = n; 174 k->left = kprev; 175 kprev->right = k; 176 kprev = k; 177 n->key = k; 178 ind = (struct index *) xmalloc(sizeof(struct index)); 179 ind->key = k; 180 if (indprev == NULL) index = ind; 181 else indprev->right = ind; 182 indprev = ind; } 183 /* create last dummy notice */ 184 n = (struct notice *) xmalloc(sizeof(struct notice)); 185 n->time = INFINITY; 186 n->isdummy = TRUE; 187 n->left = nprev; 188 n->right = NULL; 189 nprev->right = n; 190 /* create last dummy key */ 191 k = (struct key *) xmalloc(sizeof(struct key)); 192 k->time = INFINITY; 193 k->numnote = 1; 194 k->notice = n; 195 k->left = kprev; 196 k->right = NULL; 197 kprev->right = k; 198 n->key = k; 199 /* create last index element */ 200 ind = (struct index *) xmalloc(sizeof(struct index)); 201 ind->key = k; 202 ind->right = NULL; 203 indprev->right = ind; 204 205 current = NULL; 206 } 207 208 209 /**************************/ 210 void 211 el_add(event,time,id) 212 /**************************/ 213 void *event; 214 int id; 215 time_t time; 216 { 217 /* add works slightly differently than in the reference. if the 218 sublist to be inserted into is full (numnote = NLIM), 219 the sublist is split in half. thus the size of the sublists 220 in this implementation normally ranges from NLIM/2 to NLIM. */ 221 222 struct index *ind; 223 struct key *k,*k2; 224 struct notice *n,*n2; 225 int i; 226 227 if ((index==NULL) || (time<LB)) return; 228 229 /* allocate new notice */ 230 n = (struct notice *) xmalloc(sizeof(struct notice)); 231 n->time = time; 232 n->id = id; 233 n->event = event; 234 n->isdummy = FALSE; 235 n->key = NULL; 236 237 /* find the right interval */ 238 ind = index; 239 while ((ind->key)->time <= time) ind = ind->right; 240 241 /* find the right key */ 242 k = (ind->key)->left; 243 while (k->time > time) k = k->left; 244 k = k->right; 245 246 /* (k->time>time) and ((k->left)->time<=time) */ 247 if (k->numnote == NLIM) { 248 /* k's sublist is full, so split it */ 249 k->numnote = NLIM / 2; 250 n2 = k->notice; 251 for (i=1; i<=NLIM/2; i++) n2 = n2->left; 252 /* create a key which will point to notice n2 */ 253 k2 = (struct key *) xmalloc(sizeof(struct key)); 254 k2->time = n2->time; 255 k2->numnote = NLIM - NLIM/2; 256 k2->notice = n2; 257 k2->right = k; 258 k2->left = k->left; 259 k->left = k2; 260 (k2->left)->right = k2; 261 n2->key = k2; /* have n2 point back to k2 */ 262 /* which of the new sublists will hold the new notice? */ 263 if (k2->time > time) k = k2; } 264 265 /* the new notice n is ready to be inserted 266 k points to the appropriate sublist */ 267 k->numnote = k->numnote + 1; 268 n2 = k->notice; 269 while (n2->time > time) n2 = n2->left; 270 n->right = n2->right; 271 n->left = n2; 272 (n2->right)->left = n; 273 n2->right = n; 274 275 if ( (current == NULL) || (current->time > time) ) current = n; 276 } 277 278 279 /************************/ 280 void 281 el_remove(id,flag) 282 /************************/ 283 int id,flag; 284 { 285 /* remove finds notices n that need to be removed by traversing thru 286 the notice list. if n is the sole element of a sublist, the 287 sublist is deleted. if not, an adjacent sublist is merged with 288 n's sublist, if that is possible. after these checks, n is removed. */ 289 290 struct notice *n,*n2; 291 struct key *k,*kl,*kr; 292 293 if ((index==NULL) || (current==NULL)) return; 294 295 n = current; 296 while ( n != NULL) { 297 while ( (n!=NULL) && ((n->isdummy)||(n->id!=id)) ) n = n->right; 298 if (n != NULL) { 299 /* n should be deleted */ 300 if ( (n->key!=NULL) && ((n->key)->numnote==1) ) { 301 /* n = sole element of a sublist */ 302 k = n->key; 303 (k->left)->right = k->right; 304 (k->right)->left = k->left; 305 free(k); } 306 else { if (n->key != NULL) { 307 /* n has a key pointing to it */ 308 (n->left)->key = n->key; 309 (n->key)->time = (n->left)->time; 310 (n->key)->notice = n->left; } 311 /* find the key that points to this sublist */ 312 n2 = n; 313 while (n2->key == NULL) n2 = n2->right; 314 k = n2->key; 315 k->numnote = k->numnote - 1; 316 /* check if two adjacent sublists can be merged 317 first check left, then check right */ 318 kl = k->left; 319 kr = k->right; 320 if ( (!(kl->notice)->isdummy) && 321 ((kl->numnote+k->numnote)<=NLIM) ) { 322 /* delete the key to the left */ 323 (kl->notice)->key = NULL; 324 k->numnote += kl->numnote; 325 (kl->left)->right = k; 326 k->left = kl->left; 327 free(kl); } 328 else if ( (!(k->notice)->isdummy) && 329 ((kr->numnote+k->numnote)<=NLIM) ) { 330 /* delete this key */ 331 (k->notice)->key = NULL; 332 kr->numnote += k->numnote; 333 (k->left)->right = kr; 334 kr->left = k->left; 335 free(k); } 336 } 337 /* delete n, then advance n down the list */ 338 (n->left)->right = n->right; 339 (n->right)->left = n->left; 340 n2 = n->right; 341 free(n); 342 n = n2; 343 } 344 if (flag) break; 345 } 346 /* now reset current */ 347 k = (index->key)->left; 348 while (k->left != NULL) k = k->left; 349 n = (k->notice)->right; 350 while ((n!=NULL) && (n->isdummy)) n = n->right; 351 current = n; 352 } 353 354 355 /*************************/ 356 int 357 el_empty(void) 358 /*************************/ 359 { 360 if (current == NULL) return(1); 361 else return(0); 362 } 363 364 365 /*************************/ 366 void * 367 el_first(void) 368 /*************************/ 369 { 370 struct notice *n,*fn; 371 struct key *k,*fk; 372 struct index *ind,*fi; 373 int ctr,*val; 374 time_t next_int; 375 376 if ((index==NULL) || (current==NULL)) return(NULL); 377 378 while ((index->key)->time < current->time) { 379 if (DU == 2) { 380 /* only two intervals, so relabel first one */ 381 k = index->key; 382 k->time += DT; 383 (k->notice)->time += DT; 384 continue; } 385 /* remove the notice, key, and index corresponding 386 to the first time interval. Then split the 387 overflow interval into a normal interval 388 plus an overflow interval. */ 389 fi = index; 390 fk = fi->key; 391 fn = fk->notice; 392 (fn->left)->right = fn->right; 393 (fn->right)->left = fn->left; 394 (fk->left)->right = fk->right; 395 (fk->right)->left = fk->left; 396 index = index->right; 397 /* find where to split */ 398 ind = index; 399 while ((ind->right)->right != NULL) ind = ind->right; 400 /* ind points to the next to last index interval */ 401 k = ind->key; 402 next_int = k->time + DT; /* upper bound on new inter. */ 403 while (k->time < next_int) k = k->right; 404 /* k points to the appropriate sublist of notices */ 405 n = (k->notice)->left; 406 ctr = 1; 407 while (n->time >= next_int) { 408 ctr++; 409 n = n->left; } 410 n = n->right; 411 /* n points to first notice of the new overflow interval 412 ctr tells how many notices are in the first sublist 413 of the new overflow interval 414 insert the new index element */ 415 fi->right = ind->right; 416 ind->right = fi; 417 /* insert the new dummy key */ 418 fk->time = next_int; 419 fk->numnote = k->numnote - ctr + 1; 420 fk->left = k->left; 421 fk->right = k; 422 (k->left)->right = fk; 423 k->left = fk; 424 k->numnote = ctr; 425 /* insert the new dummy notice */ 426 fn->time = next_int; 427 fn->left = n->left; 428 fn->right = n; 429 (n->left)->right = fn; 430 n->left = fn; } 431 432 /* remove the first element of the list */ 433 (current->left)->right = current->right; 434 (current->right)->left = current->left; 435 /* now update the numnote field in the appropriate key */ 436 n = current; 437 while ( n->key == NULL ) n = n->right; 438 k = n->key; 439 k->numnote = k->numnote - 1; 440 /* if numnote = 0 then this key must be removed */ 441 if (k->numnote == 0) { 442 (k->left)->right = k->right; 443 (k->right)->left = k->left; 444 free(k); } 445 446 /* now set current to be the head of the list */ 447 fn = current->right; 448 while ( (fn != NULL) && (fn->isdummy) ) 449 fn = fn->right; 450 val = current->event; 451 free(current); 452 current = fn; 453 454 return(val); 455 } 456 457 458 /******************/ 459 void 460 el_delete(void) 461 /******************/ 462 { 463 /* el_delete frees up all the space associated with the event list */ 464 465 struct index *ind,*ind2; 466 struct key *k,*k2; 467 struct notice *n,*n2; 468 469 if (index==NULL) return; 470 ind = index; 471 k = ind->key; 472 while (k->left != NULL) k = k->left; 473 n = k->notice; 474 while (n!=NULL) { 475 n2 = n->right; 476 free(n); 477 n = n2; } 478 while (k!=NULL) { 479 k2 = k->right; 480 free(k); 481 k = k2; } 482 while (ind!=NULL) { 483 ind2 = ind->right; 484 free(ind); 485 ind = ind2; } 486 487 index = NULL; 488 current = NULL; 489 } 490