This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
_IO_MTSAFE_IO
- From: Florian Weimer <fweimer at redhat dot com>
- To: GNU C Library <libc-alpha at sourceware dot org>
- Date: Fri, 29 Apr 2016 10:09:11 +0200
- Subject: _IO_MTSAFE_IO
- Authentication-results: sourceware.org; auth=none
I looked at further preprocessor conditionals to remove and came across
_IO_MTSAFE_IO.
The odd thing here is that we compile libio and related parts with
_IO_MTSAFE_IO, but not the rest of glibc. The public <libio.h> header
contains a _IO_MTSAFE_IO conditional, too:
#ifdef _IO_MTSAFE_IO
# define _IO_peekc(_fp) _IO_peekc_locked (_fp)
# define _IO_flockfile(_fp) \
if (((_fp)->_flags & _IO_USER_LOCK) == 0) _IO_flockfile (_fp)
# define _IO_funlockfile(_fp) \
if (((_fp)->_flags & _IO_USER_LOCK) == 0) _IO_funlockfile (_fp)
#else
# define _IO_peekc(_fp) _IO_peekc_unlocked (_fp)
# define _IO_flockfile(_fp) /**/
# define _IO_funlockfile(_fp) /**/
# define _IO_ftrylockfile(_fp) /**/
# define _IO_cleanup_region_start(_fct, _fp) /**/
# define _IO_cleanup_region_end(_Doit) /**/
#endif /* !_IO_MTSAFE_IO */
Applications which use these macros get the !_IO_MTSAFE_IO variants,
e.g. _IO_flockfile is completely elided.
Whether applications can use these macros is somewhat debatable, but as
I said, it happens within glibc as well. There are repeated occurrences
of this in posix/getopt.c, for example:
_IO_flockfile (stderr);
int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
((_IO_FILE *) stderr)->_flags2
|= _IO_FLAGS2_NOTCANCEL;
__fxprintf (NULL, "%s", buf);
((_IO_FILE *) stderr)->_flags2 = old_flags2;
_IO_funlockfile (stderr);
Both _IO_flockfile and _IO_funlockfile are expanded to nothing, so the
flag manipulation constitutes a data race.
__malloc_stats in malloc/malloc.c is similarly afflicted.
A straight removal of _IO_MTSAFE_IO (treating it as always defined)
shows that previously, nothing in glibc actually called the
_IO_flockfile function. Apparently, the macro expansion provided in
<include/libio.h> is always used in those cases where we compile with
_IO_MTSAFE_IO defined.
Curiously, _IO_flockfile and _IO_funlockfile are only defined in
libpthread.so, not in libc.so. But these implementations are slightly
incompatible with the macro definitions in <include/libio.h> because
they do not check _IO_USER_LOCK. (libpthread also provides the public
names flockfile and funlockfile.)
How should we fix this? Is the _IO_USER_LOCK check important?
I'm not sure if inlining _IO_flockfile is beneficial. It is a lot of
code now: The _IO_USER_LOCK, the recursive mutex wrapper, and the
low-level lock implementation (which itself contains a
multiple-threads-check).
Florian