ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambient.c
Revision: 2.26
Committed: Thu Apr 27 14:12:05 1995 UTC (29 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.25: +183 -12 lines
Log Message:
added memory sorting to ambient caching module

File Contents

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