xref: /onnv-gate/usr/src/lib/libast/common/sfio/sfpool.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #include	"sfhdr.h"
234887Schin 
244887Schin /*	Management of pools of streams.
254887Schin **	If pf is not nil, f is pooled with pf and f becomes current;
264887Schin **	otherwise, f is isolated from its pool. flag can be one of
274887Schin **	0 or SF_SHARE.
284887Schin **
294887Schin **	Written by Kiem-Phong Vo.
304887Schin */
314887Schin 
324887Schin /* Note that we do not free the space for a pool once it is allocated.
334887Schin ** This is to prevent memory faults in calls such as sfsync(NULL) that walk the pool
344887Schin ** link list and during such walks may free up streams&pools. Free pools will be
354887Schin ** reused in newpool().
364887Schin */
374887Schin #if __STD_C
delpool(reg Sfpool_t * p)384887Schin static int delpool(reg Sfpool_t* p)
394887Schin #else
404887Schin static int delpool(p)
414887Schin reg Sfpool_t*	p;
424887Schin #endif
434887Schin {
448462SApril.Chin@Sun.COM 	POOLMTXENTER(p);
454887Schin 
464887Schin 	if(p->s_sf && p->sf != p->array)
474887Schin 		free((Void_t*)p->sf);
484887Schin 	p->mode = SF_AVAIL;
494887Schin 
504887Schin 	POOLMTXRETURN(p,0);
514887Schin }
524887Schin 
534887Schin #if __STD_C
newpool(reg int mode)544887Schin static Sfpool_t* newpool(reg int mode)
554887Schin #else
564887Schin static Sfpool_t* newpool(mode)
574887Schin reg int	mode;
584887Schin #endif
594887Schin {
604887Schin 	reg Sfpool_t	*p, *last = &_Sfpool;
614887Schin 
624887Schin 	/* look to see if there is a free pool */
634887Schin 	for(last = &_Sfpool, p = last->next; p; last = p, p = p->next)
644887Schin 	{	if(p->mode == SF_AVAIL )
654887Schin 		{	p->mode = 0;
664887Schin 			break;
674887Schin 		}
684887Schin 	}
694887Schin 
704887Schin 	if(!p)
714887Schin 	{	POOLMTXLOCK(last);
724887Schin 
734887Schin 		if(!(p = (Sfpool_t*) malloc(sizeof(Sfpool_t))) )
744887Schin 		{	POOLMTXUNLOCK(last);
754887Schin 			return NIL(Sfpool_t*);
764887Schin 		}
774887Schin 
784887Schin 		(void)vtmtxopen(&p->mutex, VT_INIT); /* initialize mutex */
794887Schin 
804887Schin 		p->mode = 0;
814887Schin 		p->n_sf = 0;
824887Schin 		p->next = NIL(Sfpool_t*);
834887Schin 		last->next = p;
844887Schin 
854887Schin 		POOLMTXUNLOCK(last);
864887Schin 	}
874887Schin 
888462SApril.Chin@Sun.COM 	POOLMTXENTER(p);
894887Schin 
904887Schin 	p->mode = mode&SF_SHARE;
914887Schin 	p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
924887Schin 	p->sf = p->array;
934887Schin 
944887Schin 	POOLMTXRETURN(p,p);
954887Schin }
964887Schin 
974887Schin /* move a stream to head */
984887Schin #if __STD_C
_sfphead(Sfpool_t * p,Sfio_t * f,int n)994887Schin static int _sfphead(Sfpool_t* p, Sfio_t* f, int n)
1004887Schin #else
1014887Schin static int _sfphead(p, f, n)
1024887Schin Sfpool_t*	p;	/* the pool			*/
1034887Schin Sfio_t*		f;	/* the stream			*/
1044887Schin int		n;	/* current position in pool	*/
1054887Schin #endif
1064887Schin {
1074887Schin 	reg Sfio_t*	head;
1084887Schin 	reg ssize_t	k, w, v;
1094887Schin 	reg int		rv;
1104887Schin 
1118462SApril.Chin@Sun.COM 	POOLMTXENTER(p);
1124887Schin 
1134887Schin 	if(n == 0)
1144887Schin 		POOLMTXRETURN(p,0);
1154887Schin 
1164887Schin 	head = p->sf[0];
1174887Schin 	if(SFFROZEN(head) )
1184887Schin 		POOLMTXRETURN(p,-1);
1194887Schin 
1204887Schin 	SFLOCK(head,0);
1214887Schin 	rv = -1;
1224887Schin 
1234887Schin 	if(!(p->mode&SF_SHARE) || (head->mode&SF_READ) || (f->mode&SF_READ) )
1244887Schin 	{	if(SFSYNC(head) < 0)
1254887Schin 			goto done;
1264887Schin 	}
1274887Schin 	else	/* shared pool of write-streams, data can be moved among streams */
1284887Schin 	{	if(SFMODE(head,1) != SF_WRITE && _sfmode(head,SF_WRITE,1) < 0)
1294887Schin 			goto done;
1304887Schin 		/**/ASSERT(f->next == f->data);
1314887Schin 
1324887Schin 		v = head->next - head->data;	/* pending data		*/
1334887Schin 		if((k = v - (f->endb-f->data)) <= 0)
1344887Schin 			k = 0;
1354887Schin 		else	/* try to write out amount exceeding f's capacity */
1364887Schin 		{	if((w = SFWR(head,head->data,k,head->disc)) == k)
1374887Schin 				v -= k;
1384887Schin 			else	/* write failed, recover buffer then quit */
1394887Schin 			{	if(w > 0)
1404887Schin 				{	v -= w;
1414887Schin 					memcpy(head->data,(head->data+w),v);
1424887Schin 				}
1434887Schin 				head->next = head->data+v;
1444887Schin 				goto done;
1454887Schin 			}
1464887Schin 		}
1474887Schin 
1484887Schin 		/* move data from head to f */
1494887Schin 		if((head->data+k) != f->data )
1504887Schin 			memcpy(f->data,(head->data+k),v);
1514887Schin 		f->next = f->data+v;
1524887Schin 	}
1534887Schin 
1544887Schin 	f->mode &= ~SF_POOL;
1554887Schin 	head->mode |= SF_POOL;
1564887Schin 	head->next = head->endr = head->endw = head->data; /* clear write buffer */
1574887Schin 
1584887Schin 	p->sf[n] = head;
1594887Schin 	p->sf[0] = f;
1604887Schin 	rv = 0;
1614887Schin 
1624887Schin done:
1634887Schin 	head->mode &= ~SF_LOCK; /* partially unlock because it's no longer head */
1644887Schin 
1654887Schin 	POOLMTXRETURN(p,rv);
1664887Schin }
1674887Schin 
1684887Schin /* delete a stream from its pool */
1694887Schin #if __STD_C
_sfpdelete(Sfpool_t * p,Sfio_t * f,int n)1704887Schin static int _sfpdelete(Sfpool_t* p, Sfio_t* f, int n)
1714887Schin #else
1724887Schin static int _sfpdelete(p, f, n)
1734887Schin Sfpool_t*	p;	/* the pool		*/
1744887Schin Sfio_t*		f;	/* the stream		*/
1754887Schin int		n;	/* position in pool	*/
1764887Schin #endif
1774887Schin {
1788462SApril.Chin@Sun.COM 	POOLMTXENTER(p);
1794887Schin 
1804887Schin 	p->n_sf -= 1;
1814887Schin 	for(; n < p->n_sf; ++n)
1824887Schin 		p->sf[n] = p->sf[n+1];
1834887Schin 
1844887Schin 	f->pool = NIL(Sfpool_t*);
1854887Schin 	f->mode &= ~SF_POOL;
1864887Schin 
1874887Schin 	if(p->n_sf == 0 || p == &_Sfpool)
1884887Schin 	{	if(p != &_Sfpool)
1894887Schin 			delpool(p);
1904887Schin 		goto done;
1914887Schin 	}
1924887Schin 
1934887Schin 	/* !_Sfpool, make sure head stream is an open stream */
1944887Schin 	for(n = 0; n < p->n_sf; ++n)
1954887Schin 		if(!SFFROZEN(p->sf[n]))
1964887Schin 			break;
1974887Schin 	if(n < p->n_sf && n > 0)
1984887Schin 	{	f = p->sf[n];
1994887Schin 		p->sf[n] = p->sf[0];
2004887Schin 		p->sf[0] = f;
2014887Schin 	}
2024887Schin 
2034887Schin 	/* head stream has SF_POOL off */
2044887Schin 	f = p->sf[0];
2054887Schin 	f->mode &= ~SF_POOL;
2064887Schin 	if(!SFFROZEN(f))
2074887Schin 		_SFOPEN(f);
2084887Schin 
2094887Schin 	/* if only one stream left, delete pool */
2104887Schin 	if(p->n_sf == 1 )
2114887Schin 	{	_sfpdelete(p,f,0);
2124887Schin 		_sfsetpool(f);
2134887Schin 	}
2144887Schin 
2154887Schin done:
2164887Schin 	POOLMTXRETURN(p,0);
2174887Schin }
2184887Schin 
2194887Schin #if __STD_C
_sfpmove(reg Sfio_t * f,reg int type)2204887Schin static int _sfpmove(reg Sfio_t* f, reg int type)
2214887Schin #else
2224887Schin static int _sfpmove(f,type)
2234887Schin reg Sfio_t*	f;
2244887Schin reg int		type;	/* <0 : deleting, 0: move-to-front, >0: inserting */
2254887Schin #endif
2264887Schin {
2274887Schin 	reg Sfpool_t*	p;
2284887Schin 	reg int		n;
2294887Schin 
2304887Schin 	if(type > 0)
2314887Schin 		return _sfsetpool(f);
2324887Schin 	else
2334887Schin 	{	if(!(p = f->pool) )
2344887Schin 			return -1;
2354887Schin 		for(n = p->n_sf-1; n >= 0; --n)
2364887Schin 			if(p->sf[n] == f)
2374887Schin 				break;
2384887Schin 		if(n < 0)
2394887Schin 			return -1;
2404887Schin 
2414887Schin 		return type == 0 ? _sfphead(p,f,n) : _sfpdelete(p,f,n);
2424887Schin 	}
2434887Schin }
2444887Schin 
2454887Schin #if __STD_C
sfpool(reg Sfio_t * f,reg Sfio_t * pf,reg int mode)2464887Schin Sfio_t* sfpool(reg Sfio_t* f, reg Sfio_t* pf, reg int mode)
2474887Schin #else
2484887Schin Sfio_t* sfpool(f,pf,mode)
2494887Schin reg Sfio_t*	f;
2504887Schin reg Sfio_t*	pf;
2514887Schin reg int		mode;
2524887Schin #endif
2534887Schin {
25410898Sroland.mainz@nrubsig.org 	int		k;
25510898Sroland.mainz@nrubsig.org 	Sfpool_t*	p;
25610898Sroland.mainz@nrubsig.org 	Sfio_t*		rv;
2574887Schin 
2584887Schin 	_Sfpmove = _sfpmove;
2594887Schin 
2604887Schin 	if(!f)	/* return head of pool of pf regardless of lock states */
2614887Schin 	{	if(!pf)
2624887Schin 			return NIL(Sfio_t*);
2634887Schin 		else if(!pf->pool || pf->pool == &_Sfpool)
2644887Schin 			return pf;
2654887Schin 		else	return pf->pool->sf[0];
2664887Schin 	}
2674887Schin 
2684887Schin 	if(f)	/* check for permissions */
2694887Schin 	{	SFMTXLOCK(f);
2704887Schin 		if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0)
2714887Schin 		{	SFMTXUNLOCK(f);
2724887Schin 			return NIL(Sfio_t*);
2734887Schin 		}
2744887Schin 		if(f->disc == _Sfudisc)
2754887Schin 			(void)sfclose((*_Sfstack)(f,NIL(Sfio_t*)));
2764887Schin 	}
2774887Schin 	if(pf)
2784887Schin 	{	SFMTXLOCK(pf);
2794887Schin 		if((pf->mode&SF_RDWR) != pf->mode && _sfmode(pf,0,0) < 0)
2804887Schin 		{	if(f)
2814887Schin 				SFMTXUNLOCK(f);
2824887Schin 			SFMTXUNLOCK(pf);
2834887Schin 			return NIL(Sfio_t*);
2844887Schin 		}
2854887Schin 		if(pf->disc == _Sfudisc)
2864887Schin 			(void)sfclose((*_Sfstack)(pf,NIL(Sfio_t*)));
2874887Schin 	}
2884887Schin 
2894887Schin 	/* f already in the same pool with pf */
2904887Schin 	if(f == pf || (pf && f->pool == pf->pool && f->pool != &_Sfpool) )
2914887Schin 	{	if(f)
2924887Schin 			SFMTXUNLOCK(f);
2934887Schin 		if(pf)
2944887Schin 			SFMTXUNLOCK(pf);
2954887Schin 		return pf;
2964887Schin 	}
2974887Schin 
2984887Schin 	/* lock streams before internal manipulations */
2994887Schin 	rv = NIL(Sfio_t*);
3004887Schin 	SFLOCK(f,0);
3014887Schin 	if(pf)
3024887Schin 		SFLOCK(pf,0);
3034887Schin 
3044887Schin 	if(!pf)	/* deleting f from its current pool */
30510898Sroland.mainz@nrubsig.org 	{	if((p = f->pool) != NIL(Sfpool_t*) && p != &_Sfpool)
30610898Sroland.mainz@nrubsig.org 			for(k = 0; k < p->n_sf && pf == NIL(Sfio_t*); ++k)
30710898Sroland.mainz@nrubsig.org 				if(p->sf[k] != f) /* a stream != f represents the pool */
30810898Sroland.mainz@nrubsig.org 					pf = p->sf[k];
30910898Sroland.mainz@nrubsig.org 		if(!pf) /* already isolated */
31010898Sroland.mainz@nrubsig.org 		{	rv = f; /* just return self */
3114887Schin 			goto done;
31210898Sroland.mainz@nrubsig.org 		}
3134887Schin 
31410898Sroland.mainz@nrubsig.org 		if(_sfpmove(f,-1) < 0 || _sfsetpool(f) < 0)
31510898Sroland.mainz@nrubsig.org 			goto done; /* can't delete */
31610898Sroland.mainz@nrubsig.org 
31710898Sroland.mainz@nrubsig.org 		if(!pf->pool || pf->pool == &_Sfpool || pf->pool->n_sf <= 0 )
31810898Sroland.mainz@nrubsig.org 			rv = pf;
31910898Sroland.mainz@nrubsig.org 		else	rv = pf->pool->sf[0];	/* return head of old pool */
3204887Schin 		goto done;
3214887Schin 	}
3224887Schin 
3234887Schin 	if(pf->pool && pf->pool != &_Sfpool) /* always use current mode */
3244887Schin 		mode = pf->pool->mode;
3254887Schin 
3264887Schin 	if(mode&SF_SHARE) /* can only have write streams */
3274887Schin 	{	if(SFMODE(f,1) != SF_WRITE && _sfmode(f,SF_WRITE,1) < 0)
3284887Schin 			goto done;
3294887Schin 		if(SFMODE(pf,1) != SF_WRITE && _sfmode(pf,SF_WRITE,1) < 0)
3304887Schin 			goto done;
3314887Schin 		if(f->next > f->data && SFSYNC(f) < 0) /* start f clean */
3324887Schin 			goto done;
3334887Schin 	}
3344887Schin 
3354887Schin 	if(_sfpmove(f,-1) < 0)	/* isolate f from current pool */
3364887Schin 		goto done;
3374887Schin 
3384887Schin 	if(!(p = pf->pool) || p == &_Sfpool) /* making a new pool */
3394887Schin 	{	if(!(p = newpool(mode)) )
3404887Schin 			goto done;
3414887Schin 		if(_sfpmove(pf,-1) < 0) /* isolate pf from its current pool */
3424887Schin 			goto done;
3434887Schin 		pf->pool = p;
3444887Schin 		p->sf[0] = pf;
3454887Schin 		p->n_sf += 1;
3464887Schin 	}
3474887Schin 
3484887Schin 	f->pool = p;	/* add f to pf's pool */
3494887Schin 	if(_sfsetpool(f) < 0)
3504887Schin 		goto done;
3514887Schin 
3524887Schin 	/**/ASSERT(p->sf[0] == pf && p->sf[p->n_sf-1] == f);
3534887Schin 	SFOPEN(pf,0);
3544887Schin 	SFOPEN(f,0);
3554887Schin 	if(_sfpmove(f,0) < 0) /* make f head of pool */
3564887Schin 		goto done;
3574887Schin 	rv = pf;
3584887Schin 
3594887Schin done:
3604887Schin 	if(f)
3614887Schin 	{	SFOPEN(f,0);
3624887Schin 		SFMTXUNLOCK(f);
3634887Schin 	}
3644887Schin 	if(pf)
3654887Schin 	{	SFOPEN(pf,0);
3664887Schin 		SFMTXUNLOCK(pf);
3674887Schin 	}
3684887Schin 	return rv;
3694887Schin }
370