1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*b30d1939SAndy Fiddaman * Copyright (c) 1985-2011 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6*b30d1939SAndy Fiddaman * Eclipse Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10*b30d1939SAndy Fiddaman * http://www.eclipse.org/org/documents/epl-v10.html *
11*b30d1939SAndy Fiddaman * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> *
18da2e3ebdSchin * David Korn <dgk@research.att.com> *
19da2e3ebdSchin * Phong Vo <kpv@research.att.com> *
20da2e3ebdSchin * *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #include "sfhdr.h"
23da2e3ebdSchin
24da2e3ebdSchin /* Management of pools of streams.
25da2e3ebdSchin ** If pf is not nil, f is pooled with pf and f becomes current;
26da2e3ebdSchin ** otherwise, f is isolated from its pool. flag can be one of
27da2e3ebdSchin ** 0 or SF_SHARE.
28da2e3ebdSchin **
29da2e3ebdSchin ** Written by Kiem-Phong Vo.
30da2e3ebdSchin */
31da2e3ebdSchin
32da2e3ebdSchin /* Note that we do not free the space for a pool once it is allocated.
33da2e3ebdSchin ** This is to prevent memory faults in calls such as sfsync(NULL) that walk the pool
34da2e3ebdSchin ** link list and during such walks may free up streams&pools. Free pools will be
35da2e3ebdSchin ** reused in newpool().
36da2e3ebdSchin */
37da2e3ebdSchin #if __STD_C
delpool(reg Sfpool_t * p)38da2e3ebdSchin static int delpool(reg Sfpool_t* p)
39da2e3ebdSchin #else
40da2e3ebdSchin static int delpool(p)
41da2e3ebdSchin reg Sfpool_t* p;
42da2e3ebdSchin #endif
43da2e3ebdSchin {
447c2fbfb3SApril Chin POOLMTXENTER(p);
45da2e3ebdSchin
46da2e3ebdSchin if(p->s_sf && p->sf != p->array)
47da2e3ebdSchin free((Void_t*)p->sf);
48da2e3ebdSchin p->mode = SF_AVAIL;
49da2e3ebdSchin
50da2e3ebdSchin POOLMTXRETURN(p,0);
51da2e3ebdSchin }
52da2e3ebdSchin
53da2e3ebdSchin #if __STD_C
newpool(reg int mode)54da2e3ebdSchin static Sfpool_t* newpool(reg int mode)
55da2e3ebdSchin #else
56da2e3ebdSchin static Sfpool_t* newpool(mode)
57da2e3ebdSchin reg int mode;
58da2e3ebdSchin #endif
59da2e3ebdSchin {
60da2e3ebdSchin reg Sfpool_t *p, *last = &_Sfpool;
61da2e3ebdSchin
62da2e3ebdSchin /* look to see if there is a free pool */
63da2e3ebdSchin for(last = &_Sfpool, p = last->next; p; last = p, p = p->next)
64da2e3ebdSchin { if(p->mode == SF_AVAIL )
65da2e3ebdSchin { p->mode = 0;
66da2e3ebdSchin break;
67da2e3ebdSchin }
68da2e3ebdSchin }
69da2e3ebdSchin
70da2e3ebdSchin if(!p)
71da2e3ebdSchin { POOLMTXLOCK(last);
72da2e3ebdSchin
73da2e3ebdSchin if(!(p = (Sfpool_t*) malloc(sizeof(Sfpool_t))) )
74da2e3ebdSchin { POOLMTXUNLOCK(last);
75da2e3ebdSchin return NIL(Sfpool_t*);
76da2e3ebdSchin }
77da2e3ebdSchin
78da2e3ebdSchin (void)vtmtxopen(&p->mutex, VT_INIT); /* initialize mutex */
79da2e3ebdSchin
80da2e3ebdSchin p->mode = 0;
81da2e3ebdSchin p->n_sf = 0;
82da2e3ebdSchin p->next = NIL(Sfpool_t*);
83da2e3ebdSchin last->next = p;
84da2e3ebdSchin
85da2e3ebdSchin POOLMTXUNLOCK(last);
86da2e3ebdSchin }
87da2e3ebdSchin
887c2fbfb3SApril Chin POOLMTXENTER(p);
89da2e3ebdSchin
90da2e3ebdSchin p->mode = mode&SF_SHARE;
91da2e3ebdSchin p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
92da2e3ebdSchin p->sf = p->array;
93da2e3ebdSchin
94da2e3ebdSchin POOLMTXRETURN(p,p);
95da2e3ebdSchin }
96da2e3ebdSchin
97da2e3ebdSchin /* move a stream to head */
98da2e3ebdSchin #if __STD_C
_sfphead(Sfpool_t * p,Sfio_t * f,int n)99da2e3ebdSchin static int _sfphead(Sfpool_t* p, Sfio_t* f, int n)
100da2e3ebdSchin #else
101da2e3ebdSchin static int _sfphead(p, f, n)
102da2e3ebdSchin Sfpool_t* p; /* the pool */
103da2e3ebdSchin Sfio_t* f; /* the stream */
104da2e3ebdSchin int n; /* current position in pool */
105da2e3ebdSchin #endif
106da2e3ebdSchin {
107da2e3ebdSchin reg Sfio_t* head;
108da2e3ebdSchin reg ssize_t k, w, v;
109da2e3ebdSchin reg int rv;
110da2e3ebdSchin
1117c2fbfb3SApril Chin POOLMTXENTER(p);
112da2e3ebdSchin
113da2e3ebdSchin if(n == 0)
114da2e3ebdSchin POOLMTXRETURN(p,0);
115da2e3ebdSchin
116da2e3ebdSchin head = p->sf[0];
117da2e3ebdSchin if(SFFROZEN(head) )
118da2e3ebdSchin POOLMTXRETURN(p,-1);
119da2e3ebdSchin
120da2e3ebdSchin SFLOCK(head,0);
121da2e3ebdSchin rv = -1;
122da2e3ebdSchin
123da2e3ebdSchin if(!(p->mode&SF_SHARE) || (head->mode&SF_READ) || (f->mode&SF_READ) )
124da2e3ebdSchin { if(SFSYNC(head) < 0)
125da2e3ebdSchin goto done;
126da2e3ebdSchin }
127da2e3ebdSchin else /* shared pool of write-streams, data can be moved among streams */
128da2e3ebdSchin { if(SFMODE(head,1) != SF_WRITE && _sfmode(head,SF_WRITE,1) < 0)
129da2e3ebdSchin goto done;
130da2e3ebdSchin /**/ASSERT(f->next == f->data);
131da2e3ebdSchin
132da2e3ebdSchin v = head->next - head->data; /* pending data */
133da2e3ebdSchin if((k = v - (f->endb-f->data)) <= 0)
134da2e3ebdSchin k = 0;
135da2e3ebdSchin else /* try to write out amount exceeding f's capacity */
136da2e3ebdSchin { if((w = SFWR(head,head->data,k,head->disc)) == k)
137da2e3ebdSchin v -= k;
138da2e3ebdSchin else /* write failed, recover buffer then quit */
139da2e3ebdSchin { if(w > 0)
140da2e3ebdSchin { v -= w;
141da2e3ebdSchin memcpy(head->data,(head->data+w),v);
142da2e3ebdSchin }
143da2e3ebdSchin head->next = head->data+v;
144da2e3ebdSchin goto done;
145da2e3ebdSchin }
146da2e3ebdSchin }
147da2e3ebdSchin
148da2e3ebdSchin /* move data from head to f */
149da2e3ebdSchin if((head->data+k) != f->data )
150da2e3ebdSchin memcpy(f->data,(head->data+k),v);
151da2e3ebdSchin f->next = f->data+v;
152da2e3ebdSchin }
153da2e3ebdSchin
154da2e3ebdSchin f->mode &= ~SF_POOL;
155da2e3ebdSchin head->mode |= SF_POOL;
156da2e3ebdSchin head->next = head->endr = head->endw = head->data; /* clear write buffer */
157da2e3ebdSchin
158da2e3ebdSchin p->sf[n] = head;
159da2e3ebdSchin p->sf[0] = f;
160da2e3ebdSchin rv = 0;
161da2e3ebdSchin
162da2e3ebdSchin done:
163da2e3ebdSchin head->mode &= ~SF_LOCK; /* partially unlock because it's no longer head */
164da2e3ebdSchin
165da2e3ebdSchin POOLMTXRETURN(p,rv);
166da2e3ebdSchin }
167da2e3ebdSchin
168da2e3ebdSchin /* delete a stream from its pool */
169da2e3ebdSchin #if __STD_C
_sfpdelete(Sfpool_t * p,Sfio_t * f,int n)170da2e3ebdSchin static int _sfpdelete(Sfpool_t* p, Sfio_t* f, int n)
171da2e3ebdSchin #else
172da2e3ebdSchin static int _sfpdelete(p, f, n)
173da2e3ebdSchin Sfpool_t* p; /* the pool */
174da2e3ebdSchin Sfio_t* f; /* the stream */
175da2e3ebdSchin int n; /* position in pool */
176da2e3ebdSchin #endif
177da2e3ebdSchin {
1787c2fbfb3SApril Chin POOLMTXENTER(p);
179da2e3ebdSchin
180da2e3ebdSchin p->n_sf -= 1;
181da2e3ebdSchin for(; n < p->n_sf; ++n)
182da2e3ebdSchin p->sf[n] = p->sf[n+1];
183da2e3ebdSchin
184da2e3ebdSchin f->pool = NIL(Sfpool_t*);
185da2e3ebdSchin f->mode &= ~SF_POOL;
186da2e3ebdSchin
187da2e3ebdSchin if(p->n_sf == 0 || p == &_Sfpool)
188da2e3ebdSchin { if(p != &_Sfpool)
189da2e3ebdSchin delpool(p);
190da2e3ebdSchin goto done;
191da2e3ebdSchin }
192da2e3ebdSchin
193da2e3ebdSchin /* !_Sfpool, make sure head stream is an open stream */
194da2e3ebdSchin for(n = 0; n < p->n_sf; ++n)
195da2e3ebdSchin if(!SFFROZEN(p->sf[n]))
196da2e3ebdSchin break;
197da2e3ebdSchin if(n < p->n_sf && n > 0)
198da2e3ebdSchin { f = p->sf[n];
199da2e3ebdSchin p->sf[n] = p->sf[0];
200da2e3ebdSchin p->sf[0] = f;
201da2e3ebdSchin }
202da2e3ebdSchin
203da2e3ebdSchin /* head stream has SF_POOL off */
204da2e3ebdSchin f = p->sf[0];
205da2e3ebdSchin f->mode &= ~SF_POOL;
206da2e3ebdSchin if(!SFFROZEN(f))
207da2e3ebdSchin _SFOPEN(f);
208da2e3ebdSchin
209da2e3ebdSchin /* if only one stream left, delete pool */
210da2e3ebdSchin if(p->n_sf == 1 )
211da2e3ebdSchin { _sfpdelete(p,f,0);
212da2e3ebdSchin _sfsetpool(f);
213da2e3ebdSchin }
214da2e3ebdSchin
215da2e3ebdSchin done:
216da2e3ebdSchin POOLMTXRETURN(p,0);
217da2e3ebdSchin }
218da2e3ebdSchin
219da2e3ebdSchin #if __STD_C
_sfpmove(reg Sfio_t * f,reg int type)220da2e3ebdSchin static int _sfpmove(reg Sfio_t* f, reg int type)
221da2e3ebdSchin #else
222da2e3ebdSchin static int _sfpmove(f,type)
223da2e3ebdSchin reg Sfio_t* f;
224da2e3ebdSchin reg int type; /* <0 : deleting, 0: move-to-front, >0: inserting */
225da2e3ebdSchin #endif
226da2e3ebdSchin {
227da2e3ebdSchin reg Sfpool_t* p;
228da2e3ebdSchin reg int n;
229da2e3ebdSchin
230da2e3ebdSchin if(type > 0)
231da2e3ebdSchin return _sfsetpool(f);
232da2e3ebdSchin else
233da2e3ebdSchin { if(!(p = f->pool) )
234da2e3ebdSchin return -1;
235da2e3ebdSchin for(n = p->n_sf-1; n >= 0; --n)
236da2e3ebdSchin if(p->sf[n] == f)
237da2e3ebdSchin break;
238da2e3ebdSchin if(n < 0)
239da2e3ebdSchin return -1;
240da2e3ebdSchin
241da2e3ebdSchin return type == 0 ? _sfphead(p,f,n) : _sfpdelete(p,f,n);
242da2e3ebdSchin }
243da2e3ebdSchin }
244da2e3ebdSchin
245da2e3ebdSchin #if __STD_C
sfpool(reg Sfio_t * f,reg Sfio_t * pf,reg int mode)246da2e3ebdSchin Sfio_t* sfpool(reg Sfio_t* f, reg Sfio_t* pf, reg int mode)
247da2e3ebdSchin #else
248da2e3ebdSchin Sfio_t* sfpool(f,pf,mode)
249da2e3ebdSchin reg Sfio_t* f;
250da2e3ebdSchin reg Sfio_t* pf;
251da2e3ebdSchin reg int mode;
252da2e3ebdSchin #endif
253da2e3ebdSchin {
25434f9b3eeSRoland Mainz int k;
25534f9b3eeSRoland Mainz Sfpool_t* p;
25634f9b3eeSRoland Mainz Sfio_t* rv;
257da2e3ebdSchin
258da2e3ebdSchin _Sfpmove = _sfpmove;
259da2e3ebdSchin
260da2e3ebdSchin if(!f) /* return head of pool of pf regardless of lock states */
261da2e3ebdSchin { if(!pf)
262da2e3ebdSchin return NIL(Sfio_t*);
263da2e3ebdSchin else if(!pf->pool || pf->pool == &_Sfpool)
264da2e3ebdSchin return pf;
265da2e3ebdSchin else return pf->pool->sf[0];
266da2e3ebdSchin }
267da2e3ebdSchin
268da2e3ebdSchin if(f) /* check for permissions */
269da2e3ebdSchin { SFMTXLOCK(f);
270da2e3ebdSchin if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0)
271da2e3ebdSchin { SFMTXUNLOCK(f);
272da2e3ebdSchin return NIL(Sfio_t*);
273da2e3ebdSchin }
274da2e3ebdSchin if(f->disc == _Sfudisc)
275da2e3ebdSchin (void)sfclose((*_Sfstack)(f,NIL(Sfio_t*)));
276da2e3ebdSchin }
277da2e3ebdSchin if(pf)
278da2e3ebdSchin { SFMTXLOCK(pf);
279da2e3ebdSchin if((pf->mode&SF_RDWR) != pf->mode && _sfmode(pf,0,0) < 0)
280da2e3ebdSchin { if(f)
281da2e3ebdSchin SFMTXUNLOCK(f);
282da2e3ebdSchin SFMTXUNLOCK(pf);
283da2e3ebdSchin return NIL(Sfio_t*);
284da2e3ebdSchin }
285da2e3ebdSchin if(pf->disc == _Sfudisc)
286da2e3ebdSchin (void)sfclose((*_Sfstack)(pf,NIL(Sfio_t*)));
287da2e3ebdSchin }
288da2e3ebdSchin
289da2e3ebdSchin /* f already in the same pool with pf */
290da2e3ebdSchin if(f == pf || (pf && f->pool == pf->pool && f->pool != &_Sfpool) )
2917bdb5b9aSToomas Soome {
2927bdb5b9aSToomas Soome if(f)
293da2e3ebdSchin SFMTXUNLOCK(f);
294da2e3ebdSchin if(pf)
295da2e3ebdSchin SFMTXUNLOCK(pf);
296da2e3ebdSchin return pf;
297da2e3ebdSchin }
298da2e3ebdSchin
299da2e3ebdSchin /* lock streams before internal manipulations */
300da2e3ebdSchin rv = NIL(Sfio_t*);
301da2e3ebdSchin SFLOCK(f,0);
302da2e3ebdSchin if(pf)
303da2e3ebdSchin SFLOCK(pf,0);
304da2e3ebdSchin
305da2e3ebdSchin if(!pf) /* deleting f from its current pool */
30634f9b3eeSRoland Mainz { if((p = f->pool) != NIL(Sfpool_t*) && p != &_Sfpool)
30734f9b3eeSRoland Mainz for(k = 0; k < p->n_sf && pf == NIL(Sfio_t*); ++k)
30834f9b3eeSRoland Mainz if(p->sf[k] != f) /* a stream != f represents the pool */
30934f9b3eeSRoland Mainz pf = p->sf[k];
31034f9b3eeSRoland Mainz if(!pf) /* already isolated */
31134f9b3eeSRoland Mainz { rv = f; /* just return self */
312da2e3ebdSchin goto done;
31334f9b3eeSRoland Mainz }
31434f9b3eeSRoland Mainz
31534f9b3eeSRoland Mainz if(_sfpmove(f,-1) < 0 || _sfsetpool(f) < 0)
31634f9b3eeSRoland Mainz goto done; /* can't delete */
317da2e3ebdSchin
31834f9b3eeSRoland Mainz if(!pf->pool || pf->pool == &_Sfpool || pf->pool->n_sf <= 0 )
31934f9b3eeSRoland Mainz rv = pf;
32034f9b3eeSRoland Mainz else rv = pf->pool->sf[0]; /* return head of old pool */
321da2e3ebdSchin goto done;
322da2e3ebdSchin }
323da2e3ebdSchin
324da2e3ebdSchin if(pf->pool && pf->pool != &_Sfpool) /* always use current mode */
325da2e3ebdSchin mode = pf->pool->mode;
326da2e3ebdSchin
327da2e3ebdSchin if(mode&SF_SHARE) /* can only have write streams */
328da2e3ebdSchin { if(SFMODE(f,1) != SF_WRITE && _sfmode(f,SF_WRITE,1) < 0)
329da2e3ebdSchin goto done;
330da2e3ebdSchin if(SFMODE(pf,1) != SF_WRITE && _sfmode(pf,SF_WRITE,1) < 0)
331da2e3ebdSchin goto done;
332da2e3ebdSchin if(f->next > f->data && SFSYNC(f) < 0) /* start f clean */
333da2e3ebdSchin goto done;
334da2e3ebdSchin }
335da2e3ebdSchin
336da2e3ebdSchin if(_sfpmove(f,-1) < 0) /* isolate f from current pool */
337da2e3ebdSchin goto done;
338da2e3ebdSchin
339da2e3ebdSchin if(!(p = pf->pool) || p == &_Sfpool) /* making a new pool */
340da2e3ebdSchin { if(!(p = newpool(mode)) )
341da2e3ebdSchin goto done;
342da2e3ebdSchin if(_sfpmove(pf,-1) < 0) /* isolate pf from its current pool */
343da2e3ebdSchin goto done;
344da2e3ebdSchin pf->pool = p;
345da2e3ebdSchin p->sf[0] = pf;
346da2e3ebdSchin p->n_sf += 1;
347da2e3ebdSchin }
348da2e3ebdSchin
349da2e3ebdSchin f->pool = p; /* add f to pf's pool */
350da2e3ebdSchin if(_sfsetpool(f) < 0)
351da2e3ebdSchin goto done;
352da2e3ebdSchin
353da2e3ebdSchin /**/ASSERT(p->sf[0] == pf && p->sf[p->n_sf-1] == f);
354da2e3ebdSchin SFOPEN(pf,0);
355da2e3ebdSchin SFOPEN(f,0);
356da2e3ebdSchin if(_sfpmove(f,0) < 0) /* make f head of pool */
357da2e3ebdSchin goto done;
358da2e3ebdSchin rv = pf;
359da2e3ebdSchin
360da2e3ebdSchin done:
361da2e3ebdSchin if(f)
362da2e3ebdSchin { SFOPEN(f,0);
363da2e3ebdSchin SFMTXUNLOCK(f);
364da2e3ebdSchin }
365da2e3ebdSchin if(pf)
366da2e3ebdSchin { SFOPEN(pf,0);
367da2e3ebdSchin SFMTXUNLOCK(pf);
368da2e3ebdSchin }
369da2e3ebdSchin return rv;
370da2e3ebdSchin }
371