@@ -155,5 +155,8 @@ libc {
GLIBC_PRIVATE {
# Used by NPTL and librt
__libc_fatal;
+
+ # Used by NPTL
+ _IO_enable_locks;
}
}
@@ -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);
@@ -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);
@@ -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);
@@ -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;
@@ -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);
@@ -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);
@@ -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. */
@@ -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);
@@ -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,
@@ -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. */
@@ -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);
@@ -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;
@@ -25,6 +25,7 @@
void
__flockfile (FILE *stream)
{
+ stream->_flags2 |= _IO_FLAGS2_NEED_LOCK;
_IO_lock_lock (*stream->_lock);
}
strong_alias (__flockfile, _IO_flockfile)