ArchWizard

DGD/

source navigation ]
diff markup ]
identifier search ]
file search ]
Version: [ 1.0.a0 ] [ 1.1 ] [ 1.2 ] [ 1.2p1 ] [ 1.2p2 ] [ 1.2p3 ] [ 1.2p4 ] [ 1.2.151 ]

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.