1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2009 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 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