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