+++ /dev/null
-/* $Id$ $Revision$ */
-/* vim:set shiftwidth=4 ts=8: */
-
-/*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: See CVS logs. Details at http://www.graphviz.org/
- *************************************************************************/
-
-#include <sfio/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().
-*/
-static int delpool(Sfpool_t * p)
-{
- POOLMTXSTART(p);
-
- if (p->s_sf && p->sf != p->array)
- free((void *) p->sf);
- p->mode = SF_AVAIL;
-
- POOLMTXRETURN(p, 0);
-}
-
-static Sfpool_t *newpool(int mode)
-{
- 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 *);
- }
-
- vtmtxopen(&p->mutex, VT_INIT); /* initialize mutex */
-
- p->mode = 0;
- p->n_sf = 0;
- p->next = NIL(Sfpool_t *);
- last->next = p;
-
- POOLMTXUNLOCK(last);
- }
-
- POOLMTXSTART(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 */
-/**
- * @param p the pool
- * @param f the stream
- * @param n current position in pool
- */
-static int _sfphead(Sfpool_t * p, Sfio_t * f, int n)
-{
- Sfio_t *head;
- ssize_t k, w, v;
- int rv;
-
- POOLMTXSTART(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)) {
- if (SFSYNC(head) < 0)
- goto done;
- } else { /* shared pool, data can be moved among streams */
- if (SFMODE(head, 1) != SF_WRITE && _sfmode(head, SF_WRITE, 1) < 0)
- goto done;
- /**/ ASSERT((f->mode & (SF_WRITE | SF_POOL)) ==
- (SF_WRITE | SF_POOL));
- /**/ 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;
-
- 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 */
-/**
- * @param p the pool
- * @param f the stream
- * @param n position in pool
- */
-static int _sfpdelete(Sfpool_t * p, Sfio_t * f, int n)
-{
- POOLMTXSTART(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);
-}
-
-/**
- * @param f
- * @param type <0 : deleting, 0: move-to-front, >0: inserting
- */
-static int _sfpmove(Sfio_t * f, int type)
-{
- Sfpool_t *p;
- 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);
- }
-}
-
-Sfio_t *sfpool(Sfio_t * f, Sfio_t * pf, int mode)
-{
- 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) || p == &_Sfpool ||
- _sfpmove(f, -1) < 0 || _sfsetpool(f) < 0)
- goto done;
-
- if ((p = f->pool) == &_Sfpool || p->n_sf <= 0)
- rv = f;
- else
- rv = p->sf[0]; /* return head of 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;
-}