ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambient.c
Revision: 2.44
Committed: Wed Jun 17 13:29:55 1998 UTC (25 years, 10 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 2.43: +0 -1 lines
Log Message:
moved lseek() and ftell() declarations to standard.h

File Contents

# Content
1 /* Copyright (c) 1996 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * ambient.c - routines dealing with ambient (inter-reflected) component.
9 */
10
11 #include "ray.h"
12
13 #include "octree.h"
14
15 #include "otypes.h"
16
17 #include "ambient.h"
18
19 #include "random.h"
20
21 #ifndef OCTSCALE
22 #define OCTSCALE 1.0 /* ceil((valid rad.)/(cube size)) */
23 #endif
24
25 typedef struct ambtree {
26 AMBVAL *alist; /* ambient value list */
27 struct ambtree *kid; /* 8 child nodes */
28 } AMBTREE; /* ambient octree */
29
30 extern CUBE thescene; /* contains space boundaries */
31
32 extern char *shm_boundary; /* memory sharing boundary */
33
34 #define MAXASET 511 /* maximum number of elements in ambient set */
35 OBJECT ambset[MAXASET+1]={0}; /* ambient include/exclude set */
36
37 double maxarad; /* maximum ambient radius */
38 double minarad; /* minimum ambient radius */
39
40 static AMBTREE atrunk; /* our ambient trunk node */
41
42 static FILE *ambfp = NULL; /* ambient file pointer */
43 static int nunflshed = 0; /* number of unflushed ambient values */
44
45 #ifndef SORT_THRESH
46 #ifdef BIGMEM
47 #define SORT_THRESH ((9L<<20)/sizeof(AMBVAL))
48 #else
49 #define SORT_THRESH ((3L<<20)/sizeof(AMBVAL))
50 #endif
51 #endif
52 #ifndef SORT_INTVL
53 #define SORT_INTVL (SORT_THRESH<<1)
54 #endif
55 #ifndef MAX_SORT_INTVL
56 #define MAX_SORT_INTVL (SORT_INTVL<<6)
57 #endif
58
59 static double avsum = 0.; /* computed ambient value sum (log) */
60 static unsigned int navsum = 0; /* number of values in avsum */
61 static unsigned int nambvals = 0; /* total number of indirect values */
62 static unsigned int nambshare = 0; /* number of values from file */
63 static unsigned long ambclock = 0; /* ambient access clock */
64 static unsigned long lastsort = 0; /* time of last value sort */
65 static long sortintvl = SORT_INTVL; /* time until next sort */
66
67 #define MAXACLOCK (1L<<30) /* clock turnover value */
68 /*
69 * Track access times unless we are sharing ambient values
70 * through memory on a multiprocessor, when we want to avoid
71 * claiming our own memory (copy on write). Go ahead anyway
72 * if more than two thirds of our values are unshared.
73 * Compile with -Dtracktime=0 to turn this code off.
74 */
75 #ifndef tracktime
76 #define tracktime (shm_boundary == NULL || nambvals > 3*nambshare)
77 #endif
78
79 #define AMBFLUSH (BUFSIZ/AMBVALSIZ)
80
81 #define newambval() (AMBVAL *)bmalloc(sizeof(AMBVAL))
82
83 static int initambfile(), avsave(), avinsert(), sortambvals(), avlmemi();
84 static AMBVAL *avstore();
85 #ifdef F_SETLKW
86 static aflock();
87 #endif
88
89
90 setambres(ar) /* set ambient resolution */
91 int ar;
92 {
93 ambres = ar < 0 ? 0 : ar; /* may be done already */
94 /* set min & max radii */
95 if (ar <= 0) {
96 minarad = 0;
97 maxarad = thescene.cusize / 2.0;
98 } else {
99 minarad = thescene.cusize / ar;
100 maxarad = 64 * minarad; /* heuristic */
101 if (maxarad > thescene.cusize / 2.0)
102 maxarad = thescene.cusize / 2.0;
103 }
104 if (minarad <= FTINY)
105 minarad = 10*FTINY;
106 if (maxarad <= minarad)
107 maxarad = 64 * minarad;
108 }
109
110
111 setambacc(newa) /* set ambient accuracy */
112 double newa;
113 {
114 double ambdiff;
115
116 if (newa < 0.0)
117 newa = 0.0;
118 ambdiff = fabs(newa - ambacc);
119 if (ambdiff >= .01 && (ambacc = newa) > FTINY && nambvals > 0)
120 sortambvals(1); /* rebuild tree */
121 }
122
123
124 setambient(afile) /* initialize calculation */
125 char *afile;
126 {
127 long pos, flen;
128 AMBVAL amb;
129 /* init ambient limits */
130 setambres(ambres);
131 setambacc(ambacc);
132 if (afile == NULL)
133 return;
134 if (ambacc <= FTINY) {
135 sprintf(errmsg, "zero ambient accuracy so \"%s\" not opened",
136 afile);
137 error(WARNING, errmsg);
138 return;
139 }
140 /* open ambient file */
141 if ((ambfp = fopen(afile, "r+")) != NULL) {
142 initambfile(0);
143 pos = ftell(ambfp);
144 while (readambval(&amb, ambfp))
145 avinsert(avstore(&amb));
146 /* align */
147 pos += (long)nambvals*AMBVALSIZ;
148 flen = lseek(fileno(ambfp), 0L, 2);
149 if (flen != pos) {
150 sprintf(errmsg,
151 "ignoring last %ld values in ambient file (corrupted)",
152 (flen - pos)/AMBVALSIZ);
153 error(WARNING, errmsg);
154 fseek(ambfp, pos, 0);
155 ftruncate(fileno(ambfp), pos);
156 }
157 nambshare = nambvals;
158 } else if ((ambfp = fopen(afile, "w+")) != NULL)
159 initambfile(1);
160 else {
161 sprintf(errmsg, "cannot open ambient file \"%s\"", afile);
162 error(SYSTEM, errmsg);
163 }
164 nunflshed++; /* lie */
165 ambsync();
166 }
167
168
169 ambnotify(obj) /* record new modifier */
170 OBJECT obj;
171 {
172 static int hitlimit = 0;
173 register OBJREC *o = objptr(obj);
174 register char **amblp;
175
176 if (hitlimit || !ismodifier(o->otype))
177 return;
178 for (amblp = amblist; *amblp != NULL; amblp++)
179 if (!strcmp(o->oname, *amblp)) {
180 if (ambset[0] >= MAXASET) {
181 error(WARNING, "too many modifiers in ambient list");
182 hitlimit++;
183 return; /* should this be fatal? */
184 }
185 insertelem(ambset, obj);
186 return;
187 }
188 }
189
190
191 ambient(acol, r, nrm) /* compute ambient component for ray */
192 COLOR acol;
193 register RAY *r;
194 FVECT nrm;
195 {
196 static int rdepth = 0; /* ambient recursion */
197 double d, l;
198
199 if (ambdiv <= 0) /* no ambient calculation */
200 goto dumbamb;
201 /* check number of bounces */
202 if (rdepth >= ambounce)
203 goto dumbamb;
204 /* check ambient list */
205 if (ambincl != -1 && r->ro != NULL &&
206 ambincl != inset(ambset, r->ro->omod))
207 goto dumbamb;
208
209 if (ambacc <= FTINY) { /* no ambient storage */
210 rdepth++;
211 d = doambient(acol, r, r->rweight, NULL, NULL);
212 rdepth--;
213 if (d <= FTINY)
214 goto dumbamb;
215 return;
216 }
217
218 if (tracktime) /* sort to minimize thrashing */
219 sortambvals(0);
220 /* get ambient value */
221 setcolor(acol, 0.0, 0.0, 0.0);
222 d = sumambient(acol, r, nrm, rdepth,
223 &atrunk, thescene.cuorg, thescene.cusize);
224 if (d > FTINY) {
225 scalecolor(acol, 1.0/d);
226 return;
227 }
228 rdepth++; /* need to cache new value */
229 d = makeambient(acol, r, nrm, rdepth-1);
230 rdepth--;
231 if (d > FTINY)
232 return;
233 dumbamb: /* return global value */
234 copycolor(acol, ambval);
235 if (ambvwt <= 0 | navsum == 0)
236 return;
237 l = bright(ambval); /* average in computations */
238 if (l > FTINY) {
239 d = (log(l)*(double)ambvwt + avsum) /
240 (double)(ambvwt + navsum);
241 d = exp(d) / l;
242 scalecolor(acol, d); /* apply color of ambval */
243 } else {
244 d = exp( avsum / (double)navsum );
245 setcolor(acol, d, d, d); /* neutral color */
246 }
247 }
248
249
250 double
251 sumambient(acol, r, rn, al, at, c0, s) /* get interpolated ambient value */
252 COLOR acol;
253 register RAY *r;
254 FVECT rn;
255 int al;
256 AMBTREE *at;
257 FVECT c0;
258 double s;
259 {
260 double d, e1, e2, wt, wsum;
261 COLOR ct;
262 FVECT ck0;
263 int i;
264 register int j;
265 register AMBVAL *av;
266
267 wsum = 0.0;
268 /* do this node */
269 for (av = at->alist; av != NULL; av = av->next) {
270 if (tracktime)
271 av->latick = ambclock;
272 /*
273 * Ambient level test.
274 */
275 if (av->lvl > al) /* list sorted, so this works */
276 break;
277 if (av->weight < r->rweight-FTINY)
278 continue;
279 /*
280 * Ambient radius test.
281 */
282 d = av->pos[0] - r->rop[0];
283 e1 = d * d;
284 d = av->pos[1] - r->rop[1];
285 e1 += d * d;
286 d = av->pos[2] - r->rop[2];
287 e1 += d * d;
288 e1 /= av->rad * av->rad;
289 if (e1 > ambacc*ambacc*1.21)
290 continue;
291 /*
292 * Normal direction test.
293 */
294 e2 = (1.0 - DOT(av->dir, r->ron)) * r->rweight;
295 if (e2 < 0.0) e2 = 0.0;
296 if (e1 + e2 > ambacc*ambacc*1.21)
297 continue;
298 /*
299 * Ray behind test.
300 */
301 d = 0.0;
302 for (j = 0; j < 3; j++)
303 d += (r->rop[j] - av->pos[j]) *
304 (av->dir[j] + r->ron[j]);
305 if (d*0.5 < -minarad*ambacc-.001)
306 continue;
307 /*
308 * Jittering final test reduces image artifacts.
309 */
310 wt = sqrt(e1) + sqrt(e2);
311 if (wt > ambacc*(.9+.2*urand(9015+samplendx)))
312 continue;
313 if (wt <= 1e-3)
314 wt = 1e3;
315 else
316 wt = 1.0 / wt;
317 wsum += wt;
318 extambient(ct, av, r->rop, rn);
319 scalecolor(ct, wt);
320 addcolor(acol, ct);
321 }
322 if (at->kid == NULL)
323 return(wsum);
324 /* do children */
325 s *= 0.5;
326 for (i = 0; i < 8; i++) {
327 for (j = 0; j < 3; j++) {
328 ck0[j] = c0[j];
329 if (1<<j & i)
330 ck0[j] += s;
331 if (r->rop[j] < ck0[j] - OCTSCALE*s)
332 break;
333 if (r->rop[j] > ck0[j] + (1.0+OCTSCALE)*s)
334 break;
335 }
336 if (j == 3)
337 wsum += sumambient(acol, r, rn, al, at->kid+i, ck0, s);
338 }
339 return(wsum);
340 }
341
342
343 double
344 makeambient(acol, r, rn, al) /* make a new ambient value */
345 COLOR acol;
346 register RAY *r;
347 FVECT rn;
348 int al;
349 {
350 AMBVAL amb;
351 FVECT gp, gd;
352 /* compute weight */
353 amb.weight = pow(AVGREFL, (double)al);
354 if (r->rweight < 0.1*amb.weight) /* heuristic */
355 amb.weight = r->rweight;
356 /* compute ambient */
357 amb.rad = doambient(acol, r, amb.weight, gp, gd);
358 if (amb.rad <= FTINY)
359 return(0.0);
360 /* store it */
361 VCOPY(amb.pos, r->rop);
362 VCOPY(amb.dir, r->ron);
363 amb.lvl = al;
364 copycolor(amb.val, acol);
365 VCOPY(amb.gpos, gp);
366 VCOPY(amb.gdir, gd);
367 /* insert into tree */
368 avsave(&amb); /* and save to file */
369 if (rn != r->ron)
370 extambient(acol, &amb, r->rop, rn); /* texture */
371 return(amb.rad);
372 }
373
374
375 extambient(cr, ap, pv, nv) /* extrapolate value at pv, nv */
376 COLOR cr;
377 register AMBVAL *ap;
378 FVECT pv, nv;
379 {
380 FVECT v1, v2;
381 register int i;
382 double d;
383
384 d = 1.0; /* zeroeth order */
385 /* gradient due to translation */
386 for (i = 0; i < 3; i++)
387 d += ap->gpos[i]*(pv[i]-ap->pos[i]);
388 /* gradient due to rotation */
389 VCOPY(v1, ap->dir);
390 fcross(v2, v1, nv);
391 d += DOT(ap->gdir, v2);
392 if (d <= 0.0) {
393 setcolor(cr, 0.0, 0.0, 0.0);
394 return;
395 }
396 copycolor(cr, ap->val);
397 scalecolor(cr, d);
398 }
399
400
401 static
402 initambfile(creat) /* initialize ambient file */
403 int creat;
404 {
405 extern char *progname, *octname, VersionID[];
406
407 #ifdef F_SETLKW
408 aflock(creat ? F_WRLCK : F_RDLCK);
409 #endif
410 #ifdef MSDOS
411 setmode(fileno(ambfp), O_BINARY);
412 #endif
413 setbuf(ambfp, bmalloc(BUFSIZ+8));
414 if (creat) { /* new file */
415 newheader("RADIANCE", ambfp);
416 fprintf(ambfp, "%s -av %g %g %g -aw %d -ab %d -aa %g ",
417 progname, colval(ambval,RED),
418 colval(ambval,GRN), colval(ambval,BLU),
419 ambvwt, ambounce, ambacc);
420 fprintf(ambfp, "-ad %d -as %d -ar %d %s\n",
421 ambdiv, ambssamp, ambres,
422 octname==NULL ? "" : octname);
423 fprintf(ambfp, "SOFTWARE= %s\n", VersionID);
424 fputformat(AMBFMT, ambfp);
425 putc('\n', ambfp);
426 putambmagic(ambfp);
427 } else if (checkheader(ambfp, AMBFMT, NULL) < 0 || !hasambmagic(ambfp))
428 error(USER, "bad ambient file");
429 }
430
431
432 static
433 avsave(av) /* insert and save an ambient value */
434 AMBVAL *av;
435 {
436 avinsert(avstore(av));
437 if (ambfp == NULL)
438 return;
439 if (writambval(av, ambfp) < 0)
440 goto writerr;
441 if (++nunflshed >= AMBFLUSH)
442 if (ambsync() == EOF)
443 goto writerr;
444 return;
445 writerr:
446 error(SYSTEM, "error writing ambient file");
447 }
448
449
450 static AMBVAL *
451 avstore(aval) /* allocate memory and store aval */
452 register AMBVAL *aval;
453 {
454 register AMBVAL *av;
455 double d;
456
457 if ((av = newambval()) == NULL)
458 error(SYSTEM, "out of memory in avstore");
459 copystruct(av, aval);
460 av->latick = ambclock;
461 av->next = NULL;
462 nambvals++;
463 d = bright(av->val);
464 if (d > FTINY) { /* add to log sum for averaging */
465 avsum += log(d);
466 navsum++;
467 }
468 return(av);
469 }
470
471
472 #define ATALLOCSZ 512 /* #/8 trees to allocate at once */
473
474 static AMBTREE *atfreelist = NULL; /* free ambient tree structures */
475
476
477 static
478 AMBTREE *
479 newambtree() /* allocate 8 ambient tree structs */
480 {
481 register AMBTREE *atp, *upperlim;
482
483 if (atfreelist == NULL) { /* get more nodes */
484 atfreelist = (AMBTREE *)bmalloc(ATALLOCSZ*8*sizeof(AMBTREE));
485 if (atfreelist == NULL)
486 return(NULL);
487 /* link new free list */
488 upperlim = atfreelist + 8*(ATALLOCSZ-1);
489 for (atp = atfreelist; atp < upperlim; atp += 8)
490 atp->kid = atp + 8;
491 atp->kid = NULL;
492 }
493 atp = atfreelist;
494 atfreelist = atp->kid;
495 bzero((char *)atp, 8*sizeof(AMBTREE));
496 return(atp);
497 }
498
499
500 static
501 freeambtree(atp) /* free 8 ambient tree structs */
502 AMBTREE *atp;
503 {
504 atp->kid = atfreelist;
505 atfreelist = atp;
506 }
507
508
509 static
510 avinsert(av) /* insert ambient value in our tree */
511 register AMBVAL *av;
512 {
513 register AMBTREE *at;
514 register AMBVAL *ap;
515 AMBVAL avh;
516 FVECT ck0;
517 double s;
518 int branch;
519 register int i;
520
521 if (av->rad <= FTINY)
522 error(CONSISTENCY, "zero ambient radius in avinsert");
523 at = &atrunk;
524 VCOPY(ck0, thescene.cuorg);
525 s = thescene.cusize;
526 while (s*(OCTSCALE/2) > av->rad*ambacc) {
527 if (at->kid == NULL)
528 if ((at->kid = newambtree()) == NULL)
529 error(SYSTEM, "out of memory in avinsert");
530 s *= 0.5;
531 branch = 0;
532 for (i = 0; i < 3; i++)
533 if (av->pos[i] > ck0[i] + s) {
534 ck0[i] += s;
535 branch |= 1 << i;
536 }
537 at = at->kid + branch;
538 }
539 avh.next = at->alist; /* order by increasing level */
540 for (ap = &avh; ap->next != NULL; ap = ap->next)
541 if (ap->next->lvl >= av->lvl)
542 break;
543 av->next = ap->next;
544 ap->next = av;
545 at->alist = avh.next;
546 }
547
548
549 static
550 unloadatree(at, f) /* unload an ambient value tree */
551 register AMBTREE *at;
552 int (*f)();
553 {
554 register AMBVAL *av;
555 register int i;
556 /* transfer values at this node */
557 for (av = at->alist; av != NULL; av = at->alist) {
558 at->alist = av->next;
559 (*f)(av);
560 }
561 if (at->kid == NULL)
562 return;
563 for (i = 0; i < 8; i++) /* transfer and free children */
564 unloadatree(at->kid+i, f);
565 freeambtree(at->kid);
566 at->kid = NULL;
567 }
568
569
570 static struct avl {
571 AMBVAL *p;
572 unsigned long t;
573 } *avlist1; /* ambient value list with ticks */
574 static AMBVAL **avlist2; /* memory positions for sorting */
575 static int i_avlist; /* index for lists */
576
577
578 static
579 av2list(av)
580 register AMBVAL *av;
581 {
582 #ifdef DEBUG
583 if (i_avlist >= nambvals)
584 error(CONSISTENCY, "too many ambient values in av2list1");
585 #endif
586 avlist1[i_avlist].p = avlist2[i_avlist] = av;
587 avlist1[i_avlist++].t = av->latick;
588 }
589
590
591 static int
592 alatcmp(av1, av2) /* compare ambient values for MRA */
593 struct avl *av1, *av2;
594 {
595 register long lc = av2->t - av1->t;
596 return(lc<0 ? -1 : lc>0 ? 1 : 0);
597 }
598
599
600 static int
601 aposcmp(avp1, avp2) /* compare ambient value positions */
602 AMBVAL **avp1, **avp2;
603 {
604 return(*avp1 - *avp2);
605 }
606
607
608 #if 1
609 static int
610 avlmemi(avaddr) /* find list position from address */
611 AMBVAL *avaddr;
612 {
613 register AMBVAL **avlpp;
614
615 avlpp = (AMBVAL **)bsearch((char *)&avaddr, (char *)avlist2,
616 nambvals, sizeof(AMBVAL *), aposcmp);
617 if (avlpp == NULL)
618 error(CONSISTENCY, "address not found in avlmemi");
619 return(avlpp - avlist2);
620 }
621 #else
622 #define avlmemi(avaddr) ((AMBVAL **)bsearch((char *)&avaddr,(char *)avlist2, \
623 nambvals,sizeof(AMBVAL *),aposcmp) - avlist2)
624 #endif
625
626
627 static
628 sortambvals(always) /* resort ambient values */
629 int always;
630 {
631 AMBTREE oldatrunk;
632 AMBVAL tav, *tap, *pnext;
633 register int i, j;
634 /* see if it's time yet */
635 if (!always && (ambclock++ < lastsort+sortintvl ||
636 nambvals < SORT_THRESH))
637 return;
638 /*
639 * The idea here is to minimize memory thrashing
640 * in VM systems by improving reference locality.
641 * We do this by periodically sorting our stored ambient
642 * values in memory in order of most recently to least
643 * recently accessed. This ordering was chosen so that new
644 * ambient values (which tend to be less important) go into
645 * higher memory with the infrequently accessed values.
646 * Since we expect our values to need sorting less
647 * frequently as the process continues, we double our
648 * waiting interval after each call.
649 * This routine is also called by setambacc() with
650 * the "always" parameter set to 1 so that the ambient
651 * tree will be rebuilt with the new accuracy parameter.
652 */
653 if (tracktime) { /* allocate pointer arrays to sort */
654 avlist2 = (AMBVAL **)malloc(nambvals*sizeof(AMBVAL *));
655 avlist1 = (struct avl *)malloc(nambvals*sizeof(struct avl));
656 } else {
657 avlist2 = NULL;
658 avlist1 = NULL;
659 }
660 if (avlist1 == NULL) { /* no time tracking -- rebuild tree? */
661 if (avlist2 != NULL)
662 free((char *)avlist2);
663 if (always) { /* rebuild without sorting */
664 copystruct(&oldatrunk, &atrunk);
665 atrunk.alist = NULL;
666 atrunk.kid = NULL;
667 unloadatree(&oldatrunk, avinsert);
668 }
669 } else { /* sort memory by last access time */
670 /*
671 * Sorting memory is tricky because it isn't contiguous.
672 * We have to sort an array of pointers by MRA and also
673 * by memory position. We then copy values in "loops"
674 * to minimize memory hits. Nevertheless, we will visit
675 * everyone at least twice, and this is an expensive process
676 * when we're thrashing, which is when we need to do it.
677 */
678 #ifdef DEBUG
679 sprintf(errmsg, "sorting %u ambient values at ambclock=%lu...",
680 nambvals, ambclock);
681 eputs(errmsg);
682 #endif
683 i_avlist = 0;
684 unloadatree(&atrunk, av2list); /* empty current tree */
685 #ifdef DEBUG
686 if (i_avlist < nambvals)
687 error(CONSISTENCY, "missing ambient values in sortambvals");
688 #endif
689 qsort((char *)avlist1, nambvals, sizeof(struct avl), alatcmp);
690 qsort((char *)avlist2, nambvals, sizeof(AMBVAL *), aposcmp);
691 for (i = 0; i < nambvals; i++) {
692 if (avlist1[i].p == NULL)
693 continue;
694 tap = avlist2[i];
695 copystruct(&tav, tap);
696 for (j = i; (pnext = avlist1[j].p) != tap;
697 j = avlmemi(pnext)) {
698 copystruct(avlist2[j], pnext);
699 avinsert(avlist2[j]);
700 avlist1[j].p = NULL;
701 }
702 copystruct(avlist2[j], &tav);
703 avinsert(avlist2[j]);
704 avlist1[j].p = NULL;
705 }
706 free((char *)avlist1);
707 free((char *)avlist2);
708 /* compute new sort interval */
709 sortintvl = ambclock - lastsort;
710 if (sortintvl >= MAX_SORT_INTVL/2)
711 sortintvl = MAX_SORT_INTVL;
712 else
713 sortintvl <<= 1; /* wait twice as long next */
714 #ifdef DEBUG
715 eputs("done\n");
716 #endif
717 }
718 if (ambclock >= MAXACLOCK)
719 ambclock = MAXACLOCK/2;
720 lastsort = ambclock;
721 }
722
723
724 #ifdef F_SETLKW
725
726 static
727 aflock(typ) /* lock/unlock ambient file */
728 int typ;
729 {
730 static struct flock fls; /* static so initialized to zeroes */
731
732 fls.l_type = typ;
733 if (fcntl(fileno(ambfp), F_SETLKW, &fls) < 0)
734 error(SYSTEM, "cannot (un)lock ambient file");
735 }
736
737
738 int
739 ambsync() /* synchronize ambient file */
740 {
741 static FILE *ambinp = NULL;
742 static long lastpos = -1;
743 long flen;
744 AMBVAL avs;
745 register int n;
746
747 if (nunflshed == 0)
748 return(0);
749 if (lastpos < 0) /* initializing (locked in initambfile) */
750 goto syncend;
751 /* gain exclusive access */
752 aflock(F_WRLCK);
753 /* see if file has grown */
754 if ((flen = lseek(fileno(ambfp), 0L, 2)) < 0)
755 goto seekerr;
756 if (n = flen - lastpos) { /* file has grown */
757 if (ambinp == NULL) { /* use duplicate filedes */
758 ambinp = fdopen(dup(fileno(ambfp)), "r");
759 if (ambinp == NULL)
760 error(SYSTEM, "fdopen failed in ambsync");
761 }
762 if (fseek(ambinp, lastpos, 0) < 0)
763 goto seekerr;
764 while (n >= AMBVALSIZ) { /* load contributed values */
765 if (!readambval(&avs, ambinp)) {
766 sprintf(errmsg,
767 "ambient file corrupted near character %ld",
768 flen - n);
769 error(WARNING, errmsg);
770 break;
771 }
772 avinsert(avstore(&avs));
773 n -= AMBVALSIZ;
774 }
775 /*** seek always as safety measure
776 if (n) ***/ /* alignment */
777 if (lseek(fileno(ambfp), flen-n, 0) < 0)
778 goto seekerr;
779 }
780 #ifdef DEBUG
781 if (ambfp->_ptr - ambfp->_base != nunflshed*AMBVALSIZ) {
782 sprintf(errmsg, "ambient file buffer at %d rather than %d",
783 ambfp->_ptr - ambfp->_base,
784 nunflshed*AMBVALSIZ);
785 error(CONSISTENCY, errmsg);
786 }
787 #endif
788 syncend:
789 n = fflush(ambfp); /* calls write() at last */
790 if ((lastpos = lseek(fileno(ambfp), 0L, 1)) < 0)
791 goto seekerr;
792 aflock(F_UNLCK); /* release file */
793 nunflshed = 0;
794 return(n);
795 seekerr:
796 error(SYSTEM, "seek failed in ambsync");
797 }
798
799 #else
800
801 int
802 ambsync() /* flush ambient file */
803 {
804 if (nunflshed == 0)
805 return(0);
806 nunflshed = 0;
807 return(fflush(ambfp));
808 }
809
810 #endif