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