|
|
1 # define INCLUDE_FILE_IO
2 # include "dgd.h"
3 # include "str.h"
4 # include "array.h"
5 # include "object.h"
6 # include "xfloat.h"
7 # include "interpret.h"
8 # include "data.h"
9 # include "call_out.h"
10
11 # define CYCBUF_SIZE 128 /* cyclic buffer size, power of 2 */
12 # define CYCBUF_MASK (CYCBUF_SIZE - 1) /* cyclic buffer mask */
13 # define SWPERIOD 60 /* swaprate buffer size */
14
15 typedef struct {
16 uindex handle; /* callout handle */
17 uindex oindex; /* index in object table */
18 Uint time; /* when to call */
19 uindex mtime; /* when to call in milliseconds */
20 } call_out;
21
22 # define prev oindex
23 # define next time
24 # define count mtime
25
26 struct _cbuf_ {
27 uindex list; /* list */
28 uindex last; /* last in list */
29 };
30
31 static char cb_layout[] = "uu";
32
33 static call_out *cotab; /* callout table */
34 static uindex cotabsz; /* callout table size */
35 static uindex queuebrk; /* queue brk */
36 static uindex cycbrk; /* cyclic buffer brk */
37 static uindex flist; /* free list index */
38 static uindex nzero; /* # immediate callouts */
39 static uindex nshort; /* # short-term callouts, incl. nzero */
40 static cbuf running; /* running callouts */
41 static cbuf immediate; /* immediate callouts */
42 static cbuf cycbuf[CYCBUF_SIZE]; /* cyclic buffer of callout lists */
43 static Uint timestamp; /* cycbuf start time */
44 static Uint timeout; /* time of first callout in cycbuf */
45 static Uint atimeout; /* alarm time in seconds */
46 static unsigned short amtime; /* alarm time in milliseconds */
47 static Uint timediff; /* stored/actual time difference */
48 static Uint swaptime; /* last swap count timestamp */
49 static Uint swapped1[SWPERIOD]; /* swap info for last minute */
50 static Uint swapped5[SWPERIOD]; /* swap info for last five minutes */
51 static Uint swaprate1; /* swaprate per minute */
52 static Uint swaprate5; /* swaprate per 5 minutes */
53
54 /*
55 * NAME: call_out->init()
56 * DESCRIPTION: initialize callout handling
57 */
58 bool co_init(max)
59 unsigned int max;
60 {
61 if (max != 0) {
62 /* only if callouts are enabled */
63 cotab = ALLOC(call_out, max + 1);
64 cotab[0].time = 0; /* sentinel for the heap */
65 cotab[0].mtime = 0;
66 cotab++;
67 flist = 0;
68 if (P_time() >> 24 <= 1) {
69 message("Config error: bad time (early seventies)\012"); /* LF */
70 return FALSE;
71 }
72 timestamp = timeout = 0;
73 atimeout = amtime = 0;
74 timediff = 0;
75 }
76 running.list = immediate.list = 0;
77 memset(cycbuf, '\0', sizeof(cycbuf));
78 cycbrk = cotabsz = max;
79 queuebrk = 0;
80 nzero = nshort = 0;
81
82 swaptime = P_time();
83 memset(swapped1, '\0', sizeof(swapped1));
84 memset(swapped5, '\0', sizeof(swapped5));
85 swaprate1 = swaprate5 = 0;
86
87 return TRUE;
88 }
89
90 /*
91 * NAME: restart()
92 * DESCRIPTION: possibly restart timeout
93 */
94 static void restart(t)
95 register Uint t;
96 {
97 register unsigned short m;
98
99 if (t != 0) {
100 if (nshort != nzero) {
101 /* look for next callout */
102 while (cycbuf[t & CYCBUF_MASK].list == 0) {
103 t++;
104 }
105 timeout = t;
106 } else {
107 /* no callouts left */
108 timeout = 0;
109 }
110 }
111
112 t = timeout;
113 m = 0;
114 if (queuebrk != 0 &&
115 (t == 0 || cotab[0].time < t ||
116 (cotab[0].time == t && cotab[0].mtime < m))) {
117 t = cotab[0].time;
118 m = cotab[0].mtime;
119 }
120
121 if (t != atimeout || m != amtime) {
122 P_timer(atimeout = t, amtime = m);
123 }
124 }
125
126 /*
127 * NAME: enqueue()
128 * DESCRIPTION: put a callout in the queue
129 */
130 static call_out *enqueue(t, m)
131 register Uint t;
132 unsigned short m;
133 {
134 register uindex i, j;
135 register call_out *l;
136
137 /*
138 * create a free spot in the heap, and sift it upward
139 */
140 # ifdef DEBUG
141 if (queuebrk == cycbrk) {
142 fatal("callout table overflow");
143 }
144 # endif
145 i = ++queuebrk;
146 l = cotab - 1;
147 for (j = i >> 1; l[j].time > t || (l[j].time == t && l[j].mtime > m);
148 i = j, j >>= 1) {
149 l[i] = l[j];
150 }
151
152 l = &l[i];
153 l->time = t;
154 l->mtime = m;
155 if (atimeout == 0 || t < atimeout || (t == atimeout && m < amtime)) {
156 restart((Uint) 0);
157 }
158 return l;
159 }
160
161 /*
162 * NAME: dequeue()
163 * DESCRIPTION: remove a callout from the queue
164 */
165 static void dequeue(i)
166 register uindex i;
167 {
168 register Uint t;
169 register short m;
170 register uindex j;
171 register call_out *l;
172
173 l = cotab - 1;
174 i++;
175 t = l[queuebrk].time;
176 m = l[queuebrk].mtime;
177 if (t < l[i].time) {
178 /* sift upward */
179 for (j = i >> 1; l[j].time > t || (l[j].time == t && l[j].mtime > m);
180 i = j, j >>= 1) {
181 l[i] = l[j];
182 }
183 } else if (i <= UINDEX_MAX / 2) {
184 /* sift downward */
185 for (j = i << 1; j < queuebrk; i = j, j <<= 1) {
186 if (l[j].time > l[j + 1].time ||
187 (l[j].time == l[j + 1].time && l[j].mtime > l[j + 1].mtime)) {
188 j++;
189 }
190 if (t < l[j].time || (t == l[j].time && m <= l[j].mtime)) {
191 break;
192 }
193 l[i] = l[j];
194 }
195 }
196 /* put into place */
197 l[i] = l[queuebrk--];
198 }
199
200 /*
201 * NAME: newcallout()
202 * DESCRIPTION: allocate a new callout for the cyclic buffer
203 */
204 static call_out *newcallout(list, t)
205 register cbuf *list;
206 Uint t;
207 {
208 register uindex i;
209 register call_out *co;
210
211 if (flist != 0) {
212 /* get callout from free list */
213 i = flist;
214 flist = cotab[i].next;
215 } else {
216 /* allocate new callout */
217 # ifdef DEBUG
218 if (cycbrk == queuebrk || cycbrk == 1) {
219 fatal("callout table overflow");
220 }
221 # endif
222 i = --cycbrk;
223 }
224 nshort++;
225 if (t == 0) {
226 nzero++;
227 }
228
229 co = &cotab[i];
230 if (list->list == 0) {
231 /* first one in list */
232 list->list = i;
233 co->count = 1;
234
235 if (t != 0 && (timeout == 0 || t < timeout)) {
236 restart(t);
237 }
238 } else {
239 /* add to list */
240 cotab[list->list].count++;
241 cotab[list->last].next = i;
242 }
243 list->last = i;
244 co->next = 0;
245
246 return co;
247 }
248
249 /*
250 * NAME: freecallout()
251 * DESCRIPTION: remove a callout from the cyclic buffer
252 */
253 static void freecallout(cyc, j, i, t)
254 register cbuf *cyc;
255 register uindex j, i;
256 register Uint t;
257 {
258 register call_out *l;
259
260 --nshort;
261 if (t == 0) {
262 --nzero;
263 }
264
265 l = cotab;
266 if (i == j) {
267 cyc->list = l[i].next;
268 if (cyc->list != 0) {
269 l[cyc->list].count = l[i].count - 1;
270 } else if (t != 0 && t == timeout) {
271 restart(t);
272 }
273 } else {
274 if (i == cyc->last) {
275 /* last element of the list */
276 l[cyc->last = j].next = 0;
277 } else {
278 /* connect previous to next */
279 l[j].next = l[i].next;
280 }
281 --l[cyc->list].count;
282 }
283 l += i;
284 l->handle = 0; /* mark as unused */
285 if (i == cycbrk) {
286 /*
287 * callout at the edge
288 */
289 while (++cycbrk != cotabsz && (++l)->handle == 0) {
290 /* followed by free callout */
291 if (cycbrk == flist) {
292 /* first in the free list */
293 flist = l->next;
294 } else {
295 /* connect previous to next */
296 cotab[l->prev].next = l->next;
297 if (l->next != 0) {
298 /* connect next to previous */
299 cotab[l->next].prev = l->prev;
300 }
301 }
302 }
303 } else {
304 /* add to free list */
305 if (flist != 0) {
306 /* link next to current */
307 cotab[flist].prev = i;
308 }
309 /* link to next */
310 l->next = flist;
311 flist = i;
312 }
313 }
314
315 /*
316 * NAME: encode()
317 * DESCRIPTION: encode millisecond time
318 */
319 static Uint encode(time, mtime)
320 Uint time;
321 unsigned int mtime;
322 {
323 return 0x01000000L + (((time - timediff) & 0xff) << 16) + mtime;
324 }
325
326 /*
327 * NAME: decode()
328 * DESCRIPTION: decode millisecond time
329 */
330 static Uint decode(time, mtime)
331 register Uint time;
332 unsigned short *mtime;
333 {
334 *mtime = time & 0xffff;
335 time = ((timestamp - timediff) & 0xffffff00L) + ((time >> 16) & 0xff) +
336 timediff;
337 if (time < timestamp) {
338 time += 0x100;
339 }
340 return time;
341 }
342
343 /*
344 * NAME: call_out->time()
345 * DESCRIPTION: get the current (adjusted) time
346 */
347 static Uint co_time(mtime)
348 unsigned short *mtime;
349 {
350 Uint t;
351
352 t = P_mtime(mtime);
353 if (t < timestamp) {
354 /* clock turned back? */
355 t = timestamp;
356 *mtime = 0;
357 } else if (timestamp < t) {
358 if (running.list == 0 && immediate.list == 0) {
359 if (atimeout == 0 || atimeout > t) {
360 timestamp = t;
361 } else if (timestamp < atimeout - 1) {
362 timestamp = atimeout - 1;
363 }
364 }
365 if (t > timestamp + 60) {
366 /* lot of lag? */
367 t = timestamp + 60;
368 *mtime = 0;
369 }
370 }
371
372 return t;
373 }
374
375 /*
376 * NAME: call_out->check()
377 * DESCRIPTION: check if, and how, a new callout can be added
378 */
379 Uint co_check(n, delay, mdelay, tp, mp, qp)
380 unsigned int n, mdelay;
381 Int delay;
382 Uint *tp;
383 unsigned short *mp;
384 cbuf **qp;
385 {
386 register Uint t;
387 register unsigned short m;
388
389 if (cotabsz == 0) {
390 /*
391 * call_outs are disabled
392 */
393 *qp = (cbuf *) NULL;
394 return 0;
395 }
396
397 if (queuebrk + (uindex) n == cycbrk || cycbrk - (uindex) n == 1) {
398 error("Too many callouts");
399 }
400
401 if (delay == 0 && (mdelay == 0 || mdelay == 0xffff)) {
402 /*
403 * immediate callout
404 */
405 if (nshort == 0 && queuebrk == 0 && n == 0) {
406 co_time(mp); /* initialize timestamp */
407 }
408 *qp = &immediate;
409 *tp = t = 0;
410 *mp = 0;
411 } else {
412 /*
413 * delayed callout
414 */
415 t = co_time(mp);
416 if (t + delay + 1 <= t) {
417 error("Too long delay");
418 }
419 t += delay;
420 if (mdelay != 0xffff) {
421 m = *mp + mdelay;
422 if (m >= 1000) {
423 m -= 1000;
424 t++;
425 }
426 } else {
427 m = 0;
428 }
429
430 if (mdelay == 0xffff && t < timestamp + CYCBUF_SIZE) {
431 /* use cyclic buffer */
432 *qp = &cycbuf[t & CYCBUF_MASK];
433 } else {
434 /* use queue */
435 *qp = (cbuf *) NULL;
436 }
437 *tp = t;
438 *mp = m;
439
440 if (mdelay == 0xffff) {
441 t -= timediff;
442 } else {
443 t = encode(t, m);
444 }
445 }
446
447 return t;
448 }
449
450 /*
451 * NAME: call_out->new()
452 * DESCRIPTION: add a callout
453 */
454 void co_new(oindex, handle, t, m, q)
455 unsigned int oindex, handle, m;
456 Uint t;
457 cbuf *q;
458 {
459 register call_out *co;
460
461 co = (q != (cbuf *) NULL) ? newcallout(q, t) : enqueue(t, m);
462 co->handle = handle;
463 co->oindex = oindex;
464 }
465
466 /*
467 * NAME: rmshort()
468 * DESCRIPTION: remove a short-term callout
469 */
470 static bool rmshort(cyc, i, handle, t)
471 register cbuf *cyc;
472 register uindex i, handle;
473 Uint t;
474 {
475 register uindex j, k;
476 register call_out *l;
477
478 k = cyc->list;
479 if (k != 0) {
480 /*
481 * this time-slot is in use
482 */
483 l = cotab;
484 if (l[k].oindex == i && l[k].handle == handle) {
485 /* first element in list */
486 freecallout(cyc, k, k, t);
487 return TRUE;
488 }
489 if (k != cyc->last) {
490 /*
491 * list contains more than 1 element
492 */
493 j = k;
494 k = l[j].next;
495 do {
496 if (l[k].oindex == i && l[k].handle == handle) {
497 /* found it */
498 freecallout(cyc, j, k, t);
499 return TRUE;
500 }
501 j = k;
502 } while ((k=l[j].next) != 0);
503 }
504 }
505 return FALSE;
506 }
507
508 /*
509 * NAME: call_out->remaining()
510 * DESCRIPTION: return the time remaining before a callout expires
511 */
512 Int co_remaining(t)
513 register Uint t;
514 {
515 Uint time;
516 unsigned short mtime, m;
517
518 time = co_time(&mtime);
519 if (t >> 24 != 1) {
520 t += timediff;
521 if (t > time) {
522 return t - time;
523 }
524 } else {
525 /* encoded millisecond */
526 t = decode(t, &m);
527 if (t > time || (t == time && m > mtime)) {
528 return -2 - (t - time) * 1000 - m + mtime;
529 }
530 }
531 return 0;
532 }
533
534 /*
535 * NAME: call_out->del()
536 * DESCRIPTION: remove a callout
537 */
538 void co_del(oindex, handle, t)
539 register unsigned int oindex, handle;
540 Uint t;
541 {
542 register call_out *l;
543 unsigned short m;
544
545 if (t >> 24 != 1) {
546 t += timediff;
547 /*
548 * try to find the callout in the cyclic buffer
549 */
550 if (t > timestamp && t < timestamp + CYCBUF_SIZE &&
551 rmshort(&cycbuf[t & CYCBUF_MASK], oindex, handle, t)) {
552 return;
553 }
554 }
555 /*
556 * decode() won't work correctly for times in the past, so always check
557 * the immediate queues for millisecond callouts
558 */
559 if (t <= timestamp) {
560 /*
561 * possible immediate callout
562 */
563 if (rmshort(&immediate, oindex, handle, 0) ||
564 rmshort(&running, oindex, handle, 0)) {
565 return;
566 }
567 }
568
569 /*
570 * Not found in the cyclic buffer; it <must> be in the queue.
571 */
572 l = cotab;
573 for (;;) {
574 # ifdef DEBUG
575 if (l == cotab + queuebrk) {
576 fatal("failed to remove callout");
577 }
578 # endif
579 if (l->oindex == oindex && l->handle == handle) {
580 dequeue(l - cotab);
581 return;
582 }
583 l++;
584 }
585 }
586
587 /*
588 * NAME: call_out->list()
589 * DESCRIPTION: adjust callout delays in array
590 */
591 void co_list(a)
592 array *a;
593 {
594 register value *v, *w;
595 register unsigned short i;
596 Uint time, t;
597 unsigned short mtime, m;
598 xfloat flt;
599
600 time = co_time(&mtime);
601 for (i = a->size, v = a->elts; i != 0; --i, v++) {
602 w = &v->u.array->elts[2];
603 switch ((Uint) w->u.number >> 24) {
604 case 0:
605 /* immediate */
606 break;
607
608 case 1:
609 /* encoded millisecond */
610 t = decode((Uint) w->u.number, &m);
611 if (t > time || (t == time && m > mtime)) {
612 flt_itof((Int) (t - time) * 1000 + m - mtime, &flt);
613 flt_mult(&flt, &thousandth);
614 PUT_FLTVAL(w, flt);
615 } else {
616 w->u.number = 0;
617 }
618 break;
619
620 default:
621 /* normal */
622 t = w->u.number + timediff;
623 if (t > time) {
624 w->u.number = t - time;
625 } else {
626 w->u.number = 0;
627 }
628 break;
629 }
630 }
631 }
632
633 /*
634 * NAME: call_out->expire()
635 * DESCRIPTION: collect callouts to run next
636 */
637 static void co_expire()
638 {
639 register call_out *co;
640 register uindex handle, oindex, i;
641 register cbuf *cyc;
642 Uint t;
643 unsigned short m;
644
645 if (P_timeout(&t, &m)) {
646 while (timestamp < t) {
647 timestamp++;
648
649 /*
650 * from queue
651 */
652 while (queuebrk != 0 && cotab[0].time < timestamp) {
653 handle = cotab[0].handle;
654 oindex = cotab[0].oindex;
655 dequeue(0);
656 co = newcallout(&immediate, 0);
657 co->handle = handle;
658 co->oindex = oindex;
659 }
660
661 /*
662 * from cyclic buffer list
663 */
664 cyc = &cycbuf[timestamp & CYCBUF_MASK];
665 i = cyc->list;
666 if (i != 0) {
667 cyc->list = 0;
668 if (immediate.list == 0) {
669 immediate.list = i;
670 } else {
671 cotab[immediate.last].next = i;
672 }
673 immediate.last = cyc->last;
674 i = cotab[i].count;
675 cotab[immediate.list].count += i;
676 nzero += i;
677 }
678 }
679
680 /*
681 * from queue
682 */
683 while (queuebrk != 0 &&
684 (cotab[0].time < t ||
685 (cotab[0].time == t && cotab[0].mtime <= m))) {
686 handle = cotab[0].handle;
687 oindex = cotab[0].oindex;
688 dequeue(0);
689 co = newcallout(&immediate, 0);
690 co->handle = handle;
691 co->oindex = oindex;
692 }
693
694 restart(t);
695 }
696
697 /* handle swaprate */
698 while (swaptime < t) {
699 ++swaptime;
700 swaprate1 -= swapped1[swaptime % SWPERIOD];
701 swapped1[swaptime % SWPERIOD] = 0;
702 if (swaptime % 5 == 0) {
703 swaprate5 -= swapped5[swaptime % (5 * SWPERIOD) / 5];
704 swapped5[swaptime % (5 * SWPERIOD) / 5] = 0;
705 }
706 }
707 }
708
709 /*
710 * NAME: call_out->call()
711 * DESCRIPTION: call expired callouts
712 */
713 void co_call(f)
714 frame *f;
715 {
716 register uindex i, handle;
717 object *obj;
718 string *str;
719 int nargs;
720
721 co_expire();
722 running = immediate;
723 immediate.list = 0;
724
725 if (running.list != 0) {
726 /*
727 * callouts to do
728 */
729 while (ec_push((ec_ftn) errhandler)) {
730 endthread();
731 }
732 while ((i=running.list) != 0) {
733 handle = cotab[i].handle;
734 obj = OBJ(cotab[i].oindex);
735 freecallout(&running, i, i, 0);
736
737 str = d_get_call_out(o_dataspace(obj), handle, f, &nargs);
738 if (i_call(f, obj, str->text, str->len, TRUE, nargs)) {
739 /* function exists */
740 i_del_value(f->sp++);
741 str_del((f->sp++)->u.string);
742 } else {
743 /* function doesn't exist */
744 str_del((f->sp++)->u.string);
745 }
746 endthread();
747 }
748 ec_pop();
749 }
750 }
751
752 /*
753 * NAME: call_out->info()
754 * DESCRIPTION: give information about callouts
755 */
756 void co_info(n1, n2)
757 uindex *n1, *n2;
758 {
759 *n1 = nshort;
760 *n2 = queuebrk;
761 }
762
763 /*
764 * NAME: call_out->delay()
765 * DESCRIPTION: return the time until the next timeout
766 */
767 Uint co_delay(mtime)
768 unsigned short *mtime;
769 {
770 Uint t;
771 unsigned short m;
772
773 if (nzero != 0) {
774 /* immediate */
775 *mtime = 0;
776 return 0;
777 }
778 if (atimeout == 0) {
779 /* infinite */
780 *mtime = 0xffff;
781 return 0;
782 }
783
784 t = co_time(&m);
785 if (t > atimeout || (t == atimeout && m >= amtime)) {
786 /* immediate */
787 *mtime = 0;
788 return 0;
789 }
790 if (m > amtime) {
791 m -= 1000;
792 t++;
793 }
794 *mtime = amtime - m;
795 return atimeout - t;
796 }
797
798 /*
799 * NAME: call_out->swapcount()
800 * DESCRIPTION: keep track of the number of objects swapped out
801 */
802 void co_swapcount(count)
803 unsigned int count;
804 {
805 swaprate1 += count;
806 swaprate5 += count;
807 swapped1[swaptime % SWPERIOD] += count;
808 swapped5[swaptime % (SWPERIOD * 5) / 5] += count;
809 }
810
811 /*
812 * NAME: call_out->swaprate1()
813 * DESCRIPTION: return the number of objects swapped out per minute
814 */
815 long co_swaprate1()
816 {
817 return swaprate1;
818 }
819
820 /*
821 * NAME: call_out->swaprate5()
822 * DESCRIPTION: return the number of objects swapped out per 5 minutes
823 */
824 long co_swaprate5()
825 {
826 return swaprate5;
827 }
828
829
830 typedef struct {
831 uindex cotabsz; /* callout table size */
832 uindex queuebrk; /* queue brk */
833 uindex cycbrk; /* cyclic buffer brk */
834 uindex flist; /* free list index */
835 uindex nshort; /* # of short-term callouts */
836 uindex nlong0; /* # of long-term callouts and imm. callouts */
837 Uint timestamp; /* time the last alarm came */
838 Uint timediff; /* accumulated time difference */
839 } dump_header;
840
841 static char dh_layout[] = "uuuuuuii";
842
843 typedef struct {
844 uindex handle; /* callout handle */
845 uindex oindex; /* index in object table */
846 Uint time; /* when to call */
847 } dump_callout;
848
849 static char dco_layout[] = "uui";
850
851 /*
852 * NAME: call_out->dump()
853 * DESCRIPTION: dump callout table
854 */
855 bool co_dump(fd)
856 int fd;
857 {
858 dump_header dh;
859 register uindex list, last;
860 register dump_callout *dc;
861 register call_out *co;
862 register uindex n;
863 register cbuf *cb;
864 unsigned short m;
865 bool ret;
866
867 /* update timestamp */
868 co_time(&m);
869
870 /* fill in header */
871 dh.cotabsz = cotabsz;
872 dh.queuebrk = queuebrk;
873 dh.cycbrk = cycbrk;
874 dh.flist = flist;
875 dh.nshort = nshort;
876 dh.nlong0 = queuebrk + nzero;
877 dh.timestamp = timestamp;
878 dh.timediff = timediff;
879
880 /* copy callouts */
881 n = queuebrk + cotabsz - cycbrk;
882 if (n != 0) {
883 dc = ALLOCA(dump_callout, n);
884 for (co = cotab, n = queuebrk; n != 0; co++, --n) {
885 dc->handle = co->handle;
886 dc->oindex = co->oindex;
887 dc->time = (co->mtime != 0) ?
888 encode(co->time, co->mtime) : co->time;
889 dc++;
890 }
891 for (co = cotab + cycbrk, n = cotabsz - cycbrk; n != 0; co++, --n) {
892 dc->handle = co->handle;
893 dc->oindex = co->oindex;
894 dc->time = co->time;
895 dc++;
896 }
897 n = queuebrk + cotabsz - cycbrk;
898 dc -= n;
899 }
900
901 /* deal with immediate callouts */
902 if (nzero != 0) {
903 if (running.list != 0) {
904 list = running.list;
905 if (immediate.list != 0) {
906 dc[running.last + n - cotabsz].next = immediate.list;
907 last = immediate.last;
908 } else {
909 last = running.last;
910 }
911 } else {
912 list = immediate.list;
913 last = immediate.last;
914 }
915 cb = &cycbuf[timestamp & CYCBUF_MASK];
916 last = dc[last + n - cotabsz].next = cb->list;
917 cb->list = list;
918 }
919
920 /* write header and callouts */
921 ret = (P_write(fd, (char *) &dh, sizeof(dump_header)) > 0 &&
922 (n == 0 || P_write(fd, (char *) dc, n * sizeof(dump_callout)) > 0) &&
923 P_write(fd, (char *) cycbuf, CYCBUF_SIZE * sizeof(cbuf)) > 0);
924
925 if (n != 0) {
926 AFREE(dc);
927 }
928
929 if (nzero != 0) {
930 cb->list = last;
931 }
932
933 return ret;
934 }
935
936 /*
937 * NAME: call_out->restore()
938 * DESCRIPTION: restore callout table
939 */
940 void co_restore(fd, t)
941 int fd;
942 register Uint t;
943 {
944 register uindex n, i, offset, last;
945 register dump_callout *dc;
946 register call_out *co;
947 register cbuf *cb;
948 dump_header dh;
949 cbuf buffer[CYCBUF_SIZE];
950 unsigned short m;
951
952 /* read and check header */
953 conf_dread(fd, (char *) &dh, dh_layout, (Uint) 1);
954 queuebrk = dh.queuebrk;
955 offset = cotabsz - dh.cotabsz;
956 cycbrk = dh.cycbrk + offset;
957 if (queuebrk > cycbrk + offset || cycbrk == 0) {
958 error("Restored too many callouts");
959 }
960
961 /* read tables */
962 n = queuebrk + cotabsz - cycbrk;
963 if (n != 0) {
964 dc = ALLOCA(dump_callout, n);
965 conf_dread(fd, (char *) dc, dco_layout, (Uint) n);
966 }
967 conf_dread(fd, (char *) buffer, cb_layout, (Uint) CYCBUF_SIZE);
968
969 flist = dh.flist;
970 nshort = dh.nshort;
971 nzero = dh.nlong0 - dh.queuebrk;
972 timestamp = t;
973 t -= dh.timestamp;
974 timediff = dh.timediff + t;
975
976 /* copy callouts */
977 if (n != 0) {
978 for (co = cotab, i = queuebrk; i != 0; co++, --i) {
979 co->handle = dc->handle;
980 co->oindex = dc->oindex;
981 if (dc->time >> 24 == 1) {
982 co->time = decode(dc->time, &m);
983 co->mtime = m;
984 } else {
985 co->time = dc->time + t;
986 co->mtime = 0;
987 }
988 dc++;
989 }
990 for (co = cotab + cycbrk, i = cotabsz - cycbrk; i != 0; co++, --i) {
991 co->handle = dc->handle;
992 co->oindex = dc->oindex;
993 co->time = dc->time;
994 dc++;
995 }
996 dc -= n;
997 AFREE(dc);
998 }
999
1000 /* cycle around cyclic buffer */
1001 t &= CYCBUF_MASK;
1002 memcpy(cycbuf + t, buffer, (unsigned int) (CYCBUF_SIZE - t) * sizeof(cbuf));
1003 memcpy(cycbuf, buffer + CYCBUF_SIZE - t, (unsigned int) t * sizeof(cbuf));
1004
1005 if (offset != 0) {
1006 /* patch callout references */
1007 if (flist != 0) {
1008 flist += offset;
1009 }
1010 for (i = CYCBUF_SIZE, cb = cycbuf; i > 0; --i, cb++) {
1011 if (cb->list != 0) {
1012 cb->list += offset;
1013 cb->last += offset;
1014 }
1015 }
1016 for (i = cotabsz - cycbrk, co = cotab + cycbrk; i > 0; --i, co++) {
1017 if (co->handle == 0) {
1018 co->prev += offset;
1019 }
1020 if (co->next != 0) {
1021 co->next += offset;
1022 }
1023 }
1024 }
1025
1026 /* fix up immediate callouts */
1027 if (nzero != 0) {
1028 cb = &cycbuf[timestamp & CYCBUF_MASK];
1029 immediate.list = cb->list;
1030 for (i = nzero - 1, last = cb->list; i != 0; --i) {
1031 last = cotab[last].next;
1032 }
1033 immediate.last = last;
1034 cotab[immediate.list].count = nzero;
1035 cb->list = cotab[last].next;
1036 cotab[last].next = 0;
1037 }
1038
1039 /* add counts */
1040 for (i = CYCBUF_SIZE, cb = cycbuf; i != 0; --i, cb++) {
1041 if (cb->list != 0) {
1042 n = 0;
1043 last = cb->list;
1044 do {
1045 last = cotab[last].next;
1046 n++;
1047 } while (last != 0);
1048 cotab[cb->list].count = n;
1049 }
1050 }
1051
1052 /* restart callouts */
1053 restart(timestamp);
1054 }
1055
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.