1 /*
2 * This file is part of DGD, https://github.com/dworkin/dgd
3 * Copyright (C) 1993-2010 Dworkin B.V.
4 * Copyright (C) 2010-2013 DGD Authors (see the commit log for details)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 # define INCLUDE_FILE_IO
21 # define INCLUDE_CTYPE
22 # include "dgd.h"
23 # include "str.h"
24 # include "array.h"
25 # include "object.h"
26 # include "interpret.h"
27 # include "data.h"
28
29 typedef struct _objplane_ objplane;
30
31 typedef struct _objpatch_ {
32 objplane *plane; /* plane that patch is on */
33 struct _objpatch_ *prev; /* previous patch */
34 struct _objpatch_ *next; /* next in linked list */
35 object obj; /* new object value */
36 } objpatch;
37
38 # define OPCHUNKSZ 32
39
40 typedef struct _opchunk_ {
41 struct _opchunk_ *next; /* next in linked list */
42 objpatch op[OPCHUNKSZ]; /* object patches */
43 } opchunk;
44
45 typedef struct {
46 opchunk *chunk; /* object patch chunk */
47 unsigned short chunksz; /* size of object patch chunk */
48 objpatch *flist; /* free list of object patches */
49 objpatch *op[OBJPATCHHTABSZ]; /* hash table of object patches */
50 } optable;
51
52 struct _objplane_ {
53 hashtab *htab; /* object name hash table */
54 optable *optab; /* object patch table */
55 uintptr_t clean; /* list of objects to clean */
56 uintptr_t upgrade; /* list of upgrade objects */
57 uindex destruct; /* destructed object list */
58 uindex free; /* free object list */
59 uindex nobjects; /* number of objects in object table */
60 uindex nfreeobjs; /* number of objects in free list */
61 Uint ocount; /* object creation count */
62 bool swap, dump, incr, stop, boot; /* state vars */
63 struct _objplane_ *prev; /* previous object plane */
64 };
65
66 object *otable; /* object table */
67 Uint *ocmap; /* object change map */
68 bool obase; /* object base plane flag */
69 bool swap, dump, incr, stop, boot; /* global state vars */
70 static bool recount; /* object counts recalculated? */
71 static uindex otabsize; /* size of object table */
72 static uindex uobjects; /* objects to check for upgrades */
73 static objplane baseplane; /* base object plane */
74 static objplane *oplane; /* current object plane */
75 static Uint *omap; /* object dump bitmap */
76 static Uint *counttab; /* object count table */
77 static object *upgraded; /* list of upgraded objects */
78 static uindex dobjects, dobject;/* objects to copy */
79 static uindex mobjects; /* max objects to copy */
80 static uindex dchunksz; /* copy chunk size */
81 static Uint dinterval; /* copy interval */
82 static Uint dtime; /* time copying started */
83 Uint odcount; /* objects destructed count */
84 static uindex rotabsize; /* size of object table at restore */
85
86 /*
87 * NAME: object->init()
88 * DESCRIPTION: initialize the object tables
89 */
o_init(unsigned int n,Uint interval)90 void o_init(unsigned int n, Uint interval)
91 {
92 otable = ALLOC(object, otabsize = n);
93 memset(otable, '\0', n * sizeof(object));
94 ocmap = ALLOC(Uint, BMAP(n));
95 memset(ocmap, '\0', BMAP(n) * sizeof(Uint));
96 for (n = 4; n < otabsize; n <<= 1) ;
97 baseplane.htab = ht_new(n >> 2, OBJHASHSZ, FALSE);
98 baseplane.optab = (optable *) NULL;
99 baseplane.upgrade = baseplane.clean = OBJ_NONE;
100 baseplane.destruct = baseplane.free = OBJ_NONE;
101 baseplane.nobjects = 0;
102 baseplane.nfreeobjs = 0;
103 baseplane.ocount = 3;
104 baseplane.swap = baseplane.dump = baseplane.incr = baseplane.stop =
105 baseplane.boot = FALSE;
106 oplane = &baseplane;
107 omap = ALLOC(Uint, BMAP(n));
108 memset(omap, '\0', BMAP(n) * sizeof(Uint));
109 counttab = ALLOC(Uint, n);
110 upgraded = (object *) NULL;
111 uobjects = dobjects = mobjects = 0;
112 dinterval = (interval * 19) / 20;
113 odcount = 1;
114 obase = TRUE;
115 recount = TRUE;
116 }
117
118
119 /*
120 * NAME: objpatch->init()
121 * DESCRIPTION: initialize objpatch table
122 */
op_init(objplane * plane)123 static void op_init(objplane *plane)
124 {
125 memset(plane->optab = ALLOC(optable, 1), '\0', sizeof(optable));
126 }
127
128 /*
129 * NAME: objpatch->clean()
130 * DESCRIPTION: free objpatch table
131 */
op_clean(objplane * plane)132 static void op_clean(objplane *plane)
133 {
134 opchunk *c, *f;
135
136 c = plane->optab->chunk;
137 while (c != (opchunk *) NULL) {
138 f = c;
139 c = c->next;
140 FREE(f);
141 }
142
143 FREE(plane->optab);
144 plane->optab = (optable *) NULL;
145 }
146
147 /*
148 * NAME: objpatch->new()
149 * DESCRIPTION: create a new object patch
150 */
op_new(objplane * plane,objpatch ** o,objpatch * prev,object * obj)151 static objpatch *op_new(objplane *plane, objpatch **o, objpatch *prev, object *obj)
152 {
153 optable *tab;
154 objpatch *op;
155
156 /* allocate */
157 tab = plane->optab;
158 if (tab->flist != (objpatch *) NULL) {
159 /* from free list */
160 op = tab->flist;
161 tab->flist = op->next;
162 } else {
163 /* newly allocated */
164 if (tab->chunk == (opchunk *) NULL || tab->chunksz == OPCHUNKSZ) {
165 opchunk *cc;
166
167 /* create new chunk */
168 cc = ALLOC(opchunk, 1);
169 cc->next = tab->chunk;
170 tab->chunk = cc;
171 tab->chunksz = 0;
172 }
173
174 op = &tab->chunk->op[tab->chunksz++];
175 }
176
177 /* initialize */
178 op->plane = plane;
179 op->prev = prev;
180 op->obj = *obj;
181
182 /* add to hash table */
183 op->next = *o;
184 return *o = op;
185 }
186
187 /*
188 * NAME: objpatch->del()
189 * DESCRIPTION: delete an object patch
190 */
op_del(objplane * plane,objpatch ** o)191 static void op_del(objplane *plane, objpatch **o)
192 {
193 objpatch *op;
194 optable *tab;
195
196 /* remove from hash table */
197 op = *o;
198 *o = op->next;
199
200 /* add to free list */
201 tab = plane->optab;
202 op->next = tab->flist;
203 tab->flist = op;
204 }
205
206
207 /*
208 * NAME: object->oaccess()
209 * DESCRIPTION: access to object from atomic code
210 */
o_oaccess(unsigned int index,int access)211 static object *o_oaccess(unsigned int index, int access)
212 {
213 objpatch *o, **oo;
214 object *obj;
215
216 if (BTST(ocmap, index)) {
217 /*
218 * object already patched
219 */
220 oo = &oplane->optab->op[index % OBJPATCHHTABSZ];
221 for (o = *oo; o->obj.index != index; o = o->next) ;
222 if (access == OACC_READ || o->plane == oplane) {
223 return &o->obj;
224 }
225
226 /* create new patch on current plane */
227 o = op_new(oplane, oo, o, obj = &o->obj);
228 if (obj->chain.name != (char *) NULL && obj->count != 0) {
229 *ht_lookup(oplane->htab, obj->chain.name, FALSE) = (hte *) &o->obj;
230 }
231 return &o->obj;
232 } else {
233 /*
234 * first patch for object
235 */
236 BSET(ocmap, index);
237 if (oplane->optab == (optable *) NULL) {
238 op_init(oplane);
239 }
240 oo = &oplane->optab->op[index % OBJPATCHHTABSZ];
241 obj = &op_new(oplane, oo, (objpatch *) NULL, OBJ(index))->obj;
242 if (obj->chain.name != (char *) NULL) {
243 char *name;
244 hte **h;
245
246 /* copy object name to higher plane */
247 strcpy(name = ALLOC(char, strlen(obj->chain.name) + 1),
248 obj->chain.name);
249 obj->chain.name = name;
250 if (obj->count != 0) {
251 if (oplane->htab == (hashtab *) NULL) {
252 oplane->htab = ht_new(OBJPATCHHTABSZ, OBJHASHSZ, FALSE);
253 }
254 h = ht_lookup(oplane->htab, name, FALSE);
255 obj->chain.next = *h;
256 *h = (hte *) obj;
257 }
258 }
259 return obj;
260 }
261 }
262
263 /*
264 * NAME: object->oread()
265 * DESCRIPTION: read access to object in patch table
266 */
o_oread(unsigned int index)267 object *o_oread(unsigned int index)
268 {
269 return o_oaccess(index, OACC_READ);
270 }
271
272 /*
273 * NAME: object->owrite()
274 * DESCRIPTION: write access to object in atomic code
275 */
o_owrite(unsigned int index)276 object *o_owrite(unsigned int index)
277 {
278 return o_oaccess(index, OACC_MODIFY);
279 }
280
281 /*
282 * NAME: object->space()
283 * DESCRIPTION: check if there's space for another object
284 */
o_space()285 bool o_space()
286 {
287 return (oplane->free != OBJ_NONE) ? TRUE : (oplane->nobjects != otabsize);
288 }
289
290 /*
291 * NAME: object->alloc()
292 * DESCRIPTION: allocate a new object
293 */
o_alloc()294 static object *o_alloc()
295 {
296 uindex n;
297 object *obj;
298
299 if (oplane->free != OBJ_NONE) {
300 /* get space from free object list */
301 n = oplane->free;
302 obj = OBJW(n);
303 oplane->free = obj->prev;
304 --oplane->nfreeobjs;
305 } else {
306 /* use new space in object table */
307 if (oplane->nobjects == otabsize) {
308 error("Too many objects");
309 }
310 n = oplane->nobjects++;
311 obj = OBJW(n);
312 }
313
314 OBJ(n)->index = OBJ_NONE;
315 obj->index = n;
316 obj->ctrl = (control *) NULL;
317 obj->data = (dataspace *) NULL;
318 obj->cfirst = SW_UNUSED;
319 obj->dfirst = SW_UNUSED;
320 counttab[n] = 0;
321
322 return obj;
323 }
324
325
326 /*
327 * NAME: object->new_plane()
328 * DESCRIPTION: create a new object plane
329 */
o_new_plane()330 void o_new_plane()
331 {
332 objplane *p;
333
334 p = ALLOC(objplane, 1);
335
336 if (oplane->optab == (optable *) NULL) {
337 p->htab = (hashtab *) NULL;
338 p->optab = (optable *) NULL;
339 } else {
340 p->htab = oplane->htab;
341 p->optab = oplane->optab;
342 }
343 p->clean = oplane->clean;
344 p->upgrade = oplane->upgrade;
345 p->destruct = oplane->destruct;
346 p->free = oplane->free;
347 p->nobjects = oplane->nobjects;
348 p->nfreeobjs = oplane->nfreeobjs;
349 p->ocount = oplane->ocount;
350 p->swap = oplane->swap;
351 p->dump = oplane->dump;
352 p->incr = oplane->incr;
353 p->stop = oplane->stop;
354 p->boot = oplane->boot;
355 p->prev = oplane;
356 oplane = p;
357
358 obase = FALSE;
359 }
360
361 /*
362 * NAME: object->commit_plane()
363 * DESCRIPTION: commit the current object plane
364 */
o_commit_plane()365 void o_commit_plane()
366 {
367 objplane *prev;
368 objpatch **t, **o, *op;
369 int i;
370 object *obj;
371
372
373 prev = oplane->prev;
374 if (oplane->optab != (optable *) NULL) {
375 for (i = OBJPATCHHTABSZ, t = oplane->optab->op; --i >= 0; t++) {
376 o = t;
377 while (*o != (objpatch *) NULL && (*o)->plane == oplane) {
378 op = *o;
379 if (op->prev != (objpatch *) NULL) {
380 obj = &op->prev->obj;
381 } else {
382 obj = OBJ(op->obj.index);
383 }
384 if (op->obj.count == 0 && obj->count != 0) {
385 /* remove object from stackframe above atomic function */
386 i_odest(cframe, obj);
387 }
388
389 if (prev == &baseplane) {
390 /*
391 * commit to base plane
392 */
393 if (op->obj.chain.name != (char *) NULL) {
394 hte **h;
395
396 if (obj->chain.name == (char *) NULL) {
397 char *name;
398
399 /*
400 * make object name static
401 */
402 m_static();
403 name = ALLOC(char, strlen(op->obj.chain.name) + 1);
404 m_dynamic();
405 strcpy(name, op->obj.chain.name);
406 FREE(op->obj.chain.name);
407 op->obj.chain.name = name;
408 if (op->obj.count != 0) {
409 /* put name in static hash table */
410 h = ht_lookup(prev->htab, name, FALSE);
411 op->obj.chain.next = *h;
412 *h = (hte *) obj;
413 }
414 } else {
415 /*
416 * same name
417 */
418 FREE(op->obj.chain.name);
419 op->obj.chain.name = obj->chain.name;
420 if (op->obj.count != 0) {
421 /* keep this name */
422 op->obj.chain.next = obj->chain.next;
423 } else if (obj->count != 0) {
424 /* remove from hash table */
425 h = ht_lookup(prev->htab, obj->chain.name,
426 FALSE);
427 if (*h != (hte *) obj) {
428 /* new object was compiled also */
429 h = &(*h)->next;
430 }
431 *h = obj->chain.next;
432 }
433 }
434 }
435 if (obj->count != 0) {
436 op->obj.update = obj->update;
437 }
438 BCLR(ocmap, op->obj.index);
439 *obj = op->obj;
440 op_del(oplane, o);
441 } else {
442 /*
443 * commit to previous plane
444 */
445 if (op->prev == (objpatch *) NULL ||
446 op->prev->plane != prev) {
447 /* move to previous plane */
448 op->plane = prev;
449 o = &op->next;
450 } else {
451 /*
452 * copy onto previous plane
453 */
454 if (op->obj.chain.name != (char *) NULL &&
455 op->obj.count != 0) {
456 /* move name to previous plane */
457 *ht_lookup(oplane->htab, op->obj.chain.name, FALSE)
458 = (hte *) obj;
459 }
460 *obj = op->obj;
461 op_del(oplane, o);
462 }
463 }
464 }
465 }
466
467 if (prev != &baseplane) {
468 prev->htab = oplane->htab;
469 prev->optab = oplane->optab;
470 } else {
471 if (oplane->htab != (hashtab *) NULL) {
472 ht_del(oplane->htab);
473 }
474 op_clean(oplane);
475 }
476 }
477
478 prev->clean = oplane->clean;
479 prev->upgrade = oplane->upgrade;
480 prev->destruct = oplane->destruct;
481 prev->free = oplane->free;
482 prev->nobjects = oplane->nobjects;
483 prev->nfreeobjs = oplane->nfreeobjs;
484 prev->ocount = oplane->ocount;
485 prev->swap = oplane->swap;
486 prev->dump = oplane->dump;
487 prev->incr = oplane->incr;
488 prev->stop = oplane->stop;
489 prev->boot = oplane->boot;
490 FREE(oplane);
491 oplane = prev;
492
493 obase = (prev == &baseplane);
494 }
495
496 /*
497 * NAME: object->discard_plane()
498 * DESCRIPTION: discard the current object plane without committing it
499 */
o_discard_plane()500 void o_discard_plane()
501 {
502 objpatch **o, *op;
503 int i;
504 object *obj, *clist;
505 objplane *p;
506
507 if (oplane->optab != (optable *) NULL) {
508 clist = (object *) NULL;
509 for (i = OBJPATCHHTABSZ, o = oplane->optab->op; --i >= 0; o++) {
510 while (*o != (objpatch *) NULL && (*o)->plane == oplane) {
511 op = *o;
512 if (op->prev != (objpatch *) NULL) {
513 obj = &op->prev->obj;
514 } else {
515 BCLR(ocmap, op->obj.index);
516 obj = OBJ(op->obj.index);
517 }
518
519 if (op->obj.chain.name != (char *) NULL) {
520 if (obj->chain.name == (char *) NULL ||
521 op->prev == (objpatch *) NULL) {
522 /*
523 * remove new name
524 */
525 if (op->obj.count != 0) {
526 /* remove from hash table */
527 *ht_lookup(oplane->htab, op->obj.chain.name, FALSE)
528 = op->obj.chain.next;
529 }
530 FREE(op->obj.chain.name);
531 } else {
532 hte **h;
533
534 if (op->obj.count != 0) {
535 /*
536 * move name to previous plane
537 */
538 h = ht_lookup(oplane->htab, obj->chain.name, FALSE);
539 obj->chain.next = op->obj.chain.next;
540 *h = (hte *) obj;
541 } else if (obj->count != 0) {
542 /*
543 * put name back in hashtable
544 */
545 h = ht_lookup(oplane->htab, obj->chain.name, FALSE);
546 obj->chain.next = *h;
547 *h = (hte *) obj;
548 }
549 }
550 }
551
552 if (obj->index == OBJ_NONE) {
553 /*
554 * discard newly created object
555 */
556 if ((op->obj.flags & O_MASTER) &&
557 op->obj.ctrl != (control *) NULL) {
558 op->obj.chain.next = (hte *) clist;
559 clist = &op->obj;
560 }
561 if (op->obj.data != (dataspace *) NULL) {
562 /* discard new data block */
563 d_del_dataspace(op->obj.data);
564 }
565 obj->index = op->obj.index;
566 } else {
567 /* pass on control block and dataspace */
568 obj->ctrl = op->obj.ctrl;
569 obj->data = op->obj.data;
570 }
571 op_del(oplane, o);
572 }
573 }
574
575 /* discard new control blocks */
576 while (clist != (object *) NULL) {
577 obj = clist;
578 clist = (object *) obj->chain.next;
579 d_del_control(obj->ctrl);
580 }
581 }
582
583 p = oplane;
584 oplane = p->prev;
585 if (p->optab != (optable *) NULL) {
586 if (oplane != &baseplane) {
587 oplane->htab = p->htab;
588 oplane->optab = p->optab;
589 } else {
590 if (p->htab != (hashtab *) NULL) {
591 ht_del(p->htab);
592 }
593 op_clean(p);
594 }
595 }
596 FREE(p);
597
598 obase = (oplane == &baseplane);
599 }
600
601
602 /*
603 * NAME: object->new()
604 * DESCRIPTION: create a new object
605 */
o_new(char * name,control * ctrl)606 object *o_new(char *name, control *ctrl)
607 {
608 object *o;
609 dinherit *inh;
610 int i;
611 hte **h;
612
613 /* allocate object */
614 o = o_alloc();
615
616 /* put object in object name hash table */
617 if (obase) {
618 m_static();
619 }
620 strcpy(o->chain.name = ALLOC(char, strlen(name) + 1), name);
621 if (obase) {
622 m_dynamic();
623 } else if (oplane->htab == (hashtab *) NULL) {
624 oplane->htab = ht_new(OBJPATCHHTABSZ, OBJHASHSZ, FALSE);
625 }
626 h = ht_lookup(oplane->htab, name, FALSE);
627 o->chain.next = *h;
628 *h = (hte *) o;
629
630 o->flags = O_MASTER;
631 o->cref = 0;
632 o->prev = OBJ_NONE;
633 o->count = ++oplane->ocount;
634 o->update = 0;
635 o->ctrl = ctrl;
636 ctrl->inherits[ctrl->ninherits - 1].oindex = ctrl->oindex = o->index;
637
638 /* add reference to all inherited objects */
639 o->u_ref = 0; /* increased to 1 in following loop */
640 inh = ctrl->inherits;
641 for (i = ctrl->ninherits, inh = ctrl->inherits; i > 0; --i, inh++) {
642 OBJW(inh->oindex)->u_ref++;
643 }
644
645 return o;
646 }
647
648 /*
649 * NAME: object->clone()
650 * DESCRIPTION: clone an object
651 */
o_clone(object * master)652 object *o_clone(object *master)
653 {
654 object *o;
655
656 /* allocate object */
657 o = o_alloc();
658 o->chain.name = (char *) NULL;
659 o->flags = 0;
660 o->count = ++oplane->ocount;
661 o->update = master->update;
662 o->u_master = master->index;
663
664 /* add reference to master object */
665 master->cref++;
666 master->u_ref++;
667
668 return o;
669 }
670
671 /*
672 * NAME: object->lwobj()
673 * DESCRIPTION: create light-weight instance of object
674 */
o_lwobj(object * obj)675 void o_lwobj(object *obj)
676 {
677 obj->flags |= O_LWOBJ;
678 }
679
680 /*
681 * NAME: object->delete()
682 * DESCRIPTION: the last reference to a master object was removed
683 */
o_delete(object * o,frame * f)684 static void o_delete(object *o, frame *f)
685 {
686 control *ctrl;
687 dinherit *inh;
688 int i;
689
690 ctrl = (O_UPGRADING(o)) ? OBJR(o->prev)->ctrl : o_control(o);
691
692 /* put in deleted list */
693 o->cref = oplane->destruct;
694 oplane->destruct = o->index;
695
696 /* callback to the system */
697 PUSH_STRVAL(f, str_new(NULL, strlen(o->chain.name) + 1L));
698 f->sp->u.string->text[0] = '/';
699 strcpy(f->sp->u.string->text + 1, o->chain.name);
700 PUSH_INTVAL(f, ctrl->compiled);
701 PUSH_INTVAL(f, o->index);
702 if (i_call_critical(f, "remove_program", 3, TRUE)) {
703 i_del_value(f->sp++);
704 }
705
706 /* remove references to inherited objects too */
707 for (i = ctrl->ninherits, inh = ctrl->inherits; --i > 0; inh++) {
708 o = OBJW(inh->oindex);
709 if (--(o->u_ref) == 0) {
710 o_delete(o, f);
711 }
712 }
713 }
714
715 /*
716 * NAME: object->upgrade()
717 * DESCRIPTION: upgrade an object to a new program
718 */
o_upgrade(object * obj,control * ctrl,frame * f)719 void o_upgrade(object *obj, control *ctrl, frame *f)
720 {
721 object *tmpl;
722 dinherit *inh;
723 int i;
724
725 /* allocate upgrade object */
726 tmpl = o_alloc();
727 tmpl->chain.name = (char *) NULL;
728 tmpl->flags = O_MASTER;
729 tmpl->count = 0;
730 tmpl->update = obj->update;
731 tmpl->ctrl = ctrl;
732 ctrl->inherits[ctrl->ninherits - 1].oindex = tmpl->cref = obj->index;
733
734 /* add reference to inherited objects */
735 for (i = ctrl->ninherits, inh = ctrl->inherits; --i > 0; inh++) {
736 OBJW(inh->oindex)->u_ref++;
737 }
738
739 /* add to upgrades list */
740 tmpl->chain.next = (hte *) oplane->upgrade;
741 oplane->upgrade = tmpl->index;
742
743 /* mark as upgrading */
744 obj->cref += 2;
745 tmpl->prev = obj->prev;
746 obj->prev = tmpl->index;
747
748 /* remove references to old inherited objects */
749 ctrl = o_control(obj);
750 for (i = ctrl->ninherits, inh = ctrl->inherits; --i > 0; inh++) {
751 obj = OBJW(inh->oindex);
752 if (--(obj->u_ref) == 0) {
753 o_delete(obj, f);
754 }
755 }
756 }
757
758 /*
759 * NAME: object->upgraded()
760 * DESCRIPTION: an object has been upgraded
761 */
o_upgraded(object * tmpl,object * onew)762 void o_upgraded(object *tmpl, object *onew)
763 {
764 # ifdef DEBUG
765 if (onew->count == 0) {
766 fatal("upgrading destructed object");
767 }
768 # endif
769 if (!(onew->flags & O_MASTER)) {
770 onew->update = OBJ(onew->u_master)->update;
771 }
772 if (tmpl->count == 0) {
773 tmpl->chain.next = (hte *) upgraded;
774 upgraded = tmpl;
775 }
776 tmpl->count++;
777 }
778
779 /*
780 * NAME: object->del()
781 * DESCRIPTION: delete an object
782 */
o_del(object * obj,frame * f)783 void o_del(object *obj, frame *f)
784 {
785 if (obj->count == 0) {
786 /* can happen if object selfdestructs in close()-on-destruct */
787 error("Destructing destructed object");
788 }
789 i_odest(f, obj); /* wipe out occurrences on the stack */
790 if (obj->data == (dataspace *) NULL && obj->dfirst != SW_UNUSED) {
791 o_dataspace(obj); /* load dataspace now */
792 }
793 obj->count = 0;
794 odcount++;
795
796 if (obj->flags & O_MASTER) {
797 /* remove from object name hash table */
798 *ht_lookup(oplane->htab, obj->chain.name, FALSE) = obj->chain.next;
799
800 if (--(obj->u_ref) == 0 && !O_UPGRADING(obj)) {
801 o_delete(obj, f);
802 }
803 } else {
804 object *master;
805
806 master = OBJW(obj->u_master);
807 master->cref--;
808 if (--(master->u_ref) == 0 && !O_UPGRADING(master)) {
809 o_delete(master, f);
810 }
811 }
812
813 /* put in clean list */
814 obj->chain.next = (hte *) oplane->clean;
815 oplane->clean = obj->index;
816 }
817
818
819 /*
820 * NAME: object->name()
821 * DESCRIPTION: return the name of an object
822 */
o_name(char * name,object * o)823 char *o_name(char *name, object *o)
824 {
825 if (o->chain.name != (char *) NULL) {
826 return o->chain.name;
827 } else {
828 char num[12];
829 char *p;
830 uindex n;
831
832 /*
833 * return the name of the master object with the index appended
834 */
835 n = o->index;
836 p = num + 11;
837 *p = '\0';
838 do {
839 *--p = '0' + n % 10;
840 n /= 10;
841 } while (n != 0);
842 *--p = '#';
843
844 strcpy(name, OBJR(o->u_master)->chain.name);
845 strcat(name, p);
846 return name;
847 }
848 }
849
850 /*
851 * NAME: object->builtin_name()
852 * DESCRIPTION: return the base name of a builtin type
853 */
o_builtin_name(Int type)854 char *o_builtin_name(Int type)
855 {
856 /*
857 * builtin types have names like: /builtin/type#-1
858 * the base name is then: builtin/type
859 */
860 switch (type) {
861 # ifdef CLOSURES
862 case BUILTIN_FUNCTION:
863 return BIPREFIX "function";
864 # endif
865
866 # ifdef DEBUG
867 default:
868 fatal("unknown builtin type %d", type);
869 # endif
870 }
871 return NULL;
872 }
873
874 /*
875 * NAME: object->find()
876 * DESCRIPTION: find an object by name
877 */
o_find(char * name,int access)878 object *o_find(char *name, int access)
879 {
880 object *o;
881 unsigned long number;
882 char *hash;
883
884 hash = strchr(name, '#');
885 if (hash != (char *) NULL) {
886 char *p;
887 object *m;
888
889 /*
890 * Look for a cloned object, which cannot be found directly in the
891 * object name hash table.
892 * The name must be of the form filename#1234, where 1234 is the
893 * decimal representation of the index in the object table.
894 */
895 p = hash + 1;
896 if (*p == '\0' || (p[0] == '0' && p[1] != '\0')) {
897 /* don't accept "filename#" or "filename#01" */
898 return (object *) NULL;
899 }
900
901 /* convert the string to a number */
902 number = 0;
903 do {
904 if (!isdigit(*p)) {
905 return (object *) NULL;
906 }
907 number = number * 10 + *p++ - '0';
908 if (number >= oplane->nobjects) {
909 return (object *) NULL;
910 }
911 } while (*p != '\0');
912
913 o = OBJR(number);
914 if (o->count == 0 || (o->flags & O_MASTER) ||
915 strncmp(name, (m=OBJR(o->u_master))->chain.name, hash-name) != 0 ||
916 m->chain.name[hash - name] != '\0') {
917 /*
918 * no entry, not a clone, or object name doesn't match
919 */
920 return (object *) NULL;
921 }
922 } else {
923 /* look it up in the hash table */
924 if (oplane->htab == (hashtab *) NULL ||
925 (o = (object *) *ht_lookup(oplane->htab, name, TRUE)) ==
926 (object *) NULL) {
927 if (oplane != &baseplane) {
928 o = (object *) *ht_lookup(baseplane.htab, name, FALSE);
929 if (o != (object *) NULL) {
930 number = o->index;
931 o = (access == OACC_READ)? OBJR(number) : OBJW(number);
932 if (o->count != 0) {
933 return o;
934 }
935 }
936 }
937 return (object *) NULL;
938 }
939 number = o->index;
940 }
941
942 return (access == OACC_READ) ? o : OBJW(number);
943 }
944
945 /*
946 * NAME: object->restore_object()
947 * DESCRIPTION: restore an object from the snapshot
948 */
o_restore_obj(object * obj,bool cactive,bool dactive)949 static void o_restore_obj(object *obj, bool cactive, bool dactive)
950 {
951 BCLR(omap, obj->index);
952 --dobjects;
953 d_restore_obj(obj, (recount) ? counttab : (Uint *) NULL, rotabsize, cactive,
954 dactive);
955 }
956
957 /*
958 * NAME: object->control()
959 * DESCRIPTION: return the control block for an object
960 */
o_control(object * obj)961 control *o_control(object *obj)
962 {
963 object *o;
964
965 o = obj;
966 if (!(o->flags & O_MASTER)) {
967 /* get control block of master object */
968 o = OBJR(o->u_master);
969 }
970 if (o->ctrl == (control *) NULL) {
971 if (BTST(omap, o->index)) {
972 o_restore_obj(o, TRUE, FALSE);
973 } else {
974 o->ctrl = d_load_control(o);
975 }
976 } else {
977 d_ref_control(o->ctrl);
978 }
979 return obj->ctrl = o->ctrl;
980 }
981
982 /*
983 * NAME: object->dataspace()
984 * DESCRIPTION: return the dataspace block for an object
985 */
o_dataspace(object * o)986 dataspace *o_dataspace(object *o)
987 {
988 if (o->data == (dataspace *) NULL) {
989 if (BTST(omap, o->index)) {
990 o_restore_obj(o, TRUE, TRUE);
991 } else {
992 o->data = d_load_dataspace(o);
993 }
994 } else {
995 d_ref_dataspace(o->data);
996 }
997 return o->data;
998 }
999
1000 /*
1001 * NAME: object->clean_upgrades()
1002 * DESCRIPTION: clean up upgrade templates
1003 */
o_clean_upgrades()1004 static void o_clean_upgrades()
1005 {
1006 object *o, *next;
1007 Uint count;
1008
1009 while ((next=upgraded) != (object *) NULL) {
1010 upgraded = (object *) next->chain.next;
1011
1012 count = next->count;
1013 next->count = 0;
1014 do {
1015 o = next;
1016 next = OBJ(o->cref);
1017 o->ref -= count;
1018 if (o->ref == 0) {
1019 # ifdef DEBUG
1020 if (o->prev != OBJ_NONE) {
1021 fatal("removing issue in middle of list");
1022 }
1023 # endif
1024 /* remove from template list */
1025 if (next->prev == o->index) {
1026 next->prev = OBJ_NONE;
1027 } else {
1028 OBJ(next->prev)->prev = OBJ_NONE;
1029 }
1030
1031 /* put in delete list */
1032 o->cref = baseplane.destruct;
1033 baseplane.destruct = o->index;
1034 }
1035 } while (next->chain.name == (char *) NULL);
1036 }
1037 }
1038
1039 /*
1040 * NAME: object->purge_upgrades()
1041 * DESCRIPTION: purge the LW dross from upgrade templates
1042 */
o_purge_upgrades(object * o)1043 static bool o_purge_upgrades(object *o)
1044 {
1045 bool purged;
1046
1047 purged = FALSE;
1048 while (o->prev != OBJ_NONE && ((o=OBJ(o->prev))->flags & O_LWOBJ)) {
1049 o->flags &= ~O_LWOBJ;
1050 if (--o->ref == 0) {
1051 o->cref = baseplane.destruct;
1052 baseplane.destruct = o->index;
1053 purged = TRUE;
1054 }
1055 }
1056
1057 return purged;
1058 }
1059
1060 /*
1061 * NAME: object->clean()
1062 * DESCRIPTION: clean up the object table
1063 */
o_clean()1064 void o_clean()
1065 {
1066 object *o;
1067
1068 while (baseplane.clean != OBJ_NONE) {
1069 o = OBJ(baseplane.clean);
1070 baseplane.clean = (uintptr_t) o->chain.next;
1071
1072 /* free dataspace block (if it exists) */
1073 if (o->data != (dataspace *) NULL) {
1074 d_del_dataspace(o->data);
1075 }
1076
1077 if (o->flags & O_MASTER) {
1078 /* remove possible upgrade templates */
1079 if (o_purge_upgrades(o)) {
1080 o->prev = OBJ_NONE;
1081 }
1082 } else {
1083 object *tmpl;
1084
1085 /* check if clone still had to be upgraded */
1086 tmpl = OBJW(o->u_master);
1087 if (tmpl->update != o->update) {
1088 /* non-upgraded clone of old issue */
1089 do {
1090 tmpl = OBJW(tmpl->prev);
1091 } while (tmpl->update != o->update);
1092
1093 if (tmpl->count == 0) {
1094 tmpl->chain.next = (hte *) upgraded;
1095 upgraded = tmpl;
1096 }
1097 tmpl->count++;
1098 }
1099
1100 /* put clone in free list */
1101 o->prev = baseplane.free;
1102 baseplane.free = o->index;
1103 baseplane.nfreeobjs++;
1104 }
1105 }
1106
1107 o_clean_upgrades(); /* 1st time */
1108
1109 while (baseplane.upgrade != OBJ_NONE) {
1110 object *up;
1111 control *ctrl;
1112
1113 o = OBJ(baseplane.upgrade);
1114 baseplane.upgrade = (uintptr_t) o->chain.next;
1115
1116 up = OBJ(o->cref);
1117 if (up->u_ref == 0) {
1118 /* no more instances of object around */
1119 o->cref = baseplane.destruct;
1120 baseplane.destruct = o->index;
1121 } else {
1122 /* upgrade objects */
1123 up->flags &= ~O_COMPILED;
1124 up->cref -= 2;
1125 o->u_ref = up->cref;
1126 if (up->flags & O_LWOBJ) {
1127 o->flags |= O_LWOBJ;
1128 o->u_ref++;
1129 }
1130 if (up->count != 0 && O_HASDATA(up)) {
1131 o->u_ref++;
1132 }
1133 ctrl = up->ctrl;
1134
1135 if (o->ctrl->vmapsize != 0 && o->u_ref != 0) {
1136 /*
1137 * upgrade variables
1138 */
1139 if (o->prev != OBJ_NONE) {
1140 OBJ(o->prev)->cref = o->index;
1141 }
1142
1143 if (o->u_ref > (up->count != 0)) {
1144 up->update++;
1145 }
1146 if (up->count != 0 && up->data == (dataspace *) NULL &&
1147 up->dfirst != SW_UNUSED) {
1148 /* load dataspace (with old control block) */
1149 up->data = d_load_dataspace(up);
1150 }
1151 } else {
1152 /* no variable upgrading */
1153 up->prev = o->prev;
1154 o->cref = baseplane.destruct;
1155 baseplane.destruct = o->index;
1156 }
1157
1158 /* swap control blocks */
1159 up->ctrl = o->ctrl;
1160 up->ctrl->oindex = up->index;
1161 o->ctrl = ctrl;
1162 ctrl->oindex = o->index;
1163 o->cfirst = up->cfirst;
1164 up->cfirst = SW_UNUSED;
1165
1166 /* swap vmap back to template */
1167 ctrl->vmap = up->ctrl->vmap;
1168 ctrl->vmapsize = up->ctrl->vmapsize;
1169 if (ctrl->vmapsize != 0) {
1170 ctrl->flags |= CTRL_VARMAP;
1171 }
1172 up->ctrl->vmap = (unsigned short *) NULL;
1173 up->ctrl->vmapsize = 0;
1174
1175 if (ctrl->ndata != 0) {
1176 /* upgrade all dataspaces in memory */
1177 d_upgrade_mem(o, up);
1178 }
1179 }
1180 }
1181
1182 o_clean_upgrades(); /* 2nd time */
1183
1184 while (baseplane.destruct != OBJ_NONE) {
1185 o = OBJ(baseplane.destruct);
1186 baseplane.destruct = o->cref;
1187
1188 /* free control block */
1189 d_del_control(o_control(o));
1190
1191 if (o->chain.name != (char *) NULL) {
1192 /* free object name */
1193 FREE(o->chain.name);
1194 o->chain.name = (char *) NULL;
1195 }
1196 o->u_ref = 0;
1197
1198 /* put object in free list */
1199 o->prev = baseplane.free;
1200 baseplane.free = o->index;
1201 baseplane.nfreeobjs++;
1202 }
1203
1204 swap = baseplane.swap;
1205 dump = baseplane.dump;
1206 incr = baseplane.incr;
1207 stop = baseplane.stop;
1208 boot = baseplane.boot;
1209 baseplane.swap = baseplane.dump = baseplane.incr = FALSE;
1210 }
1211
1212 /*
1213 * NAME: object->count()
1214 * DESCRIPTION: return the number of objects in use
1215 */
o_count()1216 uindex o_count()
1217 {
1218 return oplane->nobjects - oplane->nfreeobjs;
1219 }
1220
1221 /*
1222 * NAME: object->dobjects()
1223 * DESCRIPTION: return the number of objects left to copy
1224 */
o_dobjects()1225 uindex o_dobjects()
1226 {
1227 return dobjects;
1228 }
1229
1230
1231 typedef struct {
1232 uindex free; /* free object list */
1233 uindex nobjects; /* # objects */
1234 uindex nfreeobjs; /* # free objects */
1235 Uint onamelen; /* length of all object names */
1236 } dump_header;
1237
1238 static char dh_layout[] = "uuui";
1239
1240 typedef struct {
1241 uindex nctrl; /* objects left to copy */
1242 uindex ndata;
1243 uindex cobject; /* object to copy */
1244 uindex dobject;
1245 Uint count; /* object count */
1246 } map_header;
1247
1248 static char mh_layout[] = "uuuui";
1249
1250 # define CHUNKSZ 16384
1251
1252 /*
1253 * NAME: object->sweep()
1254 * DESCRIPTION: sweep through the object table after a dump or restore
1255 */
o_sweep(uindex n)1256 static void o_sweep(uindex n)
1257 {
1258 object *obj;
1259
1260 uobjects = n;
1261 dobject = 0;
1262 for (obj = otable; n > 0; obj++, --n) {
1263 if (obj->count != 0) {
1264 if (obj->cfirst != SW_UNUSED || obj->dfirst != SW_UNUSED) {
1265 BSET(omap, obj->index);
1266 dobjects++;
1267 }
1268 } else if ((obj->flags & O_MASTER) && obj->u_ref != 0 &&
1269 obj->cfirst != SW_UNUSED) {
1270 BSET(omap, obj->index);
1271 dobjects++;
1272 }
1273 }
1274 mobjects = dobjects;
1275 }
1276
1277 /*
1278 * NAME: object->recount()
1279 * DESCRIPTION: update object counts
1280 */
o_recount(uindex n)1281 static Uint o_recount(uindex n)
1282 {
1283 Uint count, *ct;
1284 object *obj;
1285
1286 count = 3;
1287 for (obj = otable, ct = counttab; n > 0; obj++, ct++, --n) {
1288 if (obj->count != 0) {
1289 *ct = obj->count;
1290 obj->count = count++;
1291 } else {
1292 *ct = 2;
1293 }
1294 }
1295
1296 odcount = 1;
1297 recount = TRUE;
1298 return count;
1299 }
1300
1301 /*
1302 * NAME: uindex_compare
1303 * DESCRIPTION: used by qsort to compare entries
1304 */
uindex_compare(const void * pa,const void * pb)1305 int uindex_compare(const void *pa, const void *pb)
1306 {
1307 uindex a = *(uindex *)pa;
1308 uindex b = *(uindex *)pb;
1309
1310 if (a > b) {
1311 return 1;
1312 } else if (a < b) {
1313 return -1;
1314 } else {
1315 return 0;
1316 }
1317 }
1318
1319 /*
1320 * NAME: object->dump()
1321 * DESCRIPTION: dump the object table
1322 */
o_dump(int fd,bool incr)1323 bool o_dump(int fd, bool incr)
1324 {
1325 uindex i;
1326 object *o;
1327 unsigned int len, buflen;
1328 dump_header dh;
1329 map_header mh;
1330 char buffer[CHUNKSZ];
1331
1332 /* prepare header */
1333 dh.free = baseplane.free;
1334 dh.nobjects = baseplane.nobjects;
1335 dh.nfreeobjs = baseplane.nfreeobjs;
1336 dh.onamelen = 0;
1337 for (i = baseplane.nobjects, o = otable; i > 0; --i, o++) {
1338 if (o->chain.name != (char *) NULL) {
1339 dh.onamelen += strlen(o->chain.name) + 1;
1340 }
1341 }
1342
1343 /* write header and objects */
1344 if (P_write(fd, (char *) &dh, sizeof(dump_header)) < 0 ||
1345 P_write(fd, (char *) otable, baseplane.nobjects * sizeof(object)) < 0) {
1346 return FALSE;
1347 }
1348
1349 /* write object names */
1350 buflen = 0;
1351 for (i = baseplane.nobjects, o = otable; i > 0; --i, o++) {
1352 if (o->chain.name != (char *) NULL) {
1353 len = strlen(o->chain.name) + 1;
1354 if (buflen + len > CHUNKSZ) {
1355 if (P_write(fd, buffer, buflen) < 0) {
1356 return FALSE;
1357 }
1358 buflen = 0;
1359 }
1360 memcpy(buffer + buflen, o->chain.name, len);
1361 buflen += len;
1362 }
1363 }
1364 if (buflen != 0 && P_write(fd, buffer, buflen) < 0) {
1365 return FALSE;
1366 }
1367
1368 if (dobjects != 0) {
1369 /*
1370 * partial snapshot: write bitmap and counts
1371 */
1372 mh.nctrl = dobjects;
1373 mh.ndata = dobjects;
1374 mh.cobject = dobject;
1375 mh.dobject = dobject;
1376 mh.count = 0;
1377 if (recount) {
1378 mh.count = baseplane.ocount;
1379 }
1380 if (P_write(fd, (char *) &mh, sizeof(map_header)) < 0 ||
1381 P_write(fd, (char *) (omap + BOFF(dobject)),
1382 (BMAP(dh.nobjects) - BOFF(dobject)) * sizeof(Uint)) < 0 ||
1383 P_write(fd, (char *) (omap + BOFF(dobject)),
1384 (BMAP(dh.nobjects) - BOFF(dobject)) * sizeof(Uint)) < 0 ||
1385 (mh.count != 0 &&
1386 P_write(fd, (char *) counttab, dh.nobjects * sizeof(Uint)) < 0)) {
1387 return FALSE;
1388 }
1389 }
1390
1391 if (!incr) {
1392 o_sweep(baseplane.nobjects);
1393 baseplane.ocount = o_recount(baseplane.nobjects);
1394 rotabsize = baseplane.nobjects;
1395 }
1396
1397 return TRUE;
1398 }
1399
1400 /*
1401 * NAME: object->restore()
1402 * DESCRIPTION: restore the object table
1403 */
o_restore(int fd,unsigned int rlwobj,bool part)1404 void o_restore(int fd, unsigned int rlwobj, bool part)
1405 {
1406 uindex i;
1407 object *o;
1408 Uint len, buflen, count;
1409 char *p;
1410 dump_header dh;
1411 char buffer[CHUNKSZ];
1412
1413 p = NULL;
1414
1415 /*
1416 * Free object names of precompiled objects.
1417 */
1418 for (i = baseplane.nobjects, o = otable; i > 0; --i, o++) {
1419 *ht_lookup(baseplane.htab, o->chain.name, FALSE) = o->chain.next;
1420 FREE(o->chain.name);
1421 }
1422
1423 /* read header and object table */
1424 conf_dread(fd, (char *) &dh, dh_layout, (Uint) 1);
1425
1426 if (dh.nobjects > otabsize) {
1427 error("Too many objects in restore file (%u)", dh.nobjects);
1428 }
1429
1430 conf_dread(fd, (char *) otable, OBJ_LAYOUT, (Uint) dh.nobjects);
1431 baseplane.free = dh.free;
1432 baseplane.nobjects = dh.nobjects;
1433 baseplane.nfreeobjs = dh.nfreeobjs;
1434
1435 /* read object names */
1436 buflen = 0;
1437 for (i = 0, o = otable; i < baseplane.nobjects; i++, o++) {
1438 if (rlwobj != 0) {
1439 o->flags &= ~O_LWOBJ;
1440 }
1441 if (o->chain.name != (char *) NULL) {
1442 /*
1443 * restore name
1444 */
1445 if (buflen == 0 ||
1446 (char *) memchr(p, '\0', buflen) == (char *) NULL) {
1447 /* move remainder to beginning, and refill buffer */
1448 if (buflen != 0) {
1449 memcpy(buffer, p, buflen);
1450 }
1451 len = (dh.onamelen > CHUNKSZ - buflen) ?
1452 CHUNKSZ - buflen : dh.onamelen;
1453 if (P_read(fd, buffer + buflen, len) != len) {
1454 fatal("cannot restore object names");
1455 }
1456 dh.onamelen -= len;
1457 buflen += len;
1458 p = buffer;
1459 }
1460 m_static();
1461 strcpy(o->chain.name = ALLOC(char, len = strlen(p) + 1), p);
1462 m_dynamic();
1463
1464 if (o->count != 0) {
1465 hte **h;
1466
1467 /* add name to lookup table */
1468 h = ht_lookup(baseplane.htab, p, FALSE);
1469 o->chain.next = *h;
1470 *h = (hte *) o;
1471
1472 /* fix O_LWOBJ */
1473 if (o->cref & rlwobj) {
1474 o->flags |= O_LWOBJ;
1475 o->cref &= ~rlwobj;
1476 }
1477 }
1478 p += len;
1479 buflen -= len;
1480 } else if (o->ref & rlwobj) {
1481 o->flags |= O_LWOBJ;
1482 o->ref &= ~rlwobj;
1483 o->ref++;
1484 }
1485
1486 if (o->count != 0) {
1487 /* there are no user or editor objects after a restore */
1488 if ((o->flags & O_SPECIAL) != O_SPECIAL) {
1489 o->flags &= ~O_SPECIAL;
1490 }
1491 }
1492 }
1493
1494 o_sweep(baseplane.nobjects);
1495
1496 if (part) {
1497 map_header mh;
1498 off_t offset;
1499 Uint *cmap, *dmap;
1500 uindex nctrl, ndata;
1501
1502 conf_dread(fd, (char *) &mh, mh_layout, (Uint) 1);
1503 nctrl = mh.nctrl;
1504 ndata = mh.ndata;
1505 count = mh.count;
1506
1507 cmap = dmap = (Uint *) NULL;
1508 if (nctrl != 0) {
1509 cmap = ALLOC(Uint, BMAP(dh.nobjects));
1510 memset(cmap, '\0', BMAP(dh.nobjects) * sizeof(Uint));
1511 conf_dread(fd, (char *) (cmap + BOFF(mh.cobject)), "i",
1512 BMAP(dh.nobjects) - BOFF(mh.cobject));
1513 }
1514 if (ndata != 0) {
1515 dmap = ALLOC(Uint, BMAP(dh.nobjects));
1516 memset(dmap, '\0', BMAP(dh.nobjects) * sizeof(Uint));
1517 conf_dread(fd, (char *) (dmap + BOFF(mh.dobject)), "i",
1518 BMAP(dh.nobjects) - BOFF(mh.dobject));
1519 }
1520
1521 if (count != 0) {
1522 conf_dread(fd, (char *) counttab, "i", dh.nobjects);
1523 recount = FALSE;
1524 } else {
1525 count = o_recount(baseplane.nobjects);
1526 }
1527
1528 /*
1529 * copy all objects from the secondary restore file
1530 */
1531 offset = P_lseek(fd, (off_t) 0, SEEK_CUR);
1532 i = mh.cobject;
1533 while (nctrl > 0) {
1534 while (!BTST(cmap, i)) {
1535 i++;
1536 }
1537 BCLR(cmap, i);
1538
1539 o = OBJ(i);
1540 if (o->cfirst != SW_UNUSED) {
1541 if (BTST(omap, i)) {
1542 BCLR(omap, i);
1543 --dobjects;
1544 }
1545 d_restore_ctrl(o, &sw_conv2);
1546 d_swapout(1);
1547 }
1548 i++;
1549 --nctrl;
1550 }
1551 i = mh.dobject;
1552 while (ndata > 0) {
1553 while (!BTST(dmap, i)) {
1554 i++;
1555 }
1556 BCLR(dmap, i);
1557
1558 o = OBJ(i);
1559 if (o->dfirst != SW_UNUSED) {
1560 if (BTST(omap, i)) {
1561 BCLR(omap, i);
1562 --dobjects;
1563 }
1564 d_restore_data(o, counttab, dh.nobjects, &sw_conv2);
1565 d_swapout(1);
1566 }
1567 i++;
1568 --ndata;
1569 }
1570
1571 if (cmap != (Uint *) NULL) {
1572 FREE(cmap);
1573 }
1574 if (dmap != (Uint *) NULL) {
1575 FREE(dmap);
1576 }
1577 P_lseek(fd, offset, SEEK_SET);
1578 } else {
1579 count = o_recount(baseplane.nobjects);
1580 }
1581
1582 baseplane.ocount = count;
1583 rotabsize = baseplane.nobjects;
1584 }
1585
1586 /*
1587 * NAME: object->copy()
1588 * DESCRIPTION: copy objects from dump to swap
1589 */
o_copy(Uint time)1590 bool o_copy(Uint time)
1591 {
1592 uindex n;
1593 object *obj, *tmpl;
1594
1595 if (dobjects != 0) {
1596 if (time == 0) {
1597 n = 0; /* copy all objects */
1598 } else {
1599 if (dtime == 0) {
1600 /* first copy */
1601 dtime = time - 1;
1602 if (dinterval == 0) {
1603 dchunksz = SWAPCHUNKSZ;
1604 } else {
1605 dchunksz = (mobjects + dinterval - 1) / dinterval;
1606 if (dchunksz == 0) {
1607 dchunksz = 1;
1608 }
1609 }
1610 }
1611
1612 time -= dtime;
1613 if (dinterval != 0 && time >= dinterval) {
1614 n = 0; /* copy all objects */
1615 } else if ((n = dchunksz * time) < mobjects) {
1616 /* copy a portion of remaining objects */
1617 n = mobjects - n;
1618 } else {
1619 n = 0; /* copy all objects */
1620 }
1621 }
1622
1623 while (dobjects > n) {
1624 for (obj = OBJ(dobject); !BTST(omap, obj->index); obj++) ;
1625 dobject = obj->index + 1;
1626 o_restore_obj(obj, FALSE, FALSE);
1627 }
1628 }
1629 o_clean();
1630
1631 if (dobjects == 0) {
1632 d_swapout(1);
1633
1634 for (n = uobjects, obj = otable; n > 0; --n, obj++) {
1635 if (obj->count != 0 && (obj->flags & O_LWOBJ)) {
1636 for (tmpl = obj; tmpl->prev != OBJ_NONE; tmpl = OBJ(tmpl->prev))
1637 {
1638 if (!(OBJ(tmpl->prev)->flags & O_LWOBJ)) {
1639 break;
1640 }
1641 if (counttab[tmpl->prev] == 2) {
1642 if (o_purge_upgrades(tmpl)) {
1643 tmpl->prev = OBJ_NONE;
1644 }
1645 break;
1646 }
1647 }
1648 }
1649 }
1650 o_clean();
1651
1652 d_converted();
1653 dtime = 0;
1654 return FALSE;
1655 } else {
1656 return TRUE;
1657 }
1658 }
1659
1660
1661 /*
1662 * NAME: swapout()
1663 * DESCRIPTION: indicate that objects are to be swapped out
1664 */
swapout()1665 void swapout()
1666 {
1667 oplane->swap = TRUE;
1668 }
1669
1670 /*
1671 * NAME: dump_state()
1672 * DESCRIPTION: indicate that the state must be dumped
1673 */
dump_state(bool incr)1674 void dump_state(bool incr)
1675 {
1676 oplane->dump = TRUE;
1677 oplane->incr = incr;
1678 }
1679
1680 /*
1681 * NAME: finish()
1682 * DESCRIPTION: indicate that the program must finish
1683 */
finish(bool boot)1684 void finish(bool boot)
1685 {
1686 if (boot && !oplane->dump) {
1687 error("Hotbooting without snapshot");
1688 }
1689 oplane->stop = TRUE;
1690 oplane->boot = boot;
1691 }
1692