diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-06-24 22:28:35 +0000 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-06-24 22:28:35 +0000 |
commit | 3950ffe2a485479f6561c27364d3d7df5a21d124 (patch) | |
tree | 468c6e14449d1b1e279222ec32f676b0311917d2 /src/lib/libast/sfio/sfpool.c | |
download | ksh-upstream.tar.gz |
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/lib/libast/sfio/sfpool.c')
-rw-r--r-- | src/lib/libast/sfio/sfpool.c | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/src/lib/libast/sfio/sfpool.c b/src/lib/libast/sfio/sfpool.c new file mode 100644 index 0000000..dbfc045 --- /dev/null +++ b/src/lib/libast/sfio/sfpool.c @@ -0,0 +1,369 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#include "sfhdr.h" + +/* Management of pools of streams. +** If pf is not nil, f is pooled with pf and f becomes current; +** otherwise, f is isolated from its pool. flag can be one of +** 0 or SF_SHARE. +** +** Written by Kiem-Phong Vo. +*/ + +/* Note that we do not free the space for a pool once it is allocated. +** This is to prevent memory faults in calls such as sfsync(NULL) that walk the pool +** link list and during such walks may free up streams&pools. Free pools will be +** reused in newpool(). +*/ +#if __STD_C +static int delpool(reg Sfpool_t* p) +#else +static int delpool(p) +reg Sfpool_t* p; +#endif +{ + POOLMTXENTER(p); + + if(p->s_sf && p->sf != p->array) + free((Void_t*)p->sf); + p->mode = SF_AVAIL; + + POOLMTXRETURN(p,0); +} + +#if __STD_C +static Sfpool_t* newpool(reg int mode) +#else +static Sfpool_t* newpool(mode) +reg int mode; +#endif +{ + reg Sfpool_t *p, *last = &_Sfpool; + + /* look to see if there is a free pool */ + for(last = &_Sfpool, p = last->next; p; last = p, p = p->next) + { if(p->mode == SF_AVAIL ) + { p->mode = 0; + break; + } + } + + if(!p) + { POOLMTXLOCK(last); + + if(!(p = (Sfpool_t*) malloc(sizeof(Sfpool_t))) ) + { POOLMTXUNLOCK(last); + return NIL(Sfpool_t*); + } + + (void)vtmtxopen(&p->mutex, VT_INIT); /* initialize mutex */ + + p->mode = 0; + p->n_sf = 0; + p->next = NIL(Sfpool_t*); + last->next = p; + + POOLMTXUNLOCK(last); + } + + POOLMTXENTER(p); + + p->mode = mode&SF_SHARE; + p->s_sf = sizeof(p->array)/sizeof(p->array[0]); + p->sf = p->array; + + POOLMTXRETURN(p,p); +} + +/* move a stream to head */ +#if __STD_C +static int _sfphead(Sfpool_t* p, Sfio_t* f, int n) +#else +static int _sfphead(p, f, n) +Sfpool_t* p; /* the pool */ +Sfio_t* f; /* the stream */ +int n; /* current position in pool */ +#endif +{ + reg Sfio_t* head; + reg ssize_t k, w, v; + reg int rv; + + POOLMTXENTER(p); + + if(n == 0) + POOLMTXRETURN(p,0); + + head = p->sf[0]; + if(SFFROZEN(head) ) + POOLMTXRETURN(p,-1); + + SFLOCK(head,0); + rv = -1; + + if(!(p->mode&SF_SHARE) || (head->mode&SF_READ) || (f->mode&SF_READ) ) + { if(SFSYNC(head) < 0) + goto done; + } + else /* shared pool of write-streams, data can be moved among streams */ + { if(SFMODE(head,1) != SF_WRITE && _sfmode(head,SF_WRITE,1) < 0) + goto done; + /**/ASSERT(f->next == f->data); + + v = head->next - head->data; /* pending data */ + if((k = v - (f->endb-f->data)) <= 0) + k = 0; + else /* try to write out amount exceeding f's capacity */ + { if((w = SFWR(head,head->data,k,head->disc)) == k) + v -= k; + else /* write failed, recover buffer then quit */ + { if(w > 0) + { v -= w; + memcpy(head->data,(head->data+w),v); + } + head->next = head->data+v; + goto done; + } + } + + /* move data from head to f */ + if((head->data+k) != f->data ) + memcpy(f->data,(head->data+k),v); + f->next = f->data+v; + } + + f->mode &= ~SF_POOL; + head->mode |= SF_POOL; + head->next = head->endr = head->endw = head->data; /* clear write buffer */ + + p->sf[n] = head; + p->sf[0] = f; + rv = 0; + +done: + head->mode &= ~SF_LOCK; /* partially unlock because it's no longer head */ + + POOLMTXRETURN(p,rv); +} + +/* delete a stream from its pool */ +#if __STD_C +static int _sfpdelete(Sfpool_t* p, Sfio_t* f, int n) +#else +static int _sfpdelete(p, f, n) +Sfpool_t* p; /* the pool */ +Sfio_t* f; /* the stream */ +int n; /* position in pool */ +#endif +{ + POOLMTXENTER(p); + + p->n_sf -= 1; + for(; n < p->n_sf; ++n) + p->sf[n] = p->sf[n+1]; + + f->pool = NIL(Sfpool_t*); + f->mode &= ~SF_POOL; + + if(p->n_sf == 0 || p == &_Sfpool) + { if(p != &_Sfpool) + delpool(p); + goto done; + } + + /* !_Sfpool, make sure head stream is an open stream */ + for(n = 0; n < p->n_sf; ++n) + if(!SFFROZEN(p->sf[n])) + break; + if(n < p->n_sf && n > 0) + { f = p->sf[n]; + p->sf[n] = p->sf[0]; + p->sf[0] = f; + } + + /* head stream has SF_POOL off */ + f = p->sf[0]; + f->mode &= ~SF_POOL; + if(!SFFROZEN(f)) + _SFOPEN(f); + + /* if only one stream left, delete pool */ + if(p->n_sf == 1 ) + { _sfpdelete(p,f,0); + _sfsetpool(f); + } + +done: + POOLMTXRETURN(p,0); +} + +#if __STD_C +static int _sfpmove(reg Sfio_t* f, reg int type) +#else +static int _sfpmove(f,type) +reg Sfio_t* f; +reg int type; /* <0 : deleting, 0: move-to-front, >0: inserting */ +#endif +{ + reg Sfpool_t* p; + reg int n; + + if(type > 0) + return _sfsetpool(f); + else + { if(!(p = f->pool) ) + return -1; + for(n = p->n_sf-1; n >= 0; --n) + if(p->sf[n] == f) + break; + if(n < 0) + return -1; + + return type == 0 ? _sfphead(p,f,n) : _sfpdelete(p,f,n); + } +} + +#if __STD_C +Sfio_t* sfpool(reg Sfio_t* f, reg Sfio_t* pf, reg int mode) +#else +Sfio_t* sfpool(f,pf,mode) +reg Sfio_t* f; +reg Sfio_t* pf; +reg int mode; +#endif +{ + int k; + Sfpool_t* p; + Sfio_t* rv; + + _Sfpmove = _sfpmove; + + if(!f) /* return head of pool of pf regardless of lock states */ + { if(!pf) + return NIL(Sfio_t*); + else if(!pf->pool || pf->pool == &_Sfpool) + return pf; + else return pf->pool->sf[0]; + } + + if(f) /* check for permissions */ + { SFMTXLOCK(f); + if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0) + { SFMTXUNLOCK(f); + return NIL(Sfio_t*); + } + if(f->disc == _Sfudisc) + (void)sfclose((*_Sfstack)(f,NIL(Sfio_t*))); + } + if(pf) + { SFMTXLOCK(pf); + if((pf->mode&SF_RDWR) != pf->mode && _sfmode(pf,0,0) < 0) + { if(f) + SFMTXUNLOCK(f); + SFMTXUNLOCK(pf); + return NIL(Sfio_t*); + } + if(pf->disc == _Sfudisc) + (void)sfclose((*_Sfstack)(pf,NIL(Sfio_t*))); + } + + /* f already in the same pool with pf */ + if(f == pf || (pf && f->pool == pf->pool && f->pool != &_Sfpool) ) + { if(f) + SFMTXUNLOCK(f); + if(pf) + SFMTXUNLOCK(pf); + return pf; + } + + /* lock streams before internal manipulations */ + rv = NIL(Sfio_t*); + SFLOCK(f,0); + if(pf) + SFLOCK(pf,0); + + if(!pf) /* deleting f from its current pool */ + { if((p = f->pool) != NIL(Sfpool_t*) && p != &_Sfpool) + for(k = 0; k < p->n_sf && pf == NIL(Sfio_t*); ++k) + if(p->sf[k] != f) /* a stream != f represents the pool */ + pf = p->sf[k]; + if(!pf) /* already isolated */ + { rv = f; /* just return self */ + goto done; + } + + if(_sfpmove(f,-1) < 0 || _sfsetpool(f) < 0) + goto done; /* can't delete */ + + if(!pf->pool || pf->pool == &_Sfpool || pf->pool->n_sf <= 0 ) + rv = pf; + else rv = pf->pool->sf[0]; /* return head of old pool */ + goto done; + } + + if(pf->pool && pf->pool != &_Sfpool) /* always use current mode */ + mode = pf->pool->mode; + + if(mode&SF_SHARE) /* can only have write streams */ + { if(SFMODE(f,1) != SF_WRITE && _sfmode(f,SF_WRITE,1) < 0) + goto done; + if(SFMODE(pf,1) != SF_WRITE && _sfmode(pf,SF_WRITE,1) < 0) + goto done; + if(f->next > f->data && SFSYNC(f) < 0) /* start f clean */ + goto done; + } + + if(_sfpmove(f,-1) < 0) /* isolate f from current pool */ + goto done; + + if(!(p = pf->pool) || p == &_Sfpool) /* making a new pool */ + { if(!(p = newpool(mode)) ) + goto done; + if(_sfpmove(pf,-1) < 0) /* isolate pf from its current pool */ + goto done; + pf->pool = p; + p->sf[0] = pf; + p->n_sf += 1; + } + + f->pool = p; /* add f to pf's pool */ + if(_sfsetpool(f) < 0) + goto done; + + /**/ASSERT(p->sf[0] == pf && p->sf[p->n_sf-1] == f); + SFOPEN(pf,0); + SFOPEN(f,0); + if(_sfpmove(f,0) < 0) /* make f head of pool */ + goto done; + rv = pf; + +done: + if(f) + { SFOPEN(f,0); + SFMTXUNLOCK(f); + } + if(pf) + { SFOPEN(pf,0); + SFMTXUNLOCK(pf); + } + return rv; +} |