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