Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libast/sfio/sfpool.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1985-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
20
* *
21
***********************************************************************/
22
#include "sfhdr.h"
23
24
/* Management of pools of streams.
25
** If pf is not nil, f is pooled with pf and f becomes current;
26
** otherwise, f is isolated from its pool. flag can be one of
27
** 0 or SF_SHARE.
28
**
29
** Written by Kiem-Phong Vo.
30
*/
31
32
/* Note that we do not free the space for a pool once it is allocated.
33
** This is to prevent memory faults in calls such as sfsync(NULL) that walk the pool
34
** link list and during such walks may free up streams&pools. Free pools will be
35
** reused in newpool().
36
*/
37
#if __STD_C
38
static int delpool(reg Sfpool_t* p)
39
#else
40
static int delpool(p)
41
reg Sfpool_t* p;
42
#endif
43
{
44
POOLMTXENTER(p);
45
46
if(p->s_sf && p->sf != p->array)
47
free((Void_t*)p->sf);
48
p->mode = SF_AVAIL;
49
50
POOLMTXRETURN(p,0);
51
}
52
53
#if __STD_C
54
static Sfpool_t* newpool(reg int mode)
55
#else
56
static Sfpool_t* newpool(mode)
57
reg int mode;
58
#endif
59
{
60
reg Sfpool_t *p, *last = &_Sfpool;
61
62
/* look to see if there is a free pool */
63
for(last = &_Sfpool, p = last->next; p; last = p, p = p->next)
64
{ if(p->mode == SF_AVAIL )
65
{ p->mode = 0;
66
break;
67
}
68
}
69
70
if(!p)
71
{ POOLMTXLOCK(last);
72
73
if(!(p = (Sfpool_t*) malloc(sizeof(Sfpool_t))) )
74
{ POOLMTXUNLOCK(last);
75
return NIL(Sfpool_t*);
76
}
77
78
(void)vtmtxopen(&p->mutex, VT_INIT); /* initialize mutex */
79
80
p->mode = 0;
81
p->n_sf = 0;
82
p->next = NIL(Sfpool_t*);
83
last->next = p;
84
85
POOLMTXUNLOCK(last);
86
}
87
88
POOLMTXENTER(p);
89
90
p->mode = mode&SF_SHARE;
91
p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
92
p->sf = p->array;
93
94
POOLMTXRETURN(p,p);
95
}
96
97
/* move a stream to head */
98
#if __STD_C
99
static int _sfphead(Sfpool_t* p, Sfio_t* f, int n)
100
#else
101
static int _sfphead(p, f, n)
102
Sfpool_t* p; /* the pool */
103
Sfio_t* f; /* the stream */
104
int n; /* current position in pool */
105
#endif
106
{
107
reg Sfio_t* head;
108
reg ssize_t k, w, v;
109
reg int rv;
110
111
POOLMTXENTER(p);
112
113
if(n == 0)
114
POOLMTXRETURN(p,0);
115
116
head = p->sf[0];
117
if(SFFROZEN(head) )
118
POOLMTXRETURN(p,-1);
119
120
SFLOCK(head,0);
121
rv = -1;
122
123
if(!(p->mode&SF_SHARE) || (head->mode&SF_READ) || (f->mode&SF_READ) )
124
{ if(SFSYNC(head) < 0)
125
goto done;
126
}
127
else /* shared pool of write-streams, data can be moved among streams */
128
{ if(SFMODE(head,1) != SF_WRITE && _sfmode(head,SF_WRITE,1) < 0)
129
goto done;
130
/**/ASSERT(f->next == f->data);
131
132
v = head->next - head->data; /* pending data */
133
if((k = v - (f->endb-f->data)) <= 0)
134
k = 0;
135
else /* try to write out amount exceeding f's capacity */
136
{ if((w = SFWR(head,head->data,k,head->disc)) == k)
137
v -= k;
138
else /* write failed, recover buffer then quit */
139
{ if(w > 0)
140
{ v -= w;
141
memmove(head->data,(head->data+w),v);
142
}
143
head->next = head->data+v;
144
goto done;
145
}
146
}
147
148
/* move data from head to f */
149
if((head->data+k) != f->data )
150
memmove(f->data,(head->data+k),v);
151
f->next = f->data+v;
152
}
153
154
f->mode &= ~SF_POOL;
155
head->mode |= SF_POOL;
156
head->next = head->endr = head->endw = head->data; /* clear write buffer */
157
158
p->sf[n] = head;
159
p->sf[0] = f;
160
rv = 0;
161
162
done:
163
head->mode &= ~SF_LOCK; /* partially unlock because it's no longer head */
164
165
POOLMTXRETURN(p,rv);
166
}
167
168
/* delete a stream from its pool */
169
#if __STD_C
170
static int _sfpdelete(Sfpool_t* p, Sfio_t* f, int n)
171
#else
172
static int _sfpdelete(p, f, n)
173
Sfpool_t* p; /* the pool */
174
Sfio_t* f; /* the stream */
175
int n; /* position in pool */
176
#endif
177
{
178
POOLMTXENTER(p);
179
180
p->n_sf -= 1;
181
for(; n < p->n_sf; ++n)
182
p->sf[n] = p->sf[n+1];
183
184
f->pool = NIL(Sfpool_t*);
185
f->mode &= ~SF_POOL;
186
187
if(p->n_sf == 0 || p == &_Sfpool)
188
{ if(p != &_Sfpool)
189
delpool(p);
190
goto done;
191
}
192
193
/* !_Sfpool, make sure head stream is an open stream */
194
for(n = 0; n < p->n_sf; ++n)
195
if(!SFFROZEN(p->sf[n]))
196
break;
197
if(n < p->n_sf && n > 0)
198
{ f = p->sf[n];
199
p->sf[n] = p->sf[0];
200
p->sf[0] = f;
201
}
202
203
/* head stream has SF_POOL off */
204
f = p->sf[0];
205
f->mode &= ~SF_POOL;
206
if(!SFFROZEN(f))
207
_SFOPEN(f);
208
209
/* if only one stream left, delete pool */
210
if(p->n_sf == 1 )
211
{ _sfpdelete(p,f,0);
212
_sfsetpool(f);
213
}
214
215
done:
216
POOLMTXRETURN(p,0);
217
}
218
219
#if __STD_C
220
static int _sfpmove(reg Sfio_t* f, reg int type)
221
#else
222
static int _sfpmove(f,type)
223
reg Sfio_t* f;
224
reg int type; /* <0 : deleting, 0: move-to-front, >0: inserting */
225
#endif
226
{
227
reg Sfpool_t* p;
228
reg int n;
229
230
if(type > 0)
231
return _sfsetpool(f);
232
else
233
{ if(!(p = f->pool) )
234
return -1;
235
for(n = p->n_sf-1; n >= 0; --n)
236
if(p->sf[n] == f)
237
break;
238
if(n < 0)
239
return -1;
240
241
return type == 0 ? _sfphead(p,f,n) : _sfpdelete(p,f,n);
242
}
243
}
244
245
#if __STD_C
246
Sfio_t* sfpool(reg Sfio_t* f, reg Sfio_t* pf, reg int mode)
247
#else
248
Sfio_t* sfpool(f,pf,mode)
249
reg Sfio_t* f;
250
reg Sfio_t* pf;
251
reg int mode;
252
#endif
253
{
254
int k;
255
Sfpool_t* p;
256
Sfio_t* rv;
257
258
_Sfpmove = _sfpmove;
259
260
if(!f) /* return head of pool of pf regardless of lock states */
261
{ if(!pf)
262
return NIL(Sfio_t*);
263
else if(!pf->pool || pf->pool == &_Sfpool)
264
return pf;
265
else return pf->pool->sf[0];
266
}
267
268
if(f) /* check for permissions */
269
{ SFMTXLOCK(f);
270
if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0)
271
{ SFMTXUNLOCK(f);
272
return NIL(Sfio_t*);
273
}
274
if(f->disc == _Sfudisc)
275
(void)sfclose((*_Sfstack)(f,NIL(Sfio_t*)));
276
}
277
if(pf)
278
{ SFMTXLOCK(pf);
279
if((pf->mode&SF_RDWR) != pf->mode && _sfmode(pf,0,0) < 0)
280
{ if(f)
281
SFMTXUNLOCK(f);
282
SFMTXUNLOCK(pf);
283
return NIL(Sfio_t*);
284
}
285
if(pf->disc == _Sfudisc)
286
(void)sfclose((*_Sfstack)(pf,NIL(Sfio_t*)));
287
}
288
289
/* f already in the same pool with pf */
290
if(f == pf || (pf && f->pool == pf->pool && f->pool != &_Sfpool) )
291
{ if(f)
292
SFMTXUNLOCK(f);
293
if(pf)
294
SFMTXUNLOCK(pf);
295
return pf;
296
}
297
298
/* lock streams before internal manipulations */
299
rv = NIL(Sfio_t*);
300
SFLOCK(f,0);
301
if(pf)
302
SFLOCK(pf,0);
303
304
if(!pf) /* deleting f from its current pool */
305
{ if((p = f->pool) != NIL(Sfpool_t*) && p != &_Sfpool)
306
for(k = 0; k < p->n_sf && pf == NIL(Sfio_t*); ++k)
307
if(p->sf[k] != f) /* a stream != f represents the pool */
308
pf = p->sf[k];
309
if(!pf) /* already isolated */
310
{ rv = f; /* just return self */
311
goto done;
312
}
313
314
if(_sfpmove(f,-1) < 0 || _sfsetpool(f) < 0)
315
goto done; /* can't delete */
316
317
if(!pf->pool || pf->pool == &_Sfpool || pf->pool->n_sf <= 0 )
318
rv = pf;
319
else rv = pf->pool->sf[0]; /* return head of old pool */
320
goto done;
321
}
322
323
if(pf->pool && pf->pool != &_Sfpool) /* always use current mode */
324
mode = pf->pool->mode;
325
326
if(mode&SF_SHARE) /* can only have write streams */
327
{ if(SFMODE(f,1) != SF_WRITE && _sfmode(f,SF_WRITE,1) < 0)
328
goto done;
329
if(SFMODE(pf,1) != SF_WRITE && _sfmode(pf,SF_WRITE,1) < 0)
330
goto done;
331
if(f->next > f->data && SFSYNC(f) < 0) /* start f clean */
332
goto done;
333
}
334
335
if(_sfpmove(f,-1) < 0) /* isolate f from current pool */
336
goto done;
337
338
if(!(p = pf->pool) || p == &_Sfpool) /* making a new pool */
339
{ if(!(p = newpool(mode)) )
340
goto done;
341
if(_sfpmove(pf,-1) < 0) /* isolate pf from its current pool */
342
goto done;
343
pf->pool = p;
344
p->sf[0] = pf;
345
p->n_sf += 1;
346
}
347
348
f->pool = p; /* add f to pf's pool */
349
if(_sfsetpool(f) < 0)
350
goto done;
351
352
/**/ASSERT(p->sf[0] == pf && p->sf[p->n_sf-1] == f);
353
SFOPEN(pf,0);
354
SFOPEN(f,0);
355
if(_sfpmove(f,0) < 0) /* make f head of pool */
356
goto done;
357
rv = pf;
358
359
done:
360
if(f)
361
{ SFOPEN(f,0);
362
SFMTXUNLOCK(f);
363
}
364
if(pf)
365
{ SFOPEN(pf,0);
366
SFMTXUNLOCK(pf);
367
}
368
return rv;
369
}
370
371