Skip to content
Snippets Groups Projects
Commit d169dfc1 authored by Christoph Hellwig's avatar Christoph Hellwig
Browse files

provide thread safety for the stdio routines

parent 54d1a24a
No related branches found
No related tags found
No related merge requests found
Showing with 50 additions and 42 deletions
...@@ -50,7 +50,7 @@ FILE *__fdopen(int fd, const char *mode) ...@@ -50,7 +50,7 @@ FILE *__fdopen(int fd, const char *mode)
f->seek = __stdio_seek; f->seek = __stdio_seek;
f->close = __stdio_close; f->close = __stdio_close;
if (!libc.threaded) f->lock = -1; if (!libc.threaded) f->lock_owner = STDIO_SINGLETHREADED;
/* Add new FILE to open file list */ /* Add new FILE to open file list */
OFLLOCK(); OFLLOCK();
......
...@@ -15,7 +15,7 @@ FILE *__fopen_rb_ca(const char *filename, FILE *f, unsigned char *buf, size_t le ...@@ -15,7 +15,7 @@ FILE *__fopen_rb_ca(const char *filename, FILE *f, unsigned char *buf, size_t le
f->read = __stdio_read; f->read = __stdio_read;
f->seek = __stdio_seek; f->seek = __stdio_seek;
f->close = __stdio_close; f->close = __stdio_close;
f->lock = -1; f->lock_owner = STDIO_SINGLETHREADED;
return f; return f;
} }
#include <assert.h>
#include <pthread.h>
#include "stdio_impl.h" #include "stdio_impl.h"
//#include "pthread_impl.h"
int __lockfile(FILE *f) int __lockfile(FILE *f)
{ {
#ifdef TODO pthread_t self = pthread_self();
int owner, tid = __pthread_self()->tid; if (f->lock_owner == self)
if (f->lock == tid)
return 0; return 0;
while ((owner = a_cas(&f->lock, 0, tid))) mutex_lock(&f->mutex);
__wait(&f->lock, &f->waiters, owner, 1); f->lock_owner = self;
#endif
return 1; return 1;
} }
void __unlockfile(FILE *f) void __unlockfile(FILE *f)
{ {
#ifdef TODO assert(f->lock_owner == pthread_self());
a_store(&f->lock, 0); f->lock_owner = 0;
mutex_unlock(&f->mutex);
/* The following read is technically invalid under situations
* of self-synchronized destruction. Another thread may have
* called fclose as soon as the above store has completed.
* Nonetheless, since FILE objects always live in memory
* obtained by malloc from the heap, it's safe to assume
* the dereferences below will not fault. In the worst case,
* a spurious syscall will be made. If the implementation of
* malloc changes, this assumption needs revisiting. */
if (f->waiters) __wake(&f->lock, 1, 1);
#endif
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
int fgetc(FILE *f) int fgetc(FILE *f)
{ {
int c; int c;
if (f->lock < 0 || !__lockfile(f)) if (f->lock_owner == STDIO_SINGLETHREADED || !__lockfile(f))
return getc_unlocked(f); return getc_unlocked(f);
c = getc_unlocked(f); c = getc_unlocked(f);
__unlockfile(f); __unlockfile(f);
......
...@@ -109,7 +109,7 @@ FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode) ...@@ -109,7 +109,7 @@ FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode)
f->seek = mseek; f->seek = mseek;
f->close = mclose; f->close = mclose;
if (!libc.threaded) f->lock = -1; if (!libc.threaded) f->lock_owner = STDIO_SINGLETHREADED;
OFLLOCK(); OFLLOCK();
f->next = libc.ofl_head; f->next = libc.ofl_head;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
int fputc(int c, FILE *f) int fputc(int c, FILE *f)
{ {
if (f->lock < 0 || !__lockfile(f)) if (f->lock_owner == STDIO_SINGLETHREADED || !__lockfile(f))
return putc_unlocked(c, f); return putc_unlocked(c, f);
c = putc_unlocked(c, f); c = putc_unlocked(c, f);
__unlockfile(f); __unlockfile(f);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
int getc(FILE *f) int getc(FILE *f)
{ {
int c; int c;
if (f->lock < 0 || !__lockfile(f)) if (f->lock_owner == STDIO_SINGLETHREADED || !__lockfile(f))
return getc_unlocked(f); return getc_unlocked(f);
c = getc_unlocked(f); c = getc_unlocked(f);
__unlockfile(f); __unlockfile(f);
......
...@@ -78,7 +78,7 @@ FILE *open_memstream(char **bufp, size_t *sizep) ...@@ -78,7 +78,7 @@ FILE *open_memstream(char **bufp, size_t *sizep)
f->seek = ms_seek; f->seek = ms_seek;
f->close = ms_close; f->close = ms_close;
if (!libc.threaded) f->lock = -1; if (!libc.threaded) f->lock_owner = STDIO_SINGLETHREADED;
OFLLOCK(); OFLLOCK();
f->next = libc.ofl_head; f->next = libc.ofl_head;
......
...@@ -79,7 +79,7 @@ FILE *open_wmemstream(wchar_t **bufp, size_t *sizep) ...@@ -79,7 +79,7 @@ FILE *open_wmemstream(wchar_t **bufp, size_t *sizep)
f->seek = wms_seek; f->seek = wms_seek;
f->close = wms_close; f->close = wms_close;
if (!libc.threaded) f->lock = -1; if (!libc.threaded) f->lock_owner = STDIO_SINGLETHREADED;
OFLLOCK(); OFLLOCK();
f->next = libc.ofl_head; f->next = libc.ofl_head;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
int putc(int c, FILE *f) int putc(int c, FILE *f)
{ {
if (f->lock < 0 || !__lockfile(f)) if (f->lock_owner == STDIO_SINGLETHREADED || !__lockfile(f))
return putc_unlocked(c, f); return putc_unlocked(c, f);
c = putc_unlocked(c, f); c = putc_unlocked(c, f);
__unlockfile(f); __unlockfile(f);
......
...@@ -10,7 +10,7 @@ static FILE f = { ...@@ -10,7 +10,7 @@ static FILE f = {
.write = __stdio_write, .write = __stdio_write,
.seek = __stdio_seek, .seek = __stdio_seek,
.close = __stdio_close, .close = __stdio_close,
.lock = -1, .lock_owner = STDIO_SINGLETHREADED,
}; };
FILE *const stderr = &f; FILE *const stderr = &f;
FILE *const __stderr_used = &f; FILE *const __stderr_used = &f;
...@@ -9,7 +9,7 @@ static FILE f = { ...@@ -9,7 +9,7 @@ static FILE f = {
.read = __stdio_read, .read = __stdio_read,
.seek = __stdio_seek, .seek = __stdio_seek,
.close = __stdio_close, .close = __stdio_close,
.lock = -1, .lock_owner = STDIO_SINGLETHREADED,
}; };
FILE *const stdin = &f; FILE *const stdin = &f;
FILE *const __stdin_used = &f; FILE *const __stdin_used = &f;
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
#define UNGET 8 #define UNGET 8
#define FFINALLOCK(f) ((f)->lock>=0 ? __lockfile((f)) : 0) #define FFINALLOCK(f) \
#define FLOCK(f) int __need_unlock = ((f)->lock>=0 ? __lockfile((f)) : 0) ((f)->lock_owner != STDIO_SINGLETHREADED ? __lockfile((f)) : 0)
#define FLOCK(f) \
int __need_unlock = ((f)->lock_owner != STDIO_SINGLETHREADED ? __lockfile((f)) : 0)
#define FUNLOCK(f) if (__need_unlock) __unlockfile((f)); else #define FUNLOCK(f) if (__need_unlock) __unlockfile((f)); else
#define F_PERM 1 #define F_PERM 1
...@@ -17,6 +19,15 @@ ...@@ -17,6 +19,15 @@
#define F_ERR 32 #define F_ERR 32
#define F_SVB 64 #define F_SVB 64
/*
* Note: this structure is layed out so that the fields which are accessed
* by the unlocked getc/putc macros is identical to glibc. Make sure to
* consult glibc before changing the layout of any fields. Adding new fields
* should be generally okay.
*
* See musl commit e3cd6c5c265cd481db6e0c5b529855d99f0bda30 for some more
* details.
*/
struct __FILE_s { struct __FILE_s {
unsigned flags; unsigned flags;
unsigned char *rpos, *rend; unsigned char *rpos, *rend;
...@@ -36,7 +47,7 @@ struct __FILE_s { ...@@ -36,7 +47,7 @@ struct __FILE_s {
short dummy3; short dummy3;
signed char mode; signed char mode;
signed char lbf; signed char lbf;
int lock; int dummy4;
int waiters; int waiters;
void *cookie; void *cookie;
off_t off; off_t off;
...@@ -44,6 +55,15 @@ struct __FILE_s { ...@@ -44,6 +55,15 @@ struct __FILE_s {
void *mustbezero_2; void *mustbezero_2;
unsigned char *shend; unsigned char *shend;
off_t shlim, shcnt; off_t shlim, shcnt;
/*
* Using magic -1 and 0 values for pthread_t fields is a dangerous
* game, but with our implementation of pthread_t as a pointer
* we'll get away with it for now.
*/
#define STDIO_SINGLETHREADED ((pthread_t)-1)
pthread_t lock_owner;
mutex_t mutex;
}; };
size_t __stdio_read(FILE *, unsigned char *, size_t); size_t __stdio_read(FILE *, unsigned char *, size_t);
......
...@@ -10,7 +10,7 @@ static FILE f = { ...@@ -10,7 +10,7 @@ static FILE f = {
.write = __stdout_write, .write = __stdout_write,
.seek = __stdio_seek, .seek = __stdio_seek,
.close = __stdio_close, .close = __stdio_close,
.lock = -1, .lock_owner = STDIO_SINGLETHREADED,
}; };
FILE *const stdout = &f; FILE *const stdout = &f;
FILE *const __stdout_used = &f; FILE *const __stdout_used = &f;
...@@ -10,7 +10,7 @@ int vdprintf(int fd, const char *restrict fmt, va_list ap) ...@@ -10,7 +10,7 @@ int vdprintf(int fd, const char *restrict fmt, va_list ap)
FILE f = { FILE f = {
.fd = fd, .lbf = EOF, .write = wrap_write, .fd = fd, .lbf = EOF, .write = wrap_write,
.buf = (void *)fmt, .buf_size = 0, .buf = (void *)fmt, .buf_size = 0,
.lock = -1 .lock_owner = STDIO_SINGLETHREADED,
}; };
return vfprintf(&f, fmt, ap); return vfprintf(&f, fmt, ap);
} }
...@@ -18,7 +18,7 @@ int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap) ...@@ -18,7 +18,7 @@ int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list ap)
{ {
int r; int r;
char b; char b;
FILE f = { .lbf = EOF, .write = sn_write, .lock = -1 }; FILE f = { .lbf = EOF, .write = sn_write, .lock_owner = STDIO_SINGLETHREADED };
if (n-1 > INT_MAX-1) { if (n-1 > INT_MAX-1) {
if (n) { if (n) {
......
...@@ -9,7 +9,7 @@ int vsscanf(const char *restrict s, const char *restrict fmt, va_list ap) ...@@ -9,7 +9,7 @@ int vsscanf(const char *restrict s, const char *restrict fmt, va_list ap)
{ {
FILE f = { FILE f = {
.buf = (void *)s, .cookie = (void *)s, .buf = (void *)s, .cookie = (void *)s,
.read = do_read, .lock = -1 .read = do_read, .lock_owner = STDIO_SINGLETHREADED,
}; };
return vfscanf(&f, fmt, ap); return vfscanf(&f, fmt, ap);
} }
...@@ -39,7 +39,7 @@ int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_lis ...@@ -39,7 +39,7 @@ int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict fmt, va_lis
f.write = sw_write; f.write = sw_write;
f.buf_size = sizeof buf; f.buf_size = sizeof buf;
f.buf = buf; f.buf = buf;
f.lock = -1; f.lock_owner = STDIO_SINGLETHREADED;
f.cookie = &c; f.cookie = &c;
if (!n) { if (!n) {
return -1; return -1;
......
...@@ -30,7 +30,7 @@ int vswscanf(const wchar_t *restrict s, const wchar_t *restrict fmt, va_list ap) ...@@ -30,7 +30,7 @@ int vswscanf(const wchar_t *restrict s, const wchar_t *restrict fmt, va_list ap)
FILE f = { FILE f = {
.buf = buf, .buf_size = sizeof buf, .buf = buf, .buf_size = sizeof buf,
.cookie = (void *)s, .cookie = (void *)s,
.read = wstring_read, .lock = -1 .read = wstring_read, .lock_owner = STDIO_SINGLETHREADED,
}; };
return vfwscanf(&f, fmt, ap); return vfwscanf(&f, fmt, ap);
} }
...@@ -7,7 +7,7 @@ static long double strtox(const char *s, char **p, int prec) ...@@ -7,7 +7,7 @@ static long double strtox(const char *s, char **p, int prec)
{ {
FILE f = { FILE f = {
.buf = (void *)s, .rpos = (void *)s, .buf = (void *)s, .rpos = (void *)s,
.rend = (void *)-1, .lock = -1 .rend = (void *)-1, .lock_owner = STDIO_SINGLETHREADED,
}; };
shlim(&f, 0); shlim(&f, 0);
long double y = __floatscan(&f, prec, 1); long double y = __floatscan(&f, prec, 1);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment