diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/stdio/fgetc.c | 10 | ||||
-rw-r--r-- | src/stdio/getc.c | 10 | ||||
-rw-r--r-- | src/stdio/getc.h | 22 | ||||
-rw-r--r-- | src/stdio/getchar.c | 3 |
4 files changed, 30 insertions, 15 deletions
diff --git a/src/stdio/fgetc.c b/src/stdio/fgetc.c index e1224164..2578afcc 100644 --- a/src/stdio/fgetc.c +++ b/src/stdio/fgetc.c @@ -1,11 +1,7 @@ -#include "stdio_impl.h" +#include <stdio.h> +#include "getc.h" int fgetc(FILE *f) { - int c; - if (f->lock < 0 || !__lockfile(f)) - return getc_unlocked(f); - c = getc_unlocked(f); - __unlockfile(f); - return c; + return do_getc(f); } diff --git a/src/stdio/getc.c b/src/stdio/getc.c index b3f351d1..8409fc23 100644 --- a/src/stdio/getc.c +++ b/src/stdio/getc.c @@ -1,13 +1,9 @@ -#include "stdio_impl.h" +#include <stdio.h> +#include "getc.h" int getc(FILE *f) { - int c; - if (f->lock < 0 || !__lockfile(f)) - return getc_unlocked(f); - c = getc_unlocked(f); - __unlockfile(f); - return c; + return do_getc(f); } weak_alias(getc, _IO_getc); diff --git a/src/stdio/getc.h b/src/stdio/getc.h new file mode 100644 index 00000000..0657ab6f --- /dev/null +++ b/src/stdio/getc.h @@ -0,0 +1,22 @@ +#include "stdio_impl.h" +#include "pthread_impl.h" + +#ifdef __GNUC__ +__attribute__((__noinline__)) +#endif +static int locking_getc(FILE *f, int tid) +{ + if (a_cas(&f->lock, 0, tid)) __lockfile(f); + int c = getc_unlocked(f); + if (a_swap(&f->lock, 0) & MAYBE_WAITERS) + __wake(&f->lock, 1, 1); + return c; +} + +static inline int do_getc(FILE *f) +{ + int tid, l = f->lock; + if (l < 0 || (l & ~MAYBE_WAITERS) == (tid=__pthread_self()->tid)) + return getc_unlocked(f); + return locking_getc(f, tid); +} diff --git a/src/stdio/getchar.c b/src/stdio/getchar.c index c1012658..df395ca9 100644 --- a/src/stdio/getchar.c +++ b/src/stdio/getchar.c @@ -1,6 +1,7 @@ #include <stdio.h> +#include "getc.h" int getchar(void) { - return fgetc(stdin); + return do_getc(stdin); } |