3
/* Management of pools of streams.
4
** If pf is not nil, f is pooled with pf and f becomes current;
5
** otherwise, f is isolated from its pool. flag can be one of
8
** Written by Kiem-Phong Vo.
11
/* Note that we do not free the space for a pool once it is allocated.
12
** This is to prevent memory faults in calls such as sfsync(NULL) that walk the pool
13
** link list and during such walks may free up streams&pools. Free pools will be
14
** reused in newpool().
17
static int delpool(reg Sfpool_t* p)
25
if(p->s_sf && p->sf != p->array)
33
static Sfpool_t* newpool(reg int mode)
35
static Sfpool_t* newpool(mode)
39
reg Sfpool_t *p, *last = &_Sfpool;
41
/* look to see if there is a free pool */
42
for(last = &_Sfpool, p = last->next; p; last = p, p = p->next)
43
{ if(p->mode == SF_AVAIL )
52
if(!(p = (Sfpool_t*) malloc(sizeof(Sfpool_t))) )
53
{ POOLMTXUNLOCK(last);
54
return NIL(Sfpool_t*);
57
vtmtxopen(&p->mutex, VT_INIT); /* initialize mutex */
61
p->next = NIL(Sfpool_t*);
69
p->mode = mode&SF_SHARE;
70
p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
76
/* move a stream to head */
78
static int _sfphead(Sfpool_t* p, Sfio_t* f, int n)
80
static int _sfphead(p, f, n)
81
Sfpool_t* p; /* the pool */
82
Sfio_t* f; /* the stream */
83
int n; /* current position in pool */
102
if(!(p->mode&SF_SHARE) )
103
{ if(SFSYNC(head) < 0)
106
else /* shared pool, data can be moved among streams */
107
{ if(SFMODE(head,1) != SF_WRITE && _sfmode(head,SF_WRITE,1) < 0)
109
/**/ASSERT((f->mode&(SF_WRITE|SF_POOL)) == (SF_WRITE|SF_POOL) );
110
/**/ASSERT(f->next == f->data);
112
v = head->next - head->data; /* pending data */
113
if((k = v - (f->endb-f->data)) <= 0)
115
else /* try to write out amount exceeding f's capacity */
116
{ if((w = SFWR(head,head->data,k,head->disc)) == k)
118
else /* write failed, recover buffer then quit */
121
memcpy(head->data,(head->data+w),v);
123
head->next = head->data+v;
128
/* move data from head to f */
129
if((head->data+k) != f->data )
130
memcpy(f->data,(head->data+k),v);
135
head->mode |= SF_POOL;
136
head->next = head->endr = head->endw = head->data;
143
head->mode &= ~SF_LOCK; /* partially unlock because it's no longer head */
148
/* delete a stream from its pool */
150
static int _sfpdelete(Sfpool_t* p, Sfio_t* f, int n)
152
static int _sfpdelete(p, f, n)
153
Sfpool_t* p; /* the pool */
154
Sfio_t* f; /* the stream */
155
int n; /* position in pool */
161
for(; n < p->n_sf; ++n)
162
p->sf[n] = p->sf[n+1];
164
f->pool = NIL(Sfpool_t*);
167
if(p->n_sf == 0 || p == &_Sfpool)
173
/* !_Sfpool, make sure head stream is an open stream */
174
for(n = 0; n < p->n_sf; ++n)
175
if(!SFFROZEN(p->sf[n]))
177
if(n < p->n_sf && n > 0)
183
/* head stream has SF_POOL off */
189
/* if only one stream left, delete pool */
200
static int _sfpmove(reg Sfio_t* f, reg int type)
202
static int _sfpmove(f,type)
204
reg int type; /* <0 : deleting, 0: move-to-front, >0: inserting */
211
return _sfsetpool(f);
213
{ if(!(p = f->pool) )
215
for(n = p->n_sf-1; n >= 0; --n)
221
return type == 0 ? _sfphead(p,f,n) : _sfpdelete(p,f,n);
226
Sfio_t* sfpool(reg Sfio_t* f, reg Sfio_t* pf, reg int mode)
228
Sfio_t* sfpool(f,pf,mode)
239
if(!f) /* return head of pool of pf regardless of lock states */
242
else if(!pf->pool || pf->pool == &_Sfpool)
244
else return pf->pool->sf[0];
247
if(f) /* check for permissions */
249
if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0)
253
if(f->disc == _Sfudisc)
254
(void)sfclose((*_Sfstack)(f,NIL(Sfio_t*)));
258
if((pf->mode&SF_RDWR) != pf->mode && _sfmode(pf,0,0) < 0)
264
if(pf->disc == _Sfudisc)
265
(void)sfclose((*_Sfstack)(pf,NIL(Sfio_t*)));
268
/* f already in the same pool with pf */
269
if(f == pf || (pf && f->pool == pf->pool && f->pool != &_Sfpool) )
277
/* lock streams before internal manipulations */
283
if(!pf) /* deleting f from its current pool */
284
{ if(!(p = f->pool) || p == &_Sfpool ||
285
_sfpmove(f,-1) < 0 || _sfsetpool(f) < 0)
288
if((p = f->pool) == &_Sfpool || p->n_sf <= 0)
290
else rv = p->sf[0]; /* return head of pool */
294
if(pf->pool && pf->pool != &_Sfpool) /* always use current mode */
295
mode = pf->pool->mode;
297
if(mode&SF_SHARE) /* can only have write streams */
298
{ if(SFMODE(f,1) != SF_WRITE && _sfmode(f,SF_WRITE,1) < 0)
300
if(SFMODE(pf,1) != SF_WRITE && _sfmode(pf,SF_WRITE,1) < 0)
302
if(f->next > f->data && SFSYNC(f) < 0) /* start f clean */
306
if(_sfpmove(f,-1) < 0) /* isolate f from current pool */
309
if(!(p = pf->pool) || p == &_Sfpool) /* making a new pool */
310
{ if(!(p = newpool(mode)) )
312
if(_sfpmove(pf,-1) < 0) /* isolate pf from its current pool */
319
f->pool = p; /* add f to pf's pool */
320
if(_sfsetpool(f) < 0)
323
/**/ASSERT(p->sf[0] == pf && p->sf[p->n_sf-1] == f);
326
if(_sfpmove(f,0) < 0) /* make f head of pool */