Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libast/sfio/sfmode.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1985-2012 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
static char* Version = "\n@(#)$Id: sfio (AT&T Labs - Research) 2009-09-15 $\0\n";
24
25
/* Functions to set a given stream to some desired mode
26
**
27
** Written by Kiem-Phong Vo.
28
**
29
** Modifications:
30
** 06/27/1990 (first version)
31
** 01/06/1991
32
** 07/08/1991
33
** 06/18/1992
34
** 02/02/1993
35
** 05/25/1993
36
** 02/07/1994
37
** 05/21/1996
38
** 08/01/1997
39
** 08/01/1998 (extended formatting)
40
** 09/09/1999 (thread-safe)
41
** 02/01/2001 (adaptive buffering)
42
** 05/31/2002 (multi-byte handling in sfvprintf/vscanf)
43
** 09/06/2002 (SF_IOINTR flag)
44
** 11/15/2002 (%#c for sfvprintf)
45
** 05/31/2003 (sfsetbuf(f,f,align_size) to set alignment for data)
46
** (%I1d is fixed to handle "signed char" correctly)
47
** 01/01/2004 Porting issues to various platforms resolved.
48
** 06/01/2008 Allowing notify() at entering/exiting thread-safe routines.
49
** 09/15/2008 Add sfwalk().
50
*/
51
52
/* the below is for protecting the application from SIGPIPE */
53
#if _PACKAGE_ast
54
#include <sig.h>
55
#include <wait.h>
56
#define Sfsignal_f Sig_handler_t
57
#else
58
#include <signal.h>
59
typedef void(* Sfsignal_f)_ARG_((int));
60
#endif
61
static int _Sfsigp = 0; /* # of streams needing SIGPIPE protection */
62
63
/* done at exiting time */
64
#if __STD_C
65
static void _sfcleanup(void)
66
#else
67
static void _sfcleanup()
68
#endif
69
{
70
reg Sfpool_t* p;
71
reg Sfio_t* f;
72
reg int n;
73
reg int pool;
74
75
f = (Sfio_t*)Version; /* shut compiler warning */
76
77
/* set this so that no more buffering is allowed for write streams */
78
_Sfexiting = 1001;
79
80
sfsync(NIL(Sfio_t*));
81
82
for(p = &_Sfpool; p; p = p->next)
83
{ for(n = 0; n < p->n_sf; ++n)
84
{ if(!(f = p->sf[n]) || SFFROZEN(f) )
85
continue;
86
87
SFLOCK(f,0);
88
SFMTXLOCK(f);
89
90
/* let application know that we are leaving */
91
(void)SFRAISE(f, SF_ATEXIT, NIL(Void_t*));
92
93
if(f->flags&SF_STRING)
94
continue;
95
96
/* from now on, write streams are unbuffered */
97
pool = f->mode&SF_POOL;
98
f->mode &= ~SF_POOL;
99
if((f->flags&SF_WRITE) && !(f->mode&SF_WRITE))
100
(void)_sfmode(f,SF_WRITE,1);
101
if(f->data &&
102
((f->bits&SF_MMAP) ||
103
((f->mode&SF_WRITE) && f->next == f->data) ) )
104
(void)SFSETBUF(f,NIL(Void_t*),0);
105
f->mode |= pool;
106
107
SFMTXUNLOCK(f);
108
SFOPEN(f,0);
109
}
110
}
111
}
112
113
/* put into discrete pool */
114
#if __STD_C
115
int _sfsetpool(Sfio_t* f)
116
#else
117
int _sfsetpool(f)
118
Sfio_t* f;
119
#endif
120
{
121
reg Sfpool_t* p;
122
reg Sfio_t** array;
123
reg int n, rv;
124
125
if(!_Sfcleanup)
126
{ _Sfcleanup = _sfcleanup;
127
(void)atexit(_sfcleanup);
128
}
129
130
if(!(p = f->pool) )
131
p = f->pool = &_Sfpool;
132
133
POOLMTXENTER(p);
134
135
rv = -1;
136
137
if(p->n_sf >= p->s_sf)
138
{ if(p->s_sf == 0) /* initialize pool array */
139
{ p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
140
p->sf = p->array;
141
}
142
else /* allocate a larger array */
143
{ n = (p->sf != p->array ? p->s_sf : (p->s_sf/4 + 1)*4) + 4;
144
if(!(array = (Sfio_t**)malloc(n*sizeof(Sfio_t*))) )
145
goto done;
146
147
/* move old array to new one */
148
memcpy((Void_t*)array,(Void_t*)p->sf,p->n_sf*sizeof(Sfio_t*));
149
if(p->sf != p->array)
150
free((Void_t*)p->sf);
151
152
p->sf = array;
153
p->s_sf = n;
154
}
155
}
156
157
/* always add at end of array because if this was done during some sort
158
of walk thru all streams, we'll want the new stream to be seen.
159
*/
160
p->sf[p->n_sf++] = f;
161
rv = 0;
162
163
done:
164
POOLMTXRETURN(p, rv);
165
}
166
167
/* create an auxiliary buffer for sfgetr/sfreserve/sfputr */
168
#if __STD_C
169
Sfrsrv_t* _sfrsrv(reg Sfio_t* f, reg ssize_t size)
170
#else
171
Sfrsrv_t* _sfrsrv(f,size)
172
reg Sfio_t* f;
173
reg ssize_t size;
174
#endif
175
{
176
Sfrsrv_t *rsrv, *rs;
177
178
/* make buffer if nothing yet */
179
size = ((size + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
180
if(!(rsrv = f->rsrv) || size > rsrv->size)
181
{ if(!(rs = (Sfrsrv_t*)malloc(size+sizeof(Sfrsrv_t))))
182
size = -1;
183
else
184
{ if(rsrv)
185
{ if(rsrv->slen > 0)
186
memcpy(rs,rsrv,sizeof(Sfrsrv_t)+rsrv->slen);
187
free(rsrv);
188
}
189
f->rsrv = rsrv = rs;
190
rsrv->size = size;
191
rsrv->slen = 0;
192
}
193
}
194
195
if(rsrv && size > 0)
196
rsrv->slen = 0;
197
198
return size >= 0 ? rsrv : NIL(Sfrsrv_t*);
199
}
200
201
#ifdef SIGPIPE
202
#if __STD_C
203
static void ignoresig(int sig)
204
#else
205
static void ignoresig(sig)
206
int sig;
207
#endif
208
{
209
signal(sig, ignoresig);
210
}
211
#endif
212
213
#if __STD_C
214
int _sfpopen(reg Sfio_t* f, int fd, int pid, int stdio)
215
#else
216
int _sfpopen(f, fd, pid, stdio)
217
reg Sfio_t* f;
218
int fd;
219
int pid;
220
int stdio; /* stdio popen() does not reset SIGPIPE handler */
221
#endif
222
{
223
reg Sfproc_t* p;
224
225
if(f->proc)
226
return 0;
227
228
if(!(p = f->proc = (Sfproc_t*)malloc(sizeof(Sfproc_t))) )
229
return -1;
230
231
p->pid = pid;
232
p->size = p->ndata = 0;
233
p->rdata = NIL(uchar*);
234
p->file = fd;
235
p->sigp = (!stdio && pid >= 0 && (f->flags&SF_WRITE)) ? 1 : 0;
236
237
#ifdef SIGPIPE /* protect from broken pipe signal */
238
if(p->sigp)
239
{ Sfsignal_f handler;
240
241
(void)vtmtxlock(_Sfmutex);
242
if((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL &&
243
handler != ignoresig)
244
signal(SIGPIPE, handler); /* honor user handler */
245
_Sfsigp += 1;
246
(void)vtmtxunlock(_Sfmutex);
247
}
248
#endif
249
250
return 0;
251
}
252
253
#if __STD_C
254
int _sfpclose(reg Sfio_t* f)
255
#else
256
int _sfpclose(f)
257
reg Sfio_t* f; /* stream to close */
258
#endif
259
{
260
Sfproc_t* p;
261
int pid, status;
262
263
if(!(p = f->proc))
264
return -1;
265
f->proc = NIL(Sfproc_t*);
266
267
if(p->rdata)
268
free(p->rdata);
269
270
if(p->pid < 0)
271
status = 0;
272
else
273
{ /* close the associated stream */
274
if(p->file >= 0)
275
CLOSE(p->file);
276
277
/* wait for process termination */
278
#if _PACKAGE_ast
279
sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
280
#endif
281
status = -1;
282
while ((pid = waitpid(p->pid,&status,0)) == -1 && errno == EINTR)
283
;
284
#if _PACKAGE_ast
285
status = status == -1 ?
286
EXIT_QUIT :
287
WIFSIGNALED(status) ?
288
EXIT_TERM(WTERMSIG(status)) :
289
EXIT_CODE(WEXITSTATUS(status));
290
sigcritical(0);
291
#endif
292
293
#ifdef SIGPIPE
294
(void)vtmtxlock(_Sfmutex);
295
if(p->sigp && (_Sfsigp -= 1) <= 0)
296
{ Sfsignal_f handler;
297
if((handler = signal(SIGPIPE,SIG_DFL)) != SIG_DFL &&
298
handler != ignoresig)
299
signal(SIGPIPE,handler); /* honor user handler */
300
_Sfsigp = 0;
301
}
302
(void)vtmtxunlock(_Sfmutex);
303
#endif
304
}
305
306
free(p);
307
return status;
308
}
309
310
#if __STD_C
311
static int _sfpmode(Sfio_t* f, int type)
312
#else
313
static int _sfpmode(f,type)
314
Sfio_t* f;
315
int type;
316
#endif
317
{
318
Sfproc_t* p;
319
320
if(!(p = f->proc) )
321
return -1;
322
323
if(type == SF_WRITE)
324
{ /* save unread data */
325
p->ndata = f->endb-f->next;
326
if(p->ndata > p->size)
327
{ if(p->rdata)
328
free((char*)p->rdata);
329
if((p->rdata = (uchar*)malloc(p->ndata)) )
330
p->size = p->ndata;
331
else
332
{ p->size = 0;
333
return -1;
334
}
335
}
336
if(p->ndata > 0)
337
memcpy((Void_t*)p->rdata,(Void_t*)f->next,p->ndata);
338
f->endb = f->data;
339
}
340
else
341
{ /* restore read data */
342
if(p->ndata > f->size) /* may lose data!!! */
343
p->ndata = f->size;
344
if(p->ndata > 0)
345
{ memcpy((Void_t*)f->data,(Void_t*)p->rdata,p->ndata);
346
f->endb = f->data+p->ndata;
347
p->ndata = 0;
348
}
349
}
350
351
/* switch file descriptor */
352
if(p->pid >= 0)
353
{ type = f->file;
354
f->file = p->file;
355
p->file = type;
356
}
357
358
return 0;
359
}
360
361
#if __STD_C
362
int _sfmode(reg Sfio_t* f, reg int wanted, reg int local)
363
#else
364
int _sfmode(f, wanted, local)
365
reg Sfio_t* f; /* change r/w mode and sync file pointer for this stream */
366
reg int wanted; /* desired mode */
367
reg int local; /* a local call */
368
#endif
369
{
370
reg int n;
371
Sfoff_t addr;
372
reg int rv = 0;
373
374
SFONCE(); /* initialize mutexes */
375
376
if(wanted&SF_SYNCED) /* for (SF_SYNCED|SF_READ) stream, just junk data */
377
{ wanted &= ~SF_SYNCED;
378
if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
379
{ f->next = f->endb = f->endr = f->data;
380
f->mode &= ~SF_SYNCED;
381
}
382
}
383
384
if((!local && SFFROZEN(f)) || (!(f->flags&SF_STRING) && f->file < 0))
385
{ if(local || !f->disc || !f->disc->exceptf)
386
{ local = 1;
387
goto err_notify;
388
}
389
390
for(;;)
391
{ if((rv = (*f->disc->exceptf)(f,SF_LOCKED,0,f->disc)) < 0)
392
return rv;
393
if((!local && SFFROZEN(f)) ||
394
(!(f->flags&SF_STRING) && f->file < 0) )
395
{ if(rv == 0)
396
{ local = 1;
397
goto err_notify;
398
}
399
else continue;
400
}
401
else break;
402
}
403
}
404
405
if(f->mode&SF_GETR)
406
{ f->mode &= ~SF_GETR;
407
#ifdef MAP_TYPE
408
if((f->bits&SF_MMAP) && (f->tiny[0] += 1) >= (4*SF_NMAP) )
409
{ /* turn off mmap to avoid page faulting */
410
sfsetbuf(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
411
f->tiny[0] = 0;
412
}
413
else
414
#endif
415
if(f->getr)
416
{ f->next[-1] = f->getr;
417
f->getr = 0;
418
}
419
}
420
421
if(f->mode&SF_STDIO) /* synchronizing with stdio pointers */
422
(*_Sfstdsync)(f);
423
424
if(f->disc == _Sfudisc && wanted == SF_WRITE &&
425
sfclose((*_Sfstack)(f,NIL(Sfio_t*))) < 0 )
426
{ local = 1;
427
goto err_notify;
428
}
429
430
if(f->mode&SF_POOL)
431
{ /* move to head of pool */
432
if(f == f->pool->sf[0] || (*_Sfpmove)(f,0) < 0 )
433
{ local = 1;
434
goto err_notify;
435
}
436
f->mode &= ~SF_POOL;
437
}
438
439
SFLOCK(f,local);
440
441
/* buffer initialization */
442
wanted &= SF_RDWR;
443
if(f->mode&SF_INIT)
444
{
445
if(!f->pool && _sfsetpool(f) < 0)
446
{ rv = -1;
447
goto done;
448
}
449
450
if(wanted == 0)
451
goto done;
452
453
if(wanted != (int)(f->mode&SF_RDWR) && !(f->flags&wanted) )
454
goto err_notify;
455
456
if((f->flags&SF_STRING) && f->size >= 0 && f->data)
457
{ f->mode &= ~SF_INIT;
458
f->extent = ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ?
459
f->size : 0;
460
f->here = 0;
461
f->endb = f->data + f->size;
462
f->next = f->endr = f->endw = f->data;
463
if(f->mode&SF_READ)
464
f->endr = f->endb;
465
else f->endw = f->endb;
466
}
467
else
468
{ n = f->flags;
469
(void)SFSETBUF(f,f->data,f->size);
470
f->flags |= (n&SF_MALLOC);
471
}
472
}
473
474
if(wanted == (int)SFMODE(f,1))
475
goto done;
476
477
switch(SFMODE(f,1))
478
{
479
case SF_WRITE: /* switching to SF_READ */
480
if(wanted == 0 || wanted == SF_WRITE)
481
break;
482
if(!(f->flags&SF_READ) )
483
goto err_notify;
484
else if(f->flags&SF_STRING)
485
{ SFSTRSIZE(f);
486
f->endb = f->data+f->extent;
487
f->mode = SF_READ;
488
break;
489
}
490
491
/* reset buffer */
492
if(f->next > f->data && SFFLSBUF(f,-1) < 0)
493
goto err_notify;
494
495
if(f->size == 0)
496
{ /* unbuffered */
497
f->data = f->tiny;
498
f->size = sizeof(f->tiny);
499
}
500
f->next = f->endr = f->endw = f->endb = f->data;
501
f->mode = SF_READ|SF_LOCK;
502
503
/* restore saved read data for coprocess */
504
if(f->proc && _sfpmode(f,wanted) < 0)
505
goto err_notify;
506
507
break;
508
509
case (SF_READ|SF_SYNCED): /* a previously sync-ed read stream */
510
if(wanted != SF_WRITE)
511
{ /* just reset the pointers */
512
f->mode = SF_READ|SF_LOCK;
513
514
/* see if must go with new physical location */
515
if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
516
(addr = SFSK(f,0,SEEK_CUR,f->disc)) != f->here)
517
{
518
#ifdef MAP_TYPE
519
if((f->bits&SF_MMAP) && f->data)
520
{ SFMUNMAP(f,f->data,f->endb-f->data);
521
f->data = NIL(uchar*);
522
}
523
#endif
524
f->endb = f->endr = f->endw = f->next = f->data;
525
f->here = addr;
526
}
527
else
528
{ addr = f->here + (f->endb - f->next);
529
if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
530
goto err_notify;
531
f->here = addr;
532
}
533
534
break;
535
}
536
/* fall thru */
537
538
case SF_READ: /* switching to SF_WRITE */
539
if(wanted != SF_WRITE)
540
break;
541
else if(!(f->flags&SF_WRITE))
542
goto err_notify;
543
else if(f->flags&SF_STRING)
544
{ f->endb = f->data+f->size;
545
f->mode = SF_WRITE|SF_LOCK;
546
break;
547
}
548
549
/* save unread data before switching mode */
550
if(f->proc && _sfpmode(f,wanted) < 0)
551
goto err_notify;
552
553
/* reset buffer and seek pointer */
554
if(!(f->mode&SF_SYNCED) )
555
{ n = f->endb - f->next;
556
if(f->extent >= 0 && (n > 0 || (f->data && (f->bits&SF_MMAP))) )
557
{ /* reset file pointer */
558
addr = f->here - n;
559
if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
560
goto err_notify;
561
f->here = addr;
562
}
563
}
564
565
f->mode = SF_WRITE|SF_LOCK;
566
#ifdef MAP_TYPE
567
if(f->bits&SF_MMAP)
568
{ if(f->data)
569
SFMUNMAP(f,f->data,f->endb-f->data);
570
(void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
571
}
572
#endif
573
if(f->data == f->tiny)
574
{ f->endb = f->data = f->next = NIL(uchar*);
575
f->size = 0;
576
}
577
else f->endb = (f->next = f->data) + f->size;
578
579
break;
580
581
default: /* unknown case */
582
err_notify:
583
if((wanted &= SF_RDWR) == 0 && (wanted = f->flags&SF_RDWR) == SF_RDWR)
584
wanted = SF_READ;
585
586
/* set errno for operations that access wrong stream type */
587
if(wanted != (f->mode&SF_RDWR) && f->file >= 0)
588
errno = EBADF;
589
590
if(_Sfnotify) /* notify application of the error */
591
(*_Sfnotify)(f, wanted, (void*)((long)f->file));
592
593
rv = -1;
594
break;
595
}
596
597
done:
598
SFOPEN(f,local);
599
return rv;
600
}
601
602