diff options
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | libio/Versions | 3 | ||||
-rw-r--r-- | libio/feof.c | 2 | ||||
-rw-r--r-- | libio/ferror.c | 2 | ||||
-rw-r--r-- | libio/fputc.c | 2 | ||||
-rw-r--r-- | libio/genops.c | 28 | ||||
-rw-r--r-- | libio/getc.c | 2 | ||||
-rw-r--r-- | libio/getchar.c | 2 | ||||
-rw-r--r-- | libio/iofopncook.c | 2 | ||||
-rw-r--r-- | libio/ioungetc.c | 2 | ||||
-rw-r--r-- | libio/libio.h | 4 | ||||
-rw-r--r-- | libio/libioP.h | 2 | ||||
-rw-r--r-- | libio/putc.c | 2 | ||||
-rw-r--r-- | nptl/pthread_create.c | 4 | ||||
-rw-r--r-- | sysdeps/pthread/flockfile.c | 1 |
15 files changed, 76 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog index 314c69f664..7f67b658f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2017-07-04 Szabolcs Nagy <szabolcs.nagy@arm.com> + + * libio/libio.h (_IO_FLAGS2_NEED_LOCK, _IO_need_lock): Define. + * libio/libioP.h (_IO_enable_locks): Declare. + * libio/Versions (_IO_enable_locks): New symbol. + * libio/genops.c (_IO_enable_locks): Define. + (_IO_old_init): Initialize flags2. + * libio/feof.c.c (_IO_feof): Avoid locking when not needed. + * libio/ferror.c (_IO_ferror): Likewise. + * libio/fputc.c (fputc): Likewise. + * libio/putc.c (_IO_putc): Likewise. + * libio/getc.c (_IO_getc): Likewise. + * libio/getchar.c (getchar): Likewise. + * libio/ioungetc.c (_IO_ungetc): Likewise. + * nptl/pthread_create.c (__pthread_create_2_1): Enable stdio locks. + * libio/iofopncook.c (_IO_fopencookie): Enable locking for the file. + * sysdeps/pthread/flockfile.c (__flockfile): Likewise. + 2017-07-04 Florian Weimer <fweimer@redhat.com> [BZ #21542] diff --git a/libio/Versions b/libio/Versions index 2a1d6e6c85..77123347e3 100644 --- a/libio/Versions +++ b/libio/Versions @@ -155,5 +155,8 @@ libc { GLIBC_PRIVATE { # Used by NPTL and librt __libc_fatal; + + # Used by NPTL + _IO_enable_locks; } } diff --git a/libio/feof.c b/libio/feof.c index 9712a81e78..8890a5f51f 100644 --- a/libio/feof.c +++ b/libio/feof.c @@ -32,6 +32,8 @@ _IO_feof (_IO_FILE *fp) { int result; CHECK_FILE (fp, EOF); + if (!_IO_need_lock (fp)) + return _IO_feof_unlocked (fp); _IO_flockfile (fp); result = _IO_feof_unlocked (fp); _IO_funlockfile (fp); diff --git a/libio/ferror.c b/libio/ferror.c index 01e3bd8e2b..d10fcd9fff 100644 --- a/libio/ferror.c +++ b/libio/ferror.c @@ -32,6 +32,8 @@ _IO_ferror (_IO_FILE *fp) { int result; CHECK_FILE (fp, EOF); + if (!_IO_need_lock (fp)) + return _IO_ferror_unlocked (fp); _IO_flockfile (fp); result = _IO_ferror_unlocked (fp); _IO_funlockfile (fp); diff --git a/libio/fputc.c b/libio/fputc.c index a7cd682fe2..b72305c06f 100644 --- a/libio/fputc.c +++ b/libio/fputc.c @@ -32,6 +32,8 @@ fputc (int c, _IO_FILE *fp) { int result; CHECK_FILE (fp, EOF); + if (!_IO_need_lock (fp)) + return _IO_putc_unlocked (c, fp); _IO_acquire_lock (fp); result = _IO_putc_unlocked (c, fp); _IO_release_lock (fp); diff --git a/libio/genops.c b/libio/genops.c index a466cfa337..6ad7346cae 100644 --- a/libio/genops.c +++ b/libio/genops.c @@ -570,11 +570,39 @@ _IO_init (_IO_FILE *fp, int flags) _IO_init_internal (fp, flags); } +static int stdio_needs_locking; + +/* In a single-threaded process most stdio locks can be omitted. After + _IO_enable_locks is called, locks are not optimized away any more. + It must be first called while the process is still single-threaded. + + This lock optimization can be disabled on a per-file basis by setting + _IO_FLAGS2_NEED_LOCK, because a file can have user-defined callbacks + or can be locked with flockfile and then a thread may be created + between a lock and unlock, so omitting the lock is not valid. + + Here we have to make sure that the flag is set on all existing files + and files created later. */ +void +_IO_enable_locks (void) +{ + _IO_ITER i; + + if (stdio_needs_locking) + return; + stdio_needs_locking = 1; + for (i = _IO_iter_begin (); i != _IO_iter_end (); i = _IO_iter_next (i)) + _IO_iter_file (i)->_flags2 |= _IO_FLAGS2_NEED_LOCK; +} +libc_hidden_def (_IO_enable_locks) + void _IO_old_init (_IO_FILE *fp, int flags) { fp->_flags = _IO_MAGIC|flags; fp->_flags2 = 0; + if (stdio_needs_locking) + fp->_flags2 |= _IO_FLAGS2_NEED_LOCK; fp->_IO_buf_base = NULL; fp->_IO_buf_end = NULL; fp->_IO_read_base = NULL; diff --git a/libio/getc.c b/libio/getc.c index b58fd62308..fd66ef93cf 100644 --- a/libio/getc.c +++ b/libio/getc.c @@ -34,6 +34,8 @@ _IO_getc (FILE *fp) { int result; CHECK_FILE (fp, EOF); + if (!_IO_need_lock (fp)) + return _IO_getc_unlocked (fp); _IO_acquire_lock (fp); result = _IO_getc_unlocked (fp); _IO_release_lock (fp); diff --git a/libio/getchar.c b/libio/getchar.c index 5b41595d17..d79932114e 100644 --- a/libio/getchar.c +++ b/libio/getchar.c @@ -33,6 +33,8 @@ int getchar (void) { int result; + if (!_IO_need_lock (_IO_stdin)) + return _IO_getc_unlocked (_IO_stdin); _IO_acquire_lock (_IO_stdin); result = _IO_getc_unlocked (_IO_stdin); _IO_release_lock (_IO_stdin); diff --git a/libio/iofopncook.c b/libio/iofopncook.c index a08dfdaa42..982f464a68 100644 --- a/libio/iofopncook.c +++ b/libio/iofopncook.c @@ -172,6 +172,8 @@ _IO_cookie_init (struct _IO_cookie_file *cfile, int read_write, _IO_mask_flags (&cfile->__fp.file, read_write, _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); + cfile->__fp.file._flags2 |= _IO_FLAGS2_NEED_LOCK; + /* We use a negative number different from -1 for _fileno to mark that this special stream is not associated with a real file, but still has to be treated as such. */ diff --git a/libio/ioungetc.c b/libio/ioungetc.c index 951064fa12..917cad8abb 100644 --- a/libio/ioungetc.c +++ b/libio/ioungetc.c @@ -33,6 +33,8 @@ _IO_ungetc (int c, _IO_FILE *fp) CHECK_FILE (fp, EOF); if (c == EOF) return EOF; + if (!_IO_need_lock (fp)) + return _IO_sputbackc (fp, (unsigned char) c); _IO_acquire_lock (fp); result = _IO_sputbackc (fp, (unsigned char) c); _IO_release_lock (fp); diff --git a/libio/libio.h b/libio/libio.h index 518ffd8e44..14bcb92332 100644 --- a/libio/libio.h +++ b/libio/libio.h @@ -119,6 +119,7 @@ # define _IO_FLAGS2_SCANF_STD 16 # define _IO_FLAGS2_NOCLOSE 32 # define _IO_FLAGS2_CLOEXEC 64 +# define _IO_FLAGS2_NEED_LOCK 128 #endif /* These are "formatting flags" matching the iostream fmtflags enum values. */ @@ -451,6 +452,9 @@ extern int _IO_ftrylockfile (_IO_FILE *) __THROW; #define _IO_cleanup_region_end(_Doit) /**/ #endif +#define _IO_need_lock(_fp) \ + (((_fp)->_flags2 & _IO_FLAGS2_NEED_LOCK) != 0) + extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict, _IO_va_list, int *__restrict); extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict, diff --git a/libio/libioP.h b/libio/libioP.h index eb93418c8d..1832b44cc7 100644 --- a/libio/libioP.h +++ b/libio/libioP.h @@ -444,6 +444,8 @@ extern void _IO_list_unlock (void) __THROW; libc_hidden_proto (_IO_list_unlock) extern void _IO_list_resetlock (void) __THROW; libc_hidden_proto (_IO_list_resetlock) +extern void _IO_enable_locks (void) __THROW; +libc_hidden_proto (_IO_enable_locks) /* Default jumptable functions. */ diff --git a/libio/putc.c b/libio/putc.c index b591c5538b..6e1fdeef3a 100644 --- a/libio/putc.c +++ b/libio/putc.c @@ -25,6 +25,8 @@ _IO_putc (int c, _IO_FILE *fp) { int result; CHECK_FILE (fp, EOF); + if (!_IO_need_lock (fp)) + return _IO_putc_unlocked (c, fp); _IO_acquire_lock (fp); result = _IO_putc_unlocked (c, fp); _IO_release_lock (fp); diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c index 7a970ffc5b..2f8ada34d6 100644 --- a/nptl/pthread_create.c +++ b/nptl/pthread_create.c @@ -32,6 +32,7 @@ #include <exit-thread.h> #include <default-sched.h> #include <futex-internal.h> +#include "libioP.h" #include <shlib-compat.h> @@ -756,6 +757,9 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr, collect_default_sched (pd); } + if (__glibc_unlikely (__nptl_nthreads == 1)) + _IO_enable_locks (); + /* Pass the descriptor to the caller. */ *newthread = (pthread_t) pd; diff --git a/sysdeps/pthread/flockfile.c b/sysdeps/pthread/flockfile.c index 7fe8e99161..a8e6c28ed9 100644 --- a/sysdeps/pthread/flockfile.c +++ b/sysdeps/pthread/flockfile.c @@ -25,6 +25,7 @@ void __flockfile (FILE *stream) { + stream->_flags2 |= _IO_FLAGS2_NEED_LOCK; _IO_lock_lock (*stream->_lock); } strong_alias (__flockfile, _IO_flockfile) |