ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambient.c
Revision: 2.45
Committed: Wed Aug 12 18:16:07 1998 UTC (25 years, 8 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 2.44: +3 -4 lines
Log Message:
changed to using VCROSS() macro in extambient()

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;
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 VCROSS(v1, ap->dir, nv);
390 d += DOT(ap->gdir, v1);
391 if (d <= 0.0) {
392 setcolor(cr, 0.0, 0.0, 0.0);
393 return;
394 }
395 copycolor(cr, ap->val);
396 scalecolor(cr, d);
397 }
398
399
400 static
401 initambfile(creat) /* initialize ambient file */
402 int creat;
403 {
404 extern char *progname, *octname, VersionID[];
405
406 #ifdef F_SETLKW
407 aflock(creat ? F_WRLCK : F_RDLCK);
408 #endif
409 #ifdef MSDOS
410 setmode(fileno(ambfp), O_BINARY);
411 #endif
412 setbuf(ambfp, bmalloc(BUFSIZ+8));
413 if (creat) { /* new file */
414 newheader("RADIANCE", ambfp);
415 fprintf(ambfp, "%s -av %g %g %g -aw %d -ab %d -aa %g ",
416 progname, colval(ambval,RED),
417 colval(ambval,GRN), colval(ambval,BLU),
418 ambvwt, ambounce, ambacc);
419 fprintf(ambfp, "-ad %d -as %d -ar %d %s\n",
420 ambdiv, ambssamp, ambres,
421 octname==NULL ? "" : octname);
422 fprintf(ambfp, "SOFTWARE= %s\n", VersionID);
423 fputformat(AMBFMT, ambfp);
424 putc('\n', ambfp);
425 putambmagic(ambfp);
426 } else if (checkheader(ambfp, AMBFMT, NULL) < 0 || !hasambmagic(ambfp))
427 error(USER, "bad ambient file");
428 }
429
430
431 static
432 avsave(av) /* insert and save an ambient value */
433 AMBVAL *av;
434 {
435 avinsert(avstore(av));
436 if (ambfp == NULL)
437 return;
438 if (writambval(av, ambfp) < 0)
439 goto writerr;
440 if (++nunflshed >= AMBFLUSH)
441 if (ambsync() == EOF)
442 goto writerr;
443 return;
444 writerr:
445 error(SYSTEM, "error writing ambient file");
446 }
447
448
449 static AMBVAL *
450 avstore(aval) /* allocate memory and store aval */
451 register AMBVAL *aval;
452 {
453 register AMBVAL *av;
454 double d;
455
456 if ((av = newambval()) == NULL)
457 error(SYSTEM, "out of memory in avstore");
458 copystruct(av, aval);
459 av->latick = ambclock;
460 av->next = NULL;
461 nambvals++;
462 d = bright(av->val);
463 if (d > FTINY) { /* add to log sum for averaging */
464 avsum += log(d);
465 navsum++;
466 }
467 return(av);
468 }
469
470
471 #define ATALLOCSZ 512 /* #/8 trees to allocate at once */
472
473 static AMBTREE *atfreelist = NULL; /* free ambient tree structures */
474
475
476 static
477 AMBTREE *
478 newambtree() /* allocate 8 ambient tree structs */
479 {
480 register AMBTREE *atp, *upperlim;
481
482 if (atfreelist == NULL) { /* get more nodes */
483 atfreelist = (AMBTREE *)bmalloc(ATALLOCSZ*8*sizeof(AMBTREE));
484 if (atfreelist == NULL)
485 return(NULL);
486 /* link new free list */
487 upperlim = atfreelist + 8*(ATALLOCSZ-1);
488 for (atp = atfreelist; atp < upperlim; atp += 8)
489 atp->kid = atp + 8;
490 atp->kid = NULL;
491 }
492 atp = atfreelist;
493 atfreelist = atp->kid;
494 bzero((char *)atp, 8*sizeof(AMBTREE));
495 return(atp);
496 }
497
498
499 static
500 freeambtree(atp) /* free 8 ambient tree structs */
501 AMBTREE *atp;
502 {
503 atp->kid = atfreelist;
504 atfreelist = atp;
505 }
506
507
508 static
509 avinsert(av) /* insert ambient value in our tree */
510 register AMBVAL *av;
511 {
512 register AMBTREE *at;
513 register AMBVAL *ap;
514 AMBVAL avh;
515 FVECT ck0;
516 double s;
517 int branch;
518 register int i;
519
520 if (av->rad <= FTINY)
521 error(CONSISTENCY, "zero ambient radius in avinsert");
522 at = &atrunk;
523 VCOPY(ck0, thescene.cuorg);
524 s = thescene.cusize;
525 while (s*(OCTSCALE/2) > av->rad*ambacc) {
526 if (at->kid == NULL)
527 if ((at->kid = newambtree()) == NULL)
528 error(SYSTEM, "out of memory in avinsert");
529 s *= 0.5;
530 branch = 0;
531 for (i = 0; i < 3; i++)
532 if (av->pos[i] > ck0[i] + s) {
533 ck0[i] += s;
534 branch |= 1 << i;
535 }
536 at = at->kid + branch;
537 }
538 avh.next = at->alist; /* order by increasing level */
539 for (ap = &avh; ap->next != NULL; ap = ap->next)
540 if (ap->next->lvl >= av->lvl)
541 break;
542 av->next = ap->next;
543 ap->next = av;
544 at->alist = avh.next;
545 }
546
547
548 static
549 unloadatree(at, f) /* unload an ambient value tree */
550 register AMBTREE *at;
551 int (*f)();
552 {
553 register AMBVAL *av;
554 register int i;
555 /* transfer values at this node */
556 for (av = at->alist; av != NULL; av = at->alist) {
557 at->alist = av->next;
558 (*f)(av);
559 }
560 if (at->kid == NULL)
561 return;
562 for (i = 0; i < 8; i++) /* transfer and free children */
563 unloadatree(at->kid+i, f);
564 freeambtree(at->kid);
565 at->kid = NULL;
566 }
567
568
569 static struct avl {
570 AMBVAL *p;
571 unsigned long t;
572 } *avlist1; /* ambient value list with ticks */
573 static AMBVAL **avlist2; /* memory positions for sorting */
574 static int i_avlist; /* index for lists */
575
576
577 static
578 av2list(av)
579 register AMBVAL *av;
580 {
581 #ifdef DEBUG
582 if (i_avlist >= nambvals)
583 error(CONSISTENCY, "too many ambient values in av2list1");
584 #endif
585 avlist1[i_avlist].p = avlist2[i_avlist] = av;
586 avlist1[i_avlist++].t = av->latick;
587 }
588
589
590 static int
591 alatcmp(av1, av2) /* compare ambient values for MRA */
592 struct avl *av1, *av2;
593 {
594 register long lc = av2->t - av1->t;
595 return(lc<0 ? -1 : lc>0 ? 1 : 0);
596 }
597
598
599 static int
600 aposcmp(avp1, avp2) /* compare ambient value positions */
601 AMBVAL **avp1, **avp2;
602 {
603 return(*avp1 - *avp2);
604 }
605
606
607 #if 1
608 static int
609 avlmemi(avaddr) /* find list position from address */
610 AMBVAL *avaddr;
611 {
612 register AMBVAL **avlpp;
613
614 avlpp = (AMBVAL **)bsearch((char *)&avaddr, (char *)avlist2,
615 nambvals, sizeof(AMBVAL *), aposcmp);
616 if (avlpp == NULL)
617 error(CONSISTENCY, "address not found in avlmemi");
618 return(avlpp - avlist2);
619 }
620 #else
621 #define avlmemi(avaddr) ((AMBVAL **)bsearch((char *)&avaddr,(char *)avlist2, \
622 nambvals,sizeof(AMBVAL *),aposcmp) - avlist2)
623 #endif
624
625
626 static
627 sortambvals(always) /* resort ambient values */
628 int always;
629 {
630 AMBTREE oldatrunk;
631 AMBVAL tav, *tap, *pnext;
632 register int i, j;
633 /* see if it's time yet */
634 if (!always && (ambclock++ < lastsort+sortintvl ||
635 nambvals < SORT_THRESH))
636 return;
637 /*
638 * The idea here is to minimize memory thrashing
639 * in VM systems by improving reference locality.
640 * We do this by periodically sorting our stored ambient
641 * values in memory in order of most recently to least
642 * recently accessed. This ordering was chosen so that new
643 * ambient values (which tend to be less important) go into
644 * higher memory with the infrequently accessed values.
645 * Since we expect our values to need sorting less
646 * frequently as the process continues, we double our
647 * waiting interval after each call.
648 * This routine is also called by setambacc() with
649 * the "always" parameter set to 1 so that the ambient
650 * tree will be rebuilt with the new accuracy parameter.
651 */
652 if (tracktime) { /* allocate pointer arrays to sort */
653 avlist2 = (AMBVAL **)malloc(nambvals*sizeof(AMBVAL *));
654 avlist1 = (struct avl *)malloc(nambvals*sizeof(struct avl));
655 } else {
656 avlist2 = NULL;
657 avlist1 = NULL;
658 }
659 if (avlist1 == NULL) { /* no time tracking -- rebuild tree? */
660 if (avlist2 != NULL)
661 free((char *)avlist2);
662 if (always) { /* rebuild without sorting */
663 copystruct(&oldatrunk, &atrunk);
664 atrunk.alist = NULL;
665 atrunk.kid = NULL;
666 unloadatree(&oldatrunk, avinsert);
667 }
668 } else { /* sort memory by last access time */
669 /*
670 * Sorting memory is tricky because it isn't contiguous.
671 * We have to sort an array of pointers by MRA and also
672 * by memory position. We then copy values in "loops"
673 * to minimize memory hits. Nevertheless, we will visit
674 * everyone at least twice, and this is an expensive process
675 * when we're thrashing, which is when we need to do it.
676 */
677 #ifdef DEBUG
678 sprintf(errmsg, "sorting %u ambient values at ambclock=%lu...",
679 nambvals, ambclock);
680 eputs(errmsg);
681 #endif
682 i_avlist = 0;
683 unloadatree(&atrunk, av2list); /* empty current tree */
684 #ifdef DEBUG
685 if (i_avlist < nambvals)
686 error(CONSISTENCY, "missing ambient values in sortambvals");
687 #endif
688 qsort((char *)avlist1, nambvals, sizeof(struct avl), alatcmp);
689 qsort((char *)avlist2, nambvals, sizeof(AMBVAL *), aposcmp);
690 for (i = 0; i < nambvals; i++) {
691 if (avlist1[i].p == NULL)
692 continue;
693 tap = avlist2[i];
694 copystruct(&tav, tap);
695 for (j = i; (pnext = avlist1[j].p) != tap;
696 j = avlmemi(pnext)) {
697 copystruct(avlist2[j], pnext);
698 avinsert(avlist2[j]);
699 avlist1[j].p = NULL;
700 }
701 copystruct(avlist2[j], &tav);
702 avinsert(avlist2[j]);
703 avlist1[j].p = NULL;
704 }
705 free((char *)avlist1);
706 free((char *)avlist2);
707 /* compute new sort interval */
708 sortintvl = ambclock - lastsort;
709 if (sortintvl >= MAX_SORT_INTVL/2)
710 sortintvl = MAX_SORT_INTVL;
711 else
712 sortintvl <<= 1; /* wait twice as long next */
713 #ifdef DEBUG
714 eputs("done\n");
715 #endif
716 }
717 if (ambclock >= MAXACLOCK)
718 ambclock = MAXACLOCK/2;
719 lastsort = ambclock;
720 }
721
722
723 #ifdef F_SETLKW
724
725 static
726 aflock(typ) /* lock/unlock ambient file */
727 int typ;
728 {
729 static struct flock fls; /* static so initialized to zeroes */
730
731 fls.l_type = typ;
732 if (fcntl(fileno(ambfp), F_SETLKW, &fls) < 0)
733 error(SYSTEM, "cannot (un)lock ambient file");
734 }
735
736
737 int
738 ambsync() /* synchronize ambient file */
739 {
740 static FILE *ambinp = NULL;
741 static long lastpos = -1;
742 long flen;
743 AMBVAL avs;
744 register int n;
745
746 if (nunflshed == 0)
747 return(0);
748 if (lastpos < 0) /* initializing (locked in initambfile) */
749 goto syncend;
750 /* gain exclusive access */
751 aflock(F_WRLCK);
752 /* see if file has grown */
753 if ((flen = lseek(fileno(ambfp), 0L, 2)) < 0)
754 goto seekerr;
755 if (n = flen - lastpos) { /* file has grown */
756 if (ambinp == NULL) { /* use duplicate filedes */
757 ambinp = fdopen(dup(fileno(ambfp)), "r");
758 if (ambinp == NULL)
759 error(SYSTEM, "fdopen failed in ambsync");
760 }
761 if (fseek(ambinp, lastpos, 0) < 0)
762 goto seekerr;
763 while (n >= AMBVALSIZ) { /* load contributed values */
764 if (!readambval(&avs, ambinp)) {
765 sprintf(errmsg,
766 "ambient file corrupted near character %ld",
767 flen - n);
768 error(WARNING, errmsg);
769 break;
770 }
771 avinsert(avstore(&avs));
772 n -= AMBVALSIZ;
773 }
774 /*** seek always as safety measure
775 if (n) ***/ /* alignment */
776 if (lseek(fileno(ambfp), flen-n, 0) < 0)
777 goto seekerr;
778 }
779 #ifdef DEBUG
780 if (ambfp->_ptr - ambfp->_base != nunflshed*AMBVALSIZ) {
781 sprintf(errmsg, "ambient file buffer at %d rather than %d",
782 ambfp->_ptr - ambfp->_base,
783 nunflshed*AMBVALSIZ);
784 error(CONSISTENCY, errmsg);
785 }
786 #endif
787 syncend:
788 n = fflush(ambfp); /* calls write() at last */
789 if ((lastpos = lseek(fileno(ambfp), 0L, 1)) < 0)
790 goto seekerr;
791 aflock(F_UNLCK); /* release file */
792 nunflshed = 0;
793 return(n);
794 seekerr:
795 error(SYSTEM, "seek failed in ambsync");
796 }
797
798 #else
799
800 int
801 ambsync() /* flush ambient file */
802 {
803 if (nunflshed == 0)
804 return(0);
805 nunflshed = 0;
806 return(fflush(ambfp));
807 }
808
809 #endif