[2/3] Remove _IO_MTSAFE_IO from public headers.

Message ID 20170301140212.14354-3-zackw@panix.com
State Superseded
Headers

Commit Message

Zack Weinberg March 1, 2017, 2:02 p.m. UTC
  _IO_MTSAFE_IO controls whether stdio is *built* with support for
multithreading.  In the distant past it might also have worked as a
feature selection macro, allowing library *users* to select
thread-safe or lock-free stdio at application build time, I haven't
done the archaeology.  Nowadays, defining _IO_MTSAFE_IO while using
the installed headers, or in _ISOMAC mode, will cause libio.h to throw
syntax errors.

This patch removes _IO_MTSAFE_IO from the public headers
(specifically, from libio/libio.h).  The internal-use-only macros
whose definitions were conditional on _IO_MTSAFE_IO are moved to
include/libio.h.  The other thing it controls is whether libio.h
defines _IO_lock_t itself or expects stdio-lock.h to have done it, and
we do still need a inter-header communication macro for that, because
stdio-lock.h can only define _IO_lock_t as a typedef.  I've invented
_IO_lock_t_defined, which is defined by both versions of stdio-lock.h.

I suspect that this entire mechanism is vestigial, and that glibc
won't build anymore if you *don't* define _IO_MTSAFE_IO, but that's
another patchset.  The bulk of libio.h is internal-use-only stuff that
no longer makes sense to expose (libstdc++ gave up on making a FILE
the same object as a C++ filebuf *decades* ago) but that, too, is
another patchset.

	* libio/libio.h: Condition dummy definition of _IO_lock_t on
	_IO_lock_t_defined, not _IO_MTSAFE_IO.	Move macro definitions
	conditioned on _IO_MTSAFE_IO ...
	* include/libio.h: ... here.

	* sysdeps/generic/stdio-lock.h, sysdeps/nptl/stdio-lock.h:
	Define _IO_lock_t_defined after defining _IO_lock_t.
---
 include/libio.h              | 31 +++++++++++++++++++++----------
 libio/libio.h                | 22 +++-------------------
 sysdeps/generic/stdio-lock.h |  1 +
 sysdeps/nptl/stdio-lock.h    |  1 +
 4 files changed, 26 insertions(+), 29 deletions(-)
  

Comments

Florian Weimer March 1, 2017, 2:09 p.m. UTC | #1
On 03/01/2017 03:02 PM, Zack Weinberg wrote:
> I suspect that this entire mechanism is vestigial, and that glibc
> won't build anymore if you *don't* define _IO_MTSAFE_IO, but that's
> another patchset.  The bulk of libio.h is internal-use-only stuff that
> no longer makes sense to expose (libstdc++ gave up on making a FILE
> the same object as a C++ filebuf *decades* ago) but that, too, is
> another patchset.

I tried to rip out _IO_MTSAFE_IO before, but it turns out that it still 
has an effect:

   <https://sourceware.org/ml/libc-alpha/2016-04/msg00748.html>

Are you sure your changes are actually a no-op?

Thanks,
Florian
  
Zack Weinberg March 1, 2017, 5:14 p.m. UTC | #2
On Wed, Mar 1, 2017 at 9:09 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 03/01/2017 03:02 PM, Zack Weinberg wrote:
>> I suspect that this entire mechanism is vestigial, and that glibc
>> won't build anymore if you *don't* define _IO_MTSAFE_IO, but that's
>> another patchset.  The bulk of libio.h is internal-use-only stuff that
>> no longer makes sense to expose (libstdc++ gave up on making a FILE
>> the same object as a C++ filebuf *decades* ago) but that, too, is
>> another patchset.
>
> I tried to rip out _IO_MTSAFE_IO before, but it turns out that it still has
> an effect:
>
>   <https://sourceware.org/ml/libc-alpha/2016-04/msg00748.html>
>
> Are you sure your changes are actually a no-op?

This limited change should indeed be a no-op.  Specifically, code
compiled as part of libc (in the presence of the wrapper headers, and
in the absence of _ISOMAC) should have _IO_MTSAFE_IO defined under
exactly the same conditions as before, and should get the same
definitions of _IO_lock_t, _IO_peekc, _IO_flockfile, _IO_funlockfile,
_IO_cleanup_region_start, and _IO_cleanup_region_end as it did before.
I can do a built-objects comparison to make sure - I was already going
to do that for the main change, so it's not much extra work.

There may well be a preexisting bug where code inside libc, but
outside the stdio implementation, doesn't do all the locking that it
ought to, but my patch should not change that.

(The subtlety that you may have missed back then is
_IO_lock_inexpensive; when this is defined (by stdio-lock.h - it
appears that all supported configurations do define it), _IO_flockfile
and _IO_funlockfile expand to inline code.)

zw
  

Patch

diff --git a/include/libio.h b/include/libio.h
index 97fc5b548b..53321b669d 100644
--- a/include/libio.h
+++ b/include/libio.h
@@ -21,16 +21,27 @@  libc_hidden_proto (_IO_sgetn)
 libc_hidden_proto (_IO_vfprintf)
 libc_hidden_proto (_IO_vfscanf)
 
-#if defined _IO_MTSAFE_IO && _IO_lock_inexpensive
-# undef _IO_flockfile
-# define _IO_flockfile(_fp) \
-  if (((_fp)->_flags & _IO_USER_LOCK) == 0)				      \
-     _IO_lock_lock (*(_fp)->_lock)
-# undef _IO_funlockfile
-# define _IO_funlockfile(_fp) \
-  if (((_fp)->_flags & _IO_USER_LOCK) == 0)				      \
-    _IO_lock_unlock (*(_fp)->_lock)
-#endif
+#ifdef _IO_MTSAFE_IO
+# define _IO_peekc(_fp) _IO_peekc_locked (_fp)
+# if _IO_lock_inexpensive
+#  define _IO_flockfile(_fp) \
+  if (((_fp)->_flags & _IO_USER_LOCK) == 0) _IO_lock_lock (*(_fp)->_lock)
+#  define _IO_funlockfile(_fp) \
+  if (((_fp)->_flags & _IO_USER_LOCK) == 0) _IO_lock_unlock (*(_fp)->_lock)
+# else
+#  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)
+# endif
+#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 */
 
 #endif
 #endif
diff --git a/libio/libio.h b/libio/libio.h
index 2241c1471d..4fa9d74727 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -143,10 +143,9 @@ 
 
 struct _IO_jump_t;  struct _IO_FILE;
 
-/* Handle lock.  */
-#ifdef _IO_MTSAFE_IO
-/* _IO_lock_t defined in internal headers during the glibc build.  */
-#else
+/* During the build of glibc itself, _IO_lock_t will already have been
+   defined by internal headers.  */
+#ifndef _IO_lock_t_defined
 typedef void _IO_lock_t;
 #endif
 
@@ -441,21 +440,6 @@  extern void _IO_flockfile (_IO_FILE *) __THROW;
 extern void _IO_funlockfile (_IO_FILE *) __THROW;
 extern int _IO_ftrylockfile (_IO_FILE *) __THROW;
 
-#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 */
-
 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/sysdeps/generic/stdio-lock.h b/sysdeps/generic/stdio-lock.h
index 532bb5f23f..763c7d465a 100644
--- a/sysdeps/generic/stdio-lock.h
+++ b/sysdeps/generic/stdio-lock.h
@@ -22,6 +22,7 @@ 
 #include <libc-lock.h>
 
 __libc_lock_define_recursive (typedef, _IO_lock_t)
+#define _IO_lock_t_defined 1
 
 /* We need recursive (counting) mutexes.  */
 #ifdef _LIBC_LOCK_RECURSIVE_INITIALIZER
diff --git a/sysdeps/nptl/stdio-lock.h b/sysdeps/nptl/stdio-lock.h
index 35d6ce0a29..df749062ea 100644
--- a/sysdeps/nptl/stdio-lock.h
+++ b/sysdeps/nptl/stdio-lock.h
@@ -27,6 +27,7 @@ 
 #define _IO_lock_inexpensive	1
 
 typedef struct { int lock; int cnt; void *owner; } _IO_lock_t;
+#define _IO_lock_t_defined 1
 
 #define _IO_lock_initializer { LLL_LOCK_INITIALIZER, 0, NULL }