1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2008 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 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 memcpy(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 memcpy(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 reg Sfpool_t* p; 255 reg Sfio_t* rv; 256 257 _Sfpmove = _sfpmove; 258 259 if(!f) /* return head of pool of pf regardless of lock states */ 260 { if(!pf) 261 return NIL(Sfio_t*); 262 else if(!pf->pool || pf->pool == &_Sfpool) 263 return pf; 264 else return pf->pool->sf[0]; 265 } 266 267 if(f) /* check for permissions */ 268 { SFMTXLOCK(f); 269 if((f->mode&SF_RDWR) != f->mode && _sfmode(f,0,0) < 0) 270 { SFMTXUNLOCK(f); 271 return NIL(Sfio_t*); 272 } 273 if(f->disc == _Sfudisc) 274 (void)sfclose((*_Sfstack)(f,NIL(Sfio_t*))); 275 } 276 if(pf) 277 { SFMTXLOCK(pf); 278 if((pf->mode&SF_RDWR) != pf->mode && _sfmode(pf,0,0) < 0) 279 { if(f) 280 SFMTXUNLOCK(f); 281 SFMTXUNLOCK(pf); 282 return NIL(Sfio_t*); 283 } 284 if(pf->disc == _Sfudisc) 285 (void)sfclose((*_Sfstack)(pf,NIL(Sfio_t*))); 286 } 287 288 /* f already in the same pool with pf */ 289 if(f == pf || (pf && f->pool == pf->pool && f->pool != &_Sfpool) ) 290 { if(f) 291 SFMTXUNLOCK(f); 292 if(pf) 293 SFMTXUNLOCK(pf); 294 return pf; 295 } 296 297 /* lock streams before internal manipulations */ 298 rv = NIL(Sfio_t*); 299 SFLOCK(f,0); 300 if(pf) 301 SFLOCK(pf,0); 302 303 if(!pf) /* deleting f from its current pool */ 304 { if(!(p = f->pool) || p == &_Sfpool || 305 _sfpmove(f,-1) < 0 || _sfsetpool(f) < 0) 306 goto done; 307 308 if((p = f->pool) == &_Sfpool || p->n_sf <= 0) 309 rv = f; 310 else rv = p->sf[0]; /* return head of pool */ 311 goto done; 312 } 313 314 if(pf->pool && pf->pool != &_Sfpool) /* always use current mode */ 315 mode = pf->pool->mode; 316 317 if(mode&SF_SHARE) /* can only have write streams */ 318 { if(SFMODE(f,1) != SF_WRITE && _sfmode(f,SF_WRITE,1) < 0) 319 goto done; 320 if(SFMODE(pf,1) != SF_WRITE && _sfmode(pf,SF_WRITE,1) < 0) 321 goto done; 322 if(f->next > f->data && SFSYNC(f) < 0) /* start f clean */ 323 goto done; 324 } 325 326 if(_sfpmove(f,-1) < 0) /* isolate f from current pool */ 327 goto done; 328 329 if(!(p = pf->pool) || p == &_Sfpool) /* making a new pool */ 330 { if(!(p = newpool(mode)) ) 331 goto done; 332 if(_sfpmove(pf,-1) < 0) /* isolate pf from its current pool */ 333 goto done; 334 pf->pool = p; 335 p->sf[0] = pf; 336 p->n_sf += 1; 337 } 338 339 f->pool = p; /* add f to pf's pool */ 340 if(_sfsetpool(f) < 0) 341 goto done; 342 343 /**/ASSERT(p->sf[0] == pf && p->sf[p->n_sf-1] == f); 344 SFOPEN(pf,0); 345 SFOPEN(f,0); 346 if(_sfpmove(f,0) < 0) /* make f head of pool */ 347 goto done; 348 rv = pf; 349 350 done: 351 if(f) 352 { SFOPEN(f,0); 353 SFMTXUNLOCK(f); 354 } 355 if(pf) 356 { SFOPEN(pf,0); 357 SFMTXUNLOCK(pf); 358 } 359 return rv; 360 } 361