ape/stdio: make fopen() quasi threadsafe for python

python uses processes sharing memory. it requires at least fopen() to
be called by multiple threads at once so we introduce _IO_newfile()
which allocates the FILE structure slot under a lock.
This commit is contained in:
cinap_lenrek 2013-03-11 00:48:35 +01:00
parent 530a2bc5e9
commit 48b0c10681
14 changed files with 79 additions and 24 deletions

View file

@ -8,7 +8,7 @@ int _IO_getc(FILE *f){
default: /* CLOSED, WR, ERR, EOF */ default: /* CLOSED, WR, ERR, EOF */
return EOF; return EOF;
case OPEN: case OPEN:
_IO_setvbuf(f); if(_IO_setvbuf(f)!=0) return EOF;
case RDWR: case RDWR:
case RD: case RD:
if(f->flags&STRING) return EOF; if(f->flags&STRING) return EOF;
@ -17,6 +17,7 @@ int _IO_getc(FILE *f){
else else
n = f->bufl; n = f->bufl;
cnt=read(f->fd, f->buf, n); cnt=read(f->fd, f->buf, n);
if(f->state==CLOSED) return EOF;
switch(cnt){ switch(cnt){
case -1: f->state=ERR; return EOF; case -1: f->state=ERR; return EOF;
case 0: f->state=END; return EOF; case 0: f->state=END; return EOF;

View file

@ -0,0 +1,27 @@
/*
* pANS stdio -- fopen
*/
#include "iolib.h"
#define _PLAN9_SOURCE
#include <lock.h>
FILE *_IO_newfile(void)
{
static FILE *fx=0;
static Lock fl;
FILE *f;
int i;
lock(&fl);
for(i=0; i<FOPEN_MAX; i++){
if(fx==0 || ++fx >= &_IO_stream[FOPEN_MAX]) fx=_IO_stream;
if(fx->state==CLOSED)
break;
}
f = fx;
unlock(&fl);
if(f->state!=CLOSED)
return NULL;
return f;
}

View file

@ -19,7 +19,8 @@ int _IO_putc(int c, FILE *f){
case CLOSED: case CLOSED:
return EOF; return EOF;
case OPEN: case OPEN:
_IO_setvbuf(f); if(_IO_setvbuf(f)!=0)
return EOF;
/* fall through */ /* fall through */
case RDWR: case RDWR:
case END: case END:

View file

@ -3,12 +3,28 @@
*/ */
#include "iolib.h" #include "iolib.h"
int fclose(FILE *f){ int fclose(FILE *f){
int error=0; int d, error=0;
char *p;
if(!f) return EOF; if(!f) return EOF;
if(f->state==CLOSED) return EOF; if(f->state==CLOSED) return EOF;
if(fflush(f)==EOF) error=EOF; if(fflush(f)==EOF) error=EOF;
if(f->flags&BALLOC) free(f->buf); if(f->flags&BALLOC){
if(!(f->flags&STRING) && close(f->fd)<0) error=EOF; if((p = f->buf)!=0){
f->buf = 0;
f->wp = 0;
f->rp = 0;
f->lp = 0;
free(p);
}
}
if(!(f->flags&STRING)){
if((d = f->fd)>=0){
f->fd = -1;
if(close(d) < 0)
error = EOF;
}
}
f->state=CLOSED; f->state=CLOSED;
f->flags=0; f->flags=0;
return error; return error;

View file

@ -14,10 +14,8 @@
*/ */
FILE *fdopen(const int fd, const char *mode){ FILE *fdopen(const int fd, const char *mode){
FILE *f; FILE *f;
for(f=_IO_stream;f!=&_IO_stream[FOPEN_MAX];f++)
if(f->state==CLOSED) if((f = _IO_newfile()) == NULL)
break;
if(f==&_IO_stream[FOPEN_MAX])
return NULL; return NULL;
f->fd=fd; f->fd=fd;
if(mode[0]=='a') if(mode[0]=='a')

View file

@ -21,6 +21,7 @@ int fflush(FILE *f){
case WR: case WR:
cnt=(f->flags&LINEBUF?f->lp:f->wp)-f->buf; cnt=(f->flags&LINEBUF?f->lp:f->wp)-f->buf;
if(cnt && write(f->fd, f->buf, cnt)!=cnt){ if(cnt && write(f->fd, f->buf, cnt)!=cnt){
if(f->state!=CLOSED)
f->state=ERR; f->state=ERR;
return EOF; return EOF;
} }

View file

@ -2,10 +2,11 @@
* pANS stdio -- fopen * pANS stdio -- fopen
*/ */
#include "iolib.h" #include "iolib.h"
FILE *fopen(const char *name, const char *mode){ FILE *fopen(const char *name, const char *mode){
FILE *f; FILE *f;
for(f=_IO_stream;f!=&_IO_stream[FOPEN_MAX];f++)
if(f->state==CLOSED) if((f = _IO_newfile()) == NULL)
return freopen(name, mode, f);
return NULL; return NULL;
return freopen(name, mode, f);
} }

View file

@ -12,7 +12,7 @@ size_t fread(void *p, size_t recl, size_t nrec, FILE *f){
s=(char *)p; s=(char *)p;
n=recl*nrec; n=recl*nrec;
while(n>0){ while(n>0 && f->state!=CLOSED){
d=f->wp-f->rp; d=f->wp-f->rp;
if(d>0){ if(d>0){
if(d>n) if(d>n)
@ -23,6 +23,7 @@ size_t fread(void *p, size_t recl, size_t nrec, FILE *f){
if(f->buf==f->unbuf || (n >= BIGN && f->state==RD && !(f->flags&STRING))){ if(f->buf==f->unbuf || (n >= BIGN && f->state==RD && !(f->flags&STRING))){
d=read(f->fd, s, n); d=read(f->fd, s, n);
if(d<=0){ if(d<=0){
if(f->state!=CLOSED)
f->state=(d==0)?END:ERR; f->state=(d==0)?END:ERR;
goto ret; goto ret;
} }

View file

@ -12,7 +12,7 @@ size_t fwrite(const void *p, size_t recl, size_t nrec, FILE *f){
s=(char *)p; s=(char *)p;
n=recl*nrec; n=recl*nrec;
while(n>0){ while(n>0 && f->state!=CLOSED){
d=f->rp-f->wp; d=f->rp-f->wp;
if(d>0){ if(d>0){
if(d>n) if(d>n)
@ -26,6 +26,7 @@ size_t fwrite(const void *p, size_t recl, size_t nrec, FILE *f){
if(f->flags&APPEND) if(f->flags&APPEND)
lseek(f->fd, 0L, SEEK_END); lseek(f->fd, 0L, SEEK_END);
if(write(f->fd, f->buf, d)!=d){ if(write(f->fd, f->buf, d)!=d){
if(f->state!=CLOSED)
f->state=ERR; f->state=ERR;
goto ret; goto ret;
} }
@ -35,6 +36,7 @@ size_t fwrite(const void *p, size_t recl, size_t nrec, FILE *f){
lseek(f->fd, 0L, SEEK_END); lseek(f->fd, 0L, SEEK_END);
d=write(f->fd, s, n); d=write(f->fd, s, n);
if(d<=0){ if(d<=0){
if(f->state!=CLOSED)
f->state=ERR; f->state=ERR;
goto ret; goto ret;
} }

View file

@ -42,3 +42,4 @@ int _IO_setvbuf(FILE *);
FILE *_IO_sopenr(const char*); FILE *_IO_sopenr(const char*);
FILE *_IO_sopenw(void); FILE *_IO_sopenw(void);
char *_IO_sclose(FILE *); char *_IO_sclose(FILE *);
FILE *_IO_newfile(void);

View file

@ -2,6 +2,7 @@ APE=/sys/src/ape
<$APE/config <$APE/config
LIB=/$objtype/lib/ape/libap.a LIB=/$objtype/lib/ape/libap.a
OFILES=\ OFILES=\
_IO_newfile.$O\
_IO_getc.$O\ _IO_getc.$O\
_IO_putc.$O\ _IO_putc.$O\
_dtoa.$O\ _dtoa.$O\

View file

@ -12,7 +12,8 @@ char *rdline(FILE *f, char **ep){
default: /* CLOSED, WR, ERR, EOF */ default: /* CLOSED, WR, ERR, EOF */
return NULL; return NULL;
case OPEN: case OPEN:
_IO_setvbuf(f); if(_IO_setvbuf(f)!=0)
return NULL;
case RDWR: case RDWR:
f->state=RD; f->state=RD;
case RD: case RD:
@ -46,6 +47,8 @@ char *rdline(FILE *f, char **ep){
break; break;
} }
cnt=read(f->fd, f->wp, cnt); cnt=read(f->fd, f->wp, cnt);
if(f->state==CLOSED)
return NULL;
if(cnt==-1){ if(cnt==-1){
f->state=ERR; f->state=ERR;
return NULL; return NULL;

View file

@ -6,8 +6,9 @@
FILE *_IO_sopenr(const char *s){ FILE *_IO_sopenr(const char *s){
FILE *f; FILE *f;
for(f=_IO_stream;f!=&_IO_stream[FOPEN_MAX];f++) if(f->state==CLOSED) break;
if(f==&_IO_stream[FOPEN_MAX]) return NULL; if((f=_IO_newfile())==NULL)
return NULL;
f->buf=f->rp=(char *)s; /* what an annoyance const is */ f->buf=f->rp=(char *)s; /* what an annoyance const is */
f->bufl=strlen(s); f->bufl=strlen(s);
f->wp=f->buf+f->bufl; f->wp=f->buf+f->bufl;

View file

@ -5,8 +5,9 @@
FILE *_IO_sopenw(void){ FILE *_IO_sopenw(void){
FILE *f; FILE *f;
for(f=_IO_stream;f!=&_IO_stream[FOPEN_MAX];f++) if(f->state==CLOSED) break;
if(f==&_IO_stream[FOPEN_MAX]) return NULL; if((f=_IO_newfile())==NULL)
return NULL;
f->buf=f->rp=f->wp=0; f->buf=f->rp=f->wp=0;
f->state=OPEN; f->state=OPEN;
f->flags=STRING; f->flags=STRING;