1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
24 /* Management of pools of streams.
25 ** If pf is not nil, f is pooled with pf and f becomes current;
26 ** otherwise, f is isolated from its pool. flag can be one of
29 ** Written by Kiem-Phong Vo.
32 /* Note that we do not free the space for a pool once it is allocated.
33 ** This is to prevent memory faults in calls such as sfsync(NULL) that walk the pool
34 ** link list and during such walks may free up streams&pools. Free pools will be
35 ** reused in newpool().
38 static int delpool(reg Sfpool_t
* p
)
46 if(p
->s_sf
&& p
->sf
!= p
->array
)
54 static Sfpool_t
* newpool(reg
int mode
)
56 static Sfpool_t
* newpool(mode
)
60 reg Sfpool_t
*p
, *last
= &_Sfpool
;
62 /* look to see if there is a free pool */
63 for(last
= &_Sfpool
, p
= last
->next
; p
; last
= p
, p
= p
->next
)
64 { if(p
->mode
== SF_AVAIL
)
73 if(!(p
= (Sfpool_t
*) malloc(sizeof(Sfpool_t
))) )
74 { POOLMTXUNLOCK(last
);
75 return NIL(Sfpool_t
*);
78 (void)vtmtxopen(&p
->mutex
, VT_INIT
); /* initialize mutex */
82 p
->next
= NIL(Sfpool_t
*);
90 p
->mode
= mode
&SF_SHARE
;
91 p
->s_sf
= sizeof(p
->array
)/sizeof(p
->array
[0]);
97 /* move a stream to head */
99 static int _sfphead(Sfpool_t
* p
, Sfio_t
* f
, int n
)
101 static int _sfphead(p
, f
, n
)
102 Sfpool_t
* p
; /* the pool */
103 Sfio_t
* f
; /* the stream */
104 int n
; /* current position in pool */
123 if(!(p
->mode
&SF_SHARE
) || (head
->mode
&SF_READ
) || (f
->mode
&SF_READ
) )
124 { if(SFSYNC(head
) < 0)
127 else /* shared pool of write-streams, data can be moved among streams */
128 { if(SFMODE(head
,1) != SF_WRITE
&& _sfmode(head
,SF_WRITE
,1) < 0)
130 /**/ASSERT(f
->next
== f
->data
);
132 v
= head
->next
- head
->data
; /* pending data */
133 if((k
= v
- (f
->endb
-f
->data
)) <= 0)
135 else /* try to write out amount exceeding f's capacity */
136 { if((w
= SFWR(head
,head
->data
,k
,head
->disc
)) == k
)
138 else /* write failed, recover buffer then quit */
141 memcpy(head
->data
,(head
->data
+w
),v
);
143 head
->next
= head
->data
+v
;
148 /* move data from head to f */
149 if((head
->data
+k
) != f
->data
)
150 memcpy(f
->data
,(head
->data
+k
),v
);
155 head
->mode
|= SF_POOL
;
156 head
->next
= head
->endr
= head
->endw
= head
->data
; /* clear write buffer */
163 head
->mode
&= ~SF_LOCK
; /* partially unlock because it's no longer head */
168 /* delete a stream from its pool */
170 static int _sfpdelete(Sfpool_t
* p
, Sfio_t
* f
, int n
)
172 static int _sfpdelete(p
, f
, n
)
173 Sfpool_t
* p
; /* the pool */
174 Sfio_t
* f
; /* the stream */
175 int n
; /* position in pool */
181 for(; n
< p
->n_sf
; ++n
)
182 p
->sf
[n
] = p
->sf
[n
+1];
184 f
->pool
= NIL(Sfpool_t
*);
187 if(p
->n_sf
== 0 || p
== &_Sfpool
)
193 /* !_Sfpool, make sure head stream is an open stream */
194 for(n
= 0; n
< p
->n_sf
; ++n
)
195 if(!SFFROZEN(p
->sf
[n
]))
197 if(n
< p
->n_sf
&& n
> 0)
203 /* head stream has SF_POOL off */
209 /* if only one stream left, delete pool */
220 static int _sfpmove(reg Sfio_t
* f
, reg
int type
)
222 static int _sfpmove(f
,type
)
224 reg
int type
; /* <0 : deleting, 0: move-to-front, >0: inserting */
231 return _sfsetpool(f
);
233 { if(!(p
= f
->pool
) )
235 for(n
= p
->n_sf
-1; n
>= 0; --n
)
241 return type
== 0 ? _sfphead(p
,f
,n
) : _sfpdelete(p
,f
,n
);
246 Sfio_t
* sfpool(reg Sfio_t
* f
, reg Sfio_t
* pf
, reg
int mode
)
248 Sfio_t
* sfpool(f
,pf
,mode
)
260 if(!f
) /* return head of pool of pf regardless of lock states */
263 else if(!pf
->pool
|| pf
->pool
== &_Sfpool
)
265 else return pf
->pool
->sf
[0];
268 if(f
) /* check for permissions */
270 if((f
->mode
&SF_RDWR
) != f
->mode
&& _sfmode(f
,0,0) < 0)
274 if(f
->disc
== _Sfudisc
)
275 (void)sfclose((*_Sfstack
)(f
,NIL(Sfio_t
*)));
279 if((pf
->mode
&SF_RDWR
) != pf
->mode
&& _sfmode(pf
,0,0) < 0)
285 if(pf
->disc
== _Sfudisc
)
286 (void)sfclose((*_Sfstack
)(pf
,NIL(Sfio_t
*)));
289 /* f already in the same pool with pf */
290 if(f
== pf
|| (pf
&& f
->pool
== pf
->pool
&& f
->pool
!= &_Sfpool
) )
298 /* lock streams before internal manipulations */
304 if(!pf
) /* deleting f from its current pool */
305 { if((p
= f
->pool
) != NIL(Sfpool_t
*) && p
!= &_Sfpool
)
306 for(k
= 0; k
< p
->n_sf
&& pf
== NIL(Sfio_t
*); ++k
)
307 if(p
->sf
[k
] != f
) /* a stream != f represents the pool */
309 if(!pf
) /* already isolated */
310 { rv
= f
; /* just return self */
314 if(_sfpmove(f
,-1) < 0 || _sfsetpool(f
) < 0)
315 goto done
; /* can't delete */
317 if(!pf
->pool
|| pf
->pool
== &_Sfpool
|| pf
->pool
->n_sf
<= 0 )
319 else rv
= pf
->pool
->sf
[0]; /* return head of old pool */
323 if(pf
->pool
&& pf
->pool
!= &_Sfpool
) /* always use current mode */
324 mode
= pf
->pool
->mode
;
326 if(mode
&SF_SHARE
) /* can only have write streams */
327 { if(SFMODE(f
,1) != SF_WRITE
&& _sfmode(f
,SF_WRITE
,1) < 0)
329 if(SFMODE(pf
,1) != SF_WRITE
&& _sfmode(pf
,SF_WRITE
,1) < 0)
331 if(f
->next
> f
->data
&& SFSYNC(f
) < 0) /* start f clean */
335 if(_sfpmove(f
,-1) < 0) /* isolate f from current pool */
338 if(!(p
= pf
->pool
) || p
== &_Sfpool
) /* making a new pool */
339 { if(!(p
= newpool(mode
)) )
341 if(_sfpmove(pf
,-1) < 0) /* isolate pf from its current pool */
348 f
->pool
= p
; /* add f to pf's pool */
349 if(_sfsetpool(f
) < 0)
352 /**/ASSERT(p
->sf
[0] == pf
&& p
->sf
[p
->n_sf
-1] == f
);
355 if(_sfpmove(f
,0) < 0) /* make f head of pool */