It's sometimes impossible to know in advance whether an X client is using Xlib from multiple threads or not. For example, there could be some generic X client that acts as a plugin container. Plugins could be loaded to the container at runtime, but the container doesn't know whether the plugins are using Xlib from a separate thread or not.
This change makes it possible to guard a system against a missing XInitThreads call in X clients. One might argue that this is a client problem and that all X clients should call XInitThreads if it's possible that they could use Xlib from multiple threads. However, experience has shown that it's just too easy for developers to overlook the need for this call. Enabling thread safety by default causes a performance regression, because even single threaded applications would start to lock data structures. However, the performance regression is only noticeable in a theoretical worst case situation. In realistic use cases the overhead from unnecessary locking can't be seen. Relative x11perf results showing the amount of regression for worst case and some common operations are shown below. enabled disabled Operation ------- -------- --------- 1.00 1.00 Copy 10x10 from window to window 1.00 1.00 Copy 500x500 from window to window 1.00 2.68 X protocol NoOperation Signed-off-by: Rami Ylimäki <rami.ylim...@vincit.fi> --- configure.ac | 36 ++++++++++++++++++++++++++++++++++++ src/locking.c | 10 ++++++++++ 2 files changed, 46 insertions(+), 0 deletions(-) diff --git a/configure.ac b/configure.ac index 40d032d..27ed595 100644 --- a/configure.ac +++ b/configure.ac @@ -270,6 +270,37 @@ AC_ARG_ENABLE(xthreads, [Disable Xlib support for Multithreading]), [xthreads=$enableval],[xthreads=yes]) +dnl Check if the user wants XInitThreads to be called by default on +dnl library initialization. +AC_ARG_ENABLE( + init_xthreads, + AC_HELP_STRING( + [--enable-init-xthreads], + [Call XInitThreads on library initialization]), + [init_xthreads=$enableval], + [init_xthreads=no]) + +dnl Check if XInitThreads can be called by default on library +dnl initialization. The following conditions must be true for that. +dnl +dnl - Option --enable-xthreads is given. +dnl - Option --enable-init-xthreads is given. +dnl - Compiler is GCC. +dnl - GCC supports library contructors. +if test "x$xthreads" = xyes && test "x$init_xthreads" = xyes && test "x$GCC" = xyes ; then + dnl Set warnings as errors so that GCC fails if the attribute is + dnl not supported. + old_CFLAGS="$CFLAGS" + CFLAGS="-Werror" + dnl Check if GCC recognizes constructor attribute. + AC_COMPILE_IFELSE( + [ void __attribute__((constructor)) test(void) {}; ], + init_xthreads=yes, + init_xthreads=no) + dnl Restore flags. + CFLAGS="$old_CFLAGS" +fi + AC_CHECK_LIB(c, getpwuid_r, [mtsafeapi="yes"], [mtsafeapi="no"]) case x$xthreads in @@ -279,6 +310,10 @@ xyes) then AC_DEFINE(XUSE_MTSAFE_API,1,[Whether libX11 needs to use MT safe API's]) fi + if test x$init_xthreads = xyes + then + AC_DEFINE(INIT_XTHREADS,1,[Whether XInitThreads is called on library initialization]) + fi ;; *) ;; @@ -480,6 +515,7 @@ echo " Loadable xcursor library support: "$XLIB_LOADABLE_XCURSOR echo " Threading support: "$xthreads echo " Use Threads safe API: "$mtsafeapi echo " Threads stubs in libX11: "$thrstubs +echo " Threads initialized by default: "$init_xthreads echo " XCMS: "$XCMS echo " Internationalization support: "$XLOCALE echo " XF86BigFont support: "$XF86BIGFONT diff --git a/src/locking.c b/src/locking.c index 4f9a40f..7673a20 100644 --- a/src/locking.c +++ b/src/locking.c @@ -615,6 +615,16 @@ Status XInitThreads(void) return 1; } +#ifdef INIT_XTHREADS + +/** Initialize threads by default when Xlib is loaded. */ +static void __attribute__((constructor)) XInitLib(void) +{ + if (!XInitThreads()) + exit(1); +} + +#endif /* INIT_XTHREADS*/ #else /* XTHREADS */ Status XInitThreads(void) { -- 1.6.3.3 _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel