summaryrefslogtreecommitdiff
path: root/src/lib/libast/sfio/sfpool.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-06-24 22:28:35 +0000
commit3950ffe2a485479f6561c27364d3d7df5a21d124 (patch)
tree468c6e14449d1b1e279222ec32f676b0311917d2 /src/lib/libast/sfio/sfpool.c
downloadksh-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.c369
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;
+}