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 <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 38static int delpool(reg Sfpool_t* p) 39#else 40static int delpool(p) 41reg 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 54static Sfpool_t* newpool(reg int mode) 55#else 56static Sfpool_t* newpool(mode) 57reg 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 99static int _sfphead(Sfpool_t* p, Sfio_t* f, int n) 100#else 101static int _sfphead(p, f, n) 102Sfpool_t* p; /* the pool */ 103Sfio_t* f; /* the stream */ 104int 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 162done: 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 170static int _sfpdelete(Sfpool_t* p, Sfio_t* f, int n) 171#else 172static int _sfpdelete(p, f, n) 173Sfpool_t* p; /* the pool */ 174Sfio_t* f; /* the stream */ 175int 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 215done: 216 POOLMTXRETURN(p,0); 217} 218 219#if __STD_C 220static int _sfpmove(reg Sfio_t* f, reg int type) 221#else 222static int _sfpmove(f,type) 223reg Sfio_t* f; 224reg 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 246Sfio_t* sfpool(reg Sfio_t* f, reg Sfio_t* pf, reg int mode) 247#else 248Sfio_t* sfpool(f,pf,mode) 249reg Sfio_t* f; 250reg Sfio_t* pf; 251reg 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 359done: 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