14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1985-2009 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 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 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 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 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 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 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 { 254*10898Sroland.mainz@nrubsig.org int k; 255*10898Sroland.mainz@nrubsig.org Sfpool_t* p; 256*10898Sroland.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 */ 305*10898Sroland.mainz@nrubsig.org { if((p = f->pool) != NIL(Sfpool_t*) && p != &_Sfpool) 306*10898Sroland.mainz@nrubsig.org for(k = 0; k < p->n_sf && pf == NIL(Sfio_t*); ++k) 307*10898Sroland.mainz@nrubsig.org if(p->sf[k] != f) /* a stream != f represents the pool */ 308*10898Sroland.mainz@nrubsig.org pf = p->sf[k]; 309*10898Sroland.mainz@nrubsig.org if(!pf) /* already isolated */ 310*10898Sroland.mainz@nrubsig.org { rv = f; /* just return self */ 3114887Schin goto done; 312*10898Sroland.mainz@nrubsig.org } 3134887Schin 314*10898Sroland.mainz@nrubsig.org if(_sfpmove(f,-1) < 0 || _sfsetpool(f) < 0) 315*10898Sroland.mainz@nrubsig.org goto done; /* can't delete */ 316*10898Sroland.mainz@nrubsig.org 317*10898Sroland.mainz@nrubsig.org if(!pf->pool || pf->pool == &_Sfpool || pf->pool->n_sf <= 0 ) 318*10898Sroland.mainz@nrubsig.org rv = pf; 319*10898Sroland.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