ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/holofile.c
Revision: 3.26
Committed: Fri Sep 18 16:47:27 1998 UTC (25 years, 7 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.25: +40 -24 lines
Log Message:
added recovery from memory allocation errors

File Contents

# Content
1 /* Copyright (c) 1998 Silicon Graphics, Inc. */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ SGI";
5 #endif
6
7 /*
8 * Routines for managing holodeck files
9 *
10 * 9/30/97 GWLarson
11 */
12
13 #include "holo.h"
14
15 #ifndef CACHESIZE
16 #define CACHESIZE 16 /* default cache size (Mbytes, 0==inf) */
17 #endif
18 #ifndef FREEBEAMS
19 #define FREEBEAMS 1500 /* maximum beams to free at a time */
20 #endif
21 #ifndef PCTFREE
22 #define PCTFREE 15 /* maximum fraction to free (%) */
23 #endif
24 #ifndef MAXFRAG
25 #define MAXFRAG 32767 /* maximum fragments/file to track (0==inf) */
26 #endif
27
28 #ifndef BSD
29 #define write writebuf /* safe i/o routines */
30 #define read readbuf
31 #endif
32
33 #define FRAGBLK 256 /* number of fragments to allocate at a time */
34
35 unsigned hdcachesize = CACHESIZE*1024*1024; /* target cache size */
36 unsigned long hdclock; /* clock value */
37
38 HOLO *hdlist[HDMAX+1]; /* holodeck pointers (NULL term.) */
39
40 static struct fraglist {
41 short nlinks; /* number of holodeck sections using us */
42 short writerr; /* write error encountered */
43 int nfrags; /* number of known fragments */
44 BEAMI *fi; /* fragments, descending file position */
45 long flen; /* last known file length */
46 } *hdfragl; /* fragment lists, indexed by file descriptor */
47
48 static int nhdfragls; /* size of hdfragl array */
49
50
51 char *
52 hdrealloc(ptr, siz, rout) /* (re)allocate memory, retry then error */
53 char *ptr;
54 unsigned siz;
55 char *rout;
56 {
57 register char *newp;
58 /* call malloc/realloc */
59 if (ptr == NULL) newp = (char *)malloc(siz);
60 else newp = (char *)realloc(ptr, siz);
61 /* check success */
62 if (newp == NULL && rout != NULL) {
63 hdfreecache(25, NULL); /* free some memory */
64 errno = 0; /* retry */
65 newp = hdrealloc(ptr, siz, NULL);
66 if (newp == NULL) { /* give up and report error */
67 sprintf(errmsg, "out of memory in %s", rout);
68 error(SYSTEM, errmsg);
69 }
70 }
71 return(newp);
72 }
73
74
75 hdattach(fd) /* start tracking file fragments for some section */
76 register int fd;
77 {
78 if (fd >= nhdfragls) {
79 hdfragl = (struct fraglist *)hdrealloc((char *)hdfragl,
80 (fd+1)*sizeof(struct fraglist), "hdattach");
81 bzero((char *)(hdfragl+nhdfragls),
82 (fd+1-nhdfragls)*sizeof(struct fraglist));
83 nhdfragls = fd+1;
84 }
85 hdfragl[fd].nlinks++;
86 hdfragl[fd].flen = lseek(fd, 0L, 2); /* get file length */
87 }
88
89
90 /* Do we need a routine to locate file fragments given known occupants? */
91
92
93 hdrelease(fd) /* stop tracking file fragments for some section */
94 register int fd;
95 {
96 if (fd < 0 | fd >= nhdfragls || !hdfragl[fd].nlinks)
97 return;
98 if (!--hdfragl[fd].nlinks && hdfragl[fd].nfrags) {
99 free((char *)hdfragl[fd].fi);
100 hdfragl[fd].fi = NULL;
101 hdfragl[fd].nfrags = 0;
102 }
103 }
104
105
106 markdirty(hp) /* mark holodeck section directory dirty */
107 register HOLO *hp;
108 {
109 static BEAMI smudge = {0, -1};
110
111 if (hp->dirty) /* already marked? */
112 return;
113 hp->dirty = 1;
114 if (lseek(hp->fd, biglob(hp)->fo+(nbeams(hp)-1)*sizeof(BEAMI), 0) < 0
115 || write(hp->fd, (char *)&smudge,
116 sizeof(BEAMI)) != sizeof(BEAMI))
117 error(SYSTEM, "seek/write error in markdirty");
118 }
119
120
121 HOLO *
122 hdinit(fd, hproto) /* initialize a holodeck section in a file */
123 int fd; /* corresponding file descriptor */
124 HDGRID *hproto; /* holodeck section grid */
125 {
126 long rtrunc;
127 long fpos;
128 register HOLO *hp;
129 register int n;
130 /* prepare for system errors */
131 errno = 0;
132 if ((fpos = lseek(fd, 0L, 1)) < 0)
133 error(SYSTEM, "cannot determine holodeck file position");
134 if (hproto == NULL) { /* assume we're loading it */
135 HDGRID hpr;
136 /* load header */
137 if (read(fd, (char *)&hpr, sizeof(HDGRID)) != sizeof(HDGRID))
138 error(SYSTEM, "cannot load holodeck header");
139 /* allocate grid */
140 if ((hp = hdalloc(&hpr)) == NULL)
141 goto memerr;
142 /* load beam directory */
143 n = nbeams(hp)*sizeof(BEAMI);
144 if (read(fd, (char *)(hp->bi+1), n) != n)
145 error(SYSTEM, "failure loading holodeck directory");
146 /* check that it's clean */
147 if (hp->bi[nbeams(hp)].fo < 0)
148 error(WARNING, "dirty holodeck section");
149 } else { /* assume we're creating it */
150 if ((hp = hdalloc(hproto)) == NULL)
151 goto memerr;
152 /* write header and skeleton */
153 n = nbeams(hp)*sizeof(BEAMI);
154 if (write(fd, (char *)hproto, sizeof(HDGRID)) !=
155 sizeof(HDGRID) ||
156 write(fd, (char *)(hp->bi+1), n) != n)
157 error(SYSTEM, "cannot write header to holodeck file");
158 }
159 hp->fd = fd;
160 hp->dirty = 0;
161 biglob(hp)->fo = fpos + sizeof(HDGRID);
162 /* start tracking fragments */
163 hdattach(fd);
164 /* check rays on disk */
165 fpos = hdfilen(fd);
166 biglob(hp)->nrd = rtrunc = 0;
167 for (n = hproto == NULL ? nbeams(hp) : 0; n > 0; n--)
168 if (hp->bi[n].nrd)
169 if (hp->bi[n].fo + hp->bi[n].nrd > fpos) {
170 rtrunc += hp->bi[n].nrd;
171 hp->bi[n].nrd = 0;
172 } else
173 biglob(hp)->nrd += hp->bi[n].nrd;
174 if (rtrunc) {
175 sprintf(errmsg, "truncated section, %ld rays lost (%.1f%%)",
176 rtrunc, 100.*rtrunc/(rtrunc+biglob(hp)->nrd));
177 error(WARNING, errmsg);
178 }
179 /* add to holodeck list */
180 for (n = 0; n < HDMAX; n++)
181 if (hdlist[n] == NULL) {
182 hdlist[n] = hp;
183 break;
184 }
185 /* all done */
186 return(hp);
187 memerr:
188 error(SYSTEM, "cannot allocate holodeck grid");
189 }
190
191
192 int
193 hdsync(hp, all) /* update beams and directory on disk */
194 register HOLO *hp;
195 int all;
196 {
197 register int j, n;
198
199 if (hp == NULL) { /* do all holodecks */
200 n = 0;
201 for (j = 0; hdlist[j] != NULL; j++)
202 n += hdsync(hdlist[j], all);
203 return(n);
204 }
205 /* sync the beams */
206 for (j = (all ? nbeams(hp) : 0); j > 0; j--)
207 if (hp->bl[j] != NULL)
208 hdsyncbeam(hp, j);
209 if (!hp->dirty) /* directory clean? */
210 return(0);
211 errno = 0;
212 if (lseek(hp->fd, biglob(hp)->fo, 0) < 0)
213 error(SYSTEM, "cannot seek on holodeck file");
214 n = nbeams(hp)*sizeof(BEAMI);
215 if (write(hp->fd, (char *)(hp->bi+1), n) != n)
216 error(SYSTEM, "cannot update holodeck section directory");
217 hp->dirty = 0;
218 return(1);
219 }
220
221
222 unsigned
223 hdmemuse(all) /* return memory usage (in bytes) */
224 int all; /* include overhead (painful) */
225 {
226 long total = 0;
227 register int i, j;
228
229 for (j = 0; hdlist[j] != NULL; j++) {
230 total += blglob(hdlist[j])->nrm * sizeof(RAYVAL);
231 if (all) {
232 total += sizeof(HOLO) + sizeof(BEAM *) +
233 nbeams(hdlist[j]) *
234 (sizeof(BEAM *)+sizeof(BEAMI));
235 for (i = nbeams(hdlist[j]); i > 0; i--)
236 if (hdlist[j]->bl[i] != NULL)
237 total += sizeof(BEAM);
238 }
239 }
240 if (all)
241 for (j = 0; j < nhdfragls; j++) {
242 total += sizeof(struct fraglist);
243 if (hdfragl[j].nfrags)
244 total += FRAGBLK*sizeof(BEAMI) *
245 ((hdfragl[j].nfrags-1)/FRAGBLK + 1) ;
246 }
247 return(total);
248 }
249
250
251 long
252 hdfilen(fd) /* return file length for fd */
253 int fd;
254 {
255 long fpos, flen;
256
257 if (fd < 0)
258 return(-1);
259 if (fd >= nhdfragls || !hdfragl[fd].nlinks) {
260 if ((fpos = lseek(fd, 0L, 1)) < 0)
261 return(-1);
262 flen = lseek(fd, 0L, 2);
263 lseek(fd, fpos, 0);
264 return(flen);
265 }
266 return(hdfragl[fd].flen);
267 }
268
269
270 long
271 hdfiluse(fd, all) /* compute file usage (in bytes) */
272 int fd; /* open file descriptor to check */
273 int all; /* include overhead and unflushed data */
274 {
275 long total = 0;
276 register int i, j;
277
278 for (j = 0; hdlist[j] != NULL; j++) {
279 if (hdlist[j]->fd != fd)
280 continue;
281 total += biglob(hdlist[j])->nrd * sizeof(RAYVAL);
282 if (all) {
283 for (i = nbeams(hdlist[j]); i > 0; i--)
284 if (hdlist[j]->bl[i] != NULL)
285 total += sizeof(RAYVAL) *
286 (hdlist[j]->bl[i]->nrm -
287 hdlist[j]->bi[i].nrd);
288 total += sizeof(HDGRID) +
289 nbeams(hdlist[j])*sizeof(BEAMI);
290 }
291 }
292 return(total); /* does not include fragments */
293 }
294
295
296 RAYVAL *
297 hdnewrays(hp, i, nr) /* allocate space for add'l rays and return pointer */
298 register HOLO *hp;
299 register int i;
300 int nr; /* number of new rays desired */
301 {
302 RAYVAL *p;
303 int n;
304
305 if (nr <= 0)
306 return(NULL);
307 if (i < 1 | i > nbeams(hp))
308 error(CONSISTENCY, "bad beam index given to hdnewrays");
309 if (hp->bl[i] != NULL)
310 hp->bl[i]->tick = hdclock; /* preempt swap */
311 if (hdcachesize > 0 && hdmemuse(0) >= hdcachesize)
312 hdfreecache(PCTFREE, NULL); /* free some space */
313 if (hp->bl[i] == NULL) { /* allocate (and load) */
314 n = hp->bi[i].nrd + nr;
315 hp->bl[i] = (BEAM *)hdrealloc(NULL, hdbsiz(n), "hdnewrays");
316 blglob(hp)->nrm += n;
317 if (n = hp->bl[i]->nrm = hp->bi[i].nrd) {
318 errno = 0;
319 if (lseek(hp->fd, hp->bi[i].fo, 0) < 0)
320 error(SYSTEM, "seek error on holodeck file");
321 n *= sizeof(RAYVAL);
322 if (read(hp->fd, (char *)hdbray(hp->bl[i]), n) != n)
323 error(SYSTEM,
324 "error reading beam from holodeck file");
325 }
326 } else { /* just grow in memory */
327 hp->bl[i] = (BEAM *)hdrealloc((char *)hp->bl[i],
328 hdbsiz(hp->bl[i]->nrm + nr), "hdnewrays");
329 blglob(hp)->nrm += nr;
330 }
331 p = hdbray(hp->bl[i]) + hp->bl[i]->nrm;
332 hp->bl[i]->nrm += nr; /* update in-core structure */
333 bzero((char *)p, nr*sizeof(RAYVAL));
334 blglob(hp)->tick = hp->bl[i]->tick = hdclock++; /* update LRU clock */
335 return(p); /* point to new rays */
336 }
337
338
339 BEAM *
340 hdgetbeam(hp, i) /* get beam (from file if necessary) */
341 register HOLO *hp;
342 register int i;
343 {
344 register int n;
345
346 if (i < 1 | i > nbeams(hp))
347 error(CONSISTENCY, "bad beam index given to hdgetbeam");
348 if (hp->bl[i] == NULL) { /* load from disk */
349 if (!(n = hp->bi[i].nrd))
350 return(NULL);
351 if (hdcachesize > 0 && hdmemuse(0) >= hdcachesize)
352 hdfreecache(PCTFREE, NULL); /* get free space */
353 hp->bl[i] = (BEAM *)hdrealloc(NULL, hdbsiz(n), "hdgetbeam");
354 blglob(hp)->nrm += hp->bl[i]->nrm = n;
355 errno = 0;
356 if (lseek(hp->fd, hp->bi[i].fo, 0) < 0)
357 error(SYSTEM, "seek error on holodeck file");
358 n *= sizeof(RAYVAL);
359 if (read(hp->fd, (char *)hdbray(hp->bl[i]), n) != n)
360 error(SYSTEM, "error reading beam from holodeck file");
361 }
362 blglob(hp)->tick = hp->bl[i]->tick = hdclock++; /* update LRU clock */
363 return(hp->bl[i]);
364 }
365
366
367 int
368 hdfilord(hb1, hb2) /* order beams for quick loading */
369 register HDBEAMI *hb1, *hb2;
370 {
371 register long c;
372 /* residents go first */
373 if (hb2->h->bl[hb2->b] != NULL)
374 return(hb1->h->bl[hb1->b] == NULL);
375 if (hb1->h->bl[hb1->b] != NULL)
376 return(-1);
377 /* otherwise sort by file descriptor */
378 if ((c = hb1->h->fd - hb2->h->fd))
379 return(c);
380 /* then by position in file */
381 c = hb1->h->bi[hb1->b].fo - hb2->h->bi[hb2->b].fo;
382 return(c > 0 ? 1 : c < 0 ? -1 : 0);
383 }
384
385
386 hdloadbeams(hb, n, bf) /* load a list of beams in optimal order */
387 register HDBEAMI *hb; /* list gets sorted by hdfilord() */
388 int n; /* list length */
389 int (*bf)(); /* callback function (optional) */
390 {
391 unsigned origcachesize, memuse;
392 int bytesloaded, needbytes, bytes2free;
393 register BEAM *bp;
394 register int i;
395 /* precheck consistency */
396 if (n <= 0) return;
397 for (i = n; i--; )
398 if (hb[i].h == NULL || hb[i].b < 1 | hb[i].b > nbeams(hb[i].h))
399 error(CONSISTENCY, "bad beam in hdloadbeams");
400 /* sort list for optimal access */
401 qsort((char *)hb, n, sizeof(HDBEAMI), hdfilord);
402 bytesloaded = 0; /* run through loaded beams */
403 for ( ; n && (bp = hb->h->bl[hb->b]) != NULL; n--, hb++) {
404 bp->tick = hdclock; /* preempt swap */
405 bytesloaded += bp->nrm;
406 if (bf != NULL)
407 (*bf)(bp, hb);
408 }
409 bytesloaded *= sizeof(RAYVAL);
410 if ((origcachesize = hdcachesize) > 0) {
411 needbytes = 0; /* figure out memory needs */
412 for (i = n; i--; )
413 needbytes += hb[i].h->bi[hb[i].b].nrd;
414 needbytes *= sizeof(RAYVAL);
415 do { /* free enough memory */
416 memuse = hdmemuse(0);
417 bytes2free = needbytes - (int)(hdcachesize-memuse);
418 if (bytes2free > (int)(memuse - bytesloaded))
419 bytes2free = memuse - bytesloaded;
420 } while (bytes2free > 0 &&
421 hdfreecache(100*bytes2free/memuse, NULL) < 0);
422 hdcachesize = 0; /* load beams w/o swap */
423 }
424 for (i = 0; i < n; i++)
425 if ((bp = hdgetbeam(hb[i].h, hb[i].b)) != NULL && bf != NULL)
426 (*bf)(bp, hb+i);
427 hdcachesize = origcachesize; /* resume dynamic swapping */
428 }
429
430
431 hdfreefrag(fd, bi) /* free a file fragment */
432 int fd;
433 register BEAMI *bi;
434 {
435 register struct fraglist *f;
436 register int j, k;
437
438 if (bi->nrd == 0)
439 return;
440 #ifdef DEBUG
441 if (fd < 0 | fd >= nhdfragls || !hdfragl[fd].nlinks)
442 error(CONSISTENCY, "bad file descriptor in hdfreefrag");
443 #endif
444 f = &hdfragl[fd];
445 if (f->nfrags % FRAGBLK == 0) { /* delete empty remnants */
446 for (j = k = 0; k < f->nfrags; j++, k++) {
447 while (f->fi[k].nrd == 0)
448 if (++k >= f->nfrags)
449 goto endloop;
450 if (k > j)
451 copystruct(f->fi+j, f->fi+k);
452 }
453 endloop:
454 f->nfrags = j;
455 }
456 j = f->nfrags++; /* allocate a slot in free list */
457 #if MAXFRAG
458 if (j >= MAXFRAG-1)
459 f->nfrags--;
460 #endif
461 if (j % FRAGBLK == 0) { /* more free list space */
462 register BEAMI *newp;
463 if (f->fi == NULL)
464 newp = (BEAMI *)malloc((j+FRAGBLK)*sizeof(BEAMI));
465 else
466 newp = (BEAMI *)realloc((char *)f->fi,
467 (j+FRAGBLK)*sizeof(BEAMI));
468 if (newp == NULL) {
469 f->nfrags--; /* graceful failure */
470 return;
471 }
472 f->fi = newp;
473 }
474 for ( ; ; j--) { /* insert in descending list */
475 if (!j || bi->fo < f->fi[j-1].fo) {
476 f->fi[j].fo = bi->fo;
477 f->fi[j].nrd = bi->nrd;
478 break;
479 }
480 copystruct(f->fi+j, f->fi+(j-1));
481 }
482 /* coalesce adjacent fragments */
483 /* successors never empty */
484 if (j && f->fi[j-1].fo == f->fi[j].fo + f->fi[j].nrd*sizeof(RAYVAL)) {
485 f->fi[j].nrd += f->fi[j-1].nrd;
486 f->fi[j-1].nrd = 0;
487 }
488 for (k = j+1; k < f->nfrags; k++) /* get non-empty predecessor */
489 if (f->fi[k].nrd) {
490 if (f->fi[j].fo == f->fi[k].fo +
491 f->fi[k].nrd*sizeof(RAYVAL)) {
492 f->fi[k].nrd += f->fi[j].nrd;
493 f->fi[j].nrd = 0;
494 }
495 break;
496 }
497 }
498
499
500 long
501 hdallocfrag(fd, nrays) /* allocate a file fragment */
502 int fd;
503 unsigned int4 nrays;
504 {
505 register struct fraglist *f;
506 register int j, k;
507 long nfo;
508
509 if (nrays == 0)
510 return(-1L);
511 #ifdef DEBUG
512 if (fd < 0 | fd >= nhdfragls || !hdfragl[fd].nlinks)
513 error(CONSISTENCY, "bad file descriptor in hdallocfrag");
514 #endif
515 f = &hdfragl[fd];
516 k = -1; /* find closest-sized fragment */
517 for (j = f->nfrags; j-- > 0; )
518 if (f->fi[j].nrd >= nrays &&
519 (k < 0 || f->fi[j].nrd < f->fi[k].nrd))
520 if (f->fi[k=j].nrd == nrays)
521 break;
522 if (k < 0) { /* no fragment -- extend file */
523 nfo = f->flen;
524 f->flen += nrays*sizeof(RAYVAL);
525 } else { /* else use fragment */
526 nfo = f->fi[k].fo;
527 f->fi[k].fo += nrays*sizeof(RAYVAL);
528 f->fi[k].nrd -= nrays;
529 }
530 return(nfo);
531 }
532
533
534 int
535 hdsyncbeam(hp, i) /* sync beam in memory with beam on disk */
536 register HOLO *hp;
537 register int i;
538 {
539 unsigned int4 nrays;
540 unsigned int n;
541 long nfo;
542 /* check file status */
543 if (hdfragl[hp->fd].writerr)
544 return(-1);
545 #ifdef DEBUG
546 if (i < 1 | i > nbeams(hp))
547 error(CONSISTENCY, "bad beam index in hdsyncbeam");
548 #endif
549 /* is current fragment OK? */
550 if (hp->bl[i] == NULL || (nrays = hp->bl[i]->nrm) == hp->bi[i].nrd)
551 return(0);
552 if (hp->bi[i].nrd) /* relinquish old fragment */
553 hdfreefrag(hp->fd, &hp->bi[i]);
554 if (nrays) { /* get and write new fragment */
555 nfo = hdallocfrag(hp->fd, nrays);
556 errno = 0;
557 if (lseek(hp->fd, nfo, 0) < 0)
558 error(SYSTEM, "cannot seek on holodeck file");
559 n = hp->bl[i]->nrm * sizeof(RAYVAL);
560 if (write(hp->fd, (char *)hdbray(hp->bl[i]), n) != n) {
561 hdfragl[hp->fd].writerr++;
562 hdsync(NULL, 0); /* sync directories */
563 error(SYSTEM, "write error in hdsyncbeam");
564 }
565 hp->bi[i].fo = nfo;
566 } else
567 hp->bi[i].fo = 0L;
568 biglob(hp)->nrd += nrays - hp->bi[i].nrd;
569 hp->bi[i].nrd = nrays;
570 markdirty(hp); /* section directory now out of date */
571 return(1);
572 }
573
574
575 int
576 hdfreebeam(hp, i) /* free beam, writing if dirty */
577 register HOLO *hp;
578 register int i;
579 {
580 int nchanged;
581
582 if (hp == NULL) { /* clear all holodecks */
583 nchanged = 0;
584 for (i = 0; hdlist[i] != NULL; i++)
585 nchanged += hdfreebeam(hdlist[i], 0);
586 return(nchanged);
587 }
588 if (hdfragl[hp->fd].writerr) /* check for file error */
589 return(0);
590 if (i == 0) { /* clear entire holodeck */
591 nchanged = 0;
592 for (i = nbeams(hp); i > 0; i--)
593 if (hp->bl[i] != NULL)
594 nchanged += hdfreebeam(hp, i);
595 return(nchanged);
596 }
597 #ifdef DEBUG
598 if (i < 1 | i > nbeams(hp))
599 error(CONSISTENCY, "bad beam index to hdfreebeam");
600 #endif
601 if (hp->bl[i] == NULL)
602 return(0);
603 /* check for additions */
604 nchanged = hp->bl[i]->nrm - hp->bi[i].nrd;
605 if (nchanged)
606 hdsyncbeam(hp, i); /* write new fragment */
607 blglob(hp)->nrm -= hp->bl[i]->nrm;
608 free((char *)hp->bl[i]); /* free memory */
609 hp->bl[i] = NULL;
610 return(nchanged);
611 }
612
613
614 int
615 hdkillbeam(hp, i) /* delete beam from holodeck */
616 register HOLO *hp;
617 register int i;
618 {
619 static BEAM emptybeam;
620 int nchanged;
621
622 if (hp == NULL) { /* clobber all holodecks */
623 nchanged = 0;
624 for (i = 0; hdlist[i] != NULL; i++)
625 nchanged += hdkillbeam(hdlist[i], 0);
626 return(nchanged);
627 }
628 if (i == 0) { /* clobber entire holodeck */
629 nchanged = 0;
630 for (i = nbeams(hp); i > 0; i--)
631 if (hp->bi[i].nrd > 0 || hp->bl[i] != NULL)
632 nchanged += hdkillbeam(hp, i);
633 #ifdef DEBUG
634 if (biglob(hp)->nrd != 0 | blglob(hp)->nrm != 0)
635 error(CONSISTENCY, "bad beam count in hdkillbeam");
636 #endif
637 return(nchanged);
638 }
639 #ifdef DEBUG
640 if (i < 1 | i > nbeams(hp))
641 error(CONSISTENCY, "bad beam index to hdkillbeam");
642 #endif
643 if (hp->bl[i] != NULL) { /* free memory */
644 blglob(hp)->nrm -= nchanged = hp->bl[i]->nrm;
645 free((char *)hp->bl[i]);
646 } else
647 nchanged = hp->bi[i].nrd;
648 if (hp->bi[i].nrd) { /* free file fragment */
649 hp->bl[i] = &emptybeam;
650 hdsyncbeam(hp, i);
651 }
652 hp->bl[i] = NULL;
653 return(nchanged);
654 }
655
656
657 int
658 hdlrulist(hb, nents, n, hp) /* add beams from holodeck to LRU list */
659 register HDBEAMI *hb; /* beam list */
660 int nents; /* current list length */
661 int n; /* maximum list length */
662 register HOLO *hp; /* section we're adding from */
663 {
664 register int i, j;
665 /* insert each beam from hp */
666 for (i = 1; i <= nbeams(hp); i++) {
667 if (hp->bl[i] == NULL) /* check if loaded */
668 continue;
669 #if 0
670 if (hp->bl[i]->tick == hdclock) /* preempt swap? */
671 continue;
672 #endif
673 if ((j = ++nents) >= n) /* grow list if we can */
674 nents--;
675 for ( ; ; ) { /* bubble into place */
676 if (!--j || hp->bl[i]->tick >=
677 hb[j-1].h->bl[hb[j-1].b]->tick) {
678 hb[j].h = hp;
679 hb[j].b = i;
680 break;
681 }
682 copystruct(hb+j, hb+(j-1));
683 }
684 }
685 return(nents); /* return new list length */
686 }
687
688
689 int
690 hdfreecache(pct, honly) /* free up cache space, writing changes */
691 int pct; /* maximum percentage to free */
692 register HOLO *honly; /* NULL means check all */
693 {
694 HDBEAMI hb[FREEBEAMS];
695 int freetarget;
696 int n;
697 register int i;
698 #ifdef DEBUG
699 unsigned membefore;
700
701 membefore = hdmemuse(0);
702 #endif
703 /* compute free target */
704 freetarget = (honly != NULL) ? blglob(honly)->nrm :
705 hdmemuse(0)/sizeof(RAYVAL) ;
706 freetarget = freetarget*pct/100;
707 if (freetarget <= 0)
708 return(0);
709 /* find least recently used */
710 n = 0;
711 if (honly != NULL)
712 n = hdlrulist(hb, n, FREEBEAMS, honly);
713 else
714 for (i = 0; hdlist[i] != NULL; i++)
715 n = hdlrulist(hb, n, FREEBEAMS, hdlist[i]);
716 /* free LRU beams */
717 for (i = 0; i < n; i++) {
718 hdfreebeam(hb[i].h, hb[i].b);
719 if ((freetarget -= hb[i].h->bi[hb[i].b].nrd) <= 0)
720 break;
721 }
722 hdsync(honly, 0); /* synchronize directories as necessary */
723 #ifdef DEBUG
724 sprintf(errmsg,
725 "%dK before, %dK after hdfreecache (%dK total), %d rays short\n",
726 membefore>>10, hdmemuse(0)>>10, hdmemuse(1)>>10, freetarget);
727 wputs(errmsg);
728 #endif
729 return(-freetarget); /* return how far past goal we went */
730 }
731
732
733 hddone(hp) /* clean up holodeck section and free */
734 register HOLO *hp; /* NULL means clean up all */
735 {
736 register int i;
737
738 if (hp == NULL) { /* NULL means clean up everything */
739 while (hdlist[0] != NULL)
740 hddone(hdlist[0]);
741 free((char *)hdfragl);
742 hdfragl = NULL; nhdfragls = 0;
743 return;
744 }
745 /* flush all data and free memory */
746 hdflush(hp);
747 /* release fragment resources */
748 hdrelease(hp->fd);
749 /* remove hp from active list */
750 for (i = 0; hdlist[i] != NULL; i++)
751 if (hdlist[i] == hp) {
752 while ((hdlist[i] = hdlist[i+1]) != NULL)
753 i++;
754 break;
755 }
756 free((char *)hp->bl); /* free beam list */
757 free((char *)hp); /* free holodeck struct */
758 }