Mark Kettenis <mark.kette...@xs4all.nl> writes:

> I'd say that would be overkill.  The use of recursive mutexes is
> somewhat controversal, which is almost certainly why they weren't part
> of POSIX initially.  But they were part of Unix98 and present as an
> XSI extension in POSIX until they were moved to base in 2008.

I would argue that recursive mutexes aren't 'controversial', they're
just a bad idea used by lazy programmers. However, given that the
existign code uses what is effectively a recursive mutex, converting to
threaded input *and* eliminating the mutex recursion at the same time
seems like a worse idea.

> So unless there is real evidence that there are still supported
> systems out there that don't provide PTHREAD_MUTEX_RECURSIVE, I'd stop
> at 1) and disable the input thread support on systems that don't
> provide it.  Adding fallbacks just increases the maintenance burden.

Linux doesn't appear to provide PTHREAD_RECURSIVE_MUTEX_INITIALIZER,
which seems rather odd to me.

> Must admit that I have an agenda here.  I'd like to avoid 3) as this
> might encourage people to use __thread in other places in the Xorg
> codebase.

Mesa already uses __thread extensively, and it looks to provide
significant performance benefits. I did some simple benchmarking today
with PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP vs __thread, and my test
program ran twice as fast using __thread compared with recursive mutexes
(see attached).

So, what I suggest is that we use recursive mutexes where supported,
falling back to __thread/__declspec(thread). Two paths seems like a fine
plan to me, offering portability to a wider set of systems than either
one alone, while preferring the POSIX  standard where supported.

#define _GNU_SOURCE	1
#include <pthread.h>

#define LOOPS		10000000
#define DEPTH		10
#define THREADS		10
#define RECURSIVE	0

#if RECURSIVE
static pthread_mutex_t	mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

static inline void lock() {
	pthread_mutex_lock(&mutex);
}

static inline void unlock() {
	pthread_mutex_unlock(&mutex);
}

#else

static pthread_mutex_t	mutex = PTHREAD_MUTEX_INITIALIZER;
static __thread int count;

static inline void lock() {
	if (count++ == 0)
		pthread_mutex_lock(&mutex);
}

static inline void unlock() {
	if (--count == 0)
		pthread_mutex_unlock(&mutex);
}
#endif

void idle(void);

void idle(void) {
}

static inline void acquire(int depth) {
	while (depth--) {
		lock();
		idle();
	}
}

static inline void release(int depth) {
	while (depth--) {
		idle();
		unlock();
	}
}

static void *doit(void *arg) {
	int i;

	for (i = 0; i < LOOPS; i++) {
		acquire(DEPTH);
		release(DEPTH);
	}
}

int
main (int argc, char **argv)
{
	int	t;
	pthread_t	threads[THREADS];

	for (t = 0; t < THREADS; t++)
		pthread_create(&threads[t], NULL, doit, NULL);

	for (t = 0; t < THREADS; t++)
		pthread_join(threads[t], NULL);
}
From 55f483cff8d660e444a65026e57f793c06a66ce3 Mon Sep 17 00:00:00 2001
From: Keith Packard <kei...@keithp.com>
Date: Thu, 10 Dec 2015 11:36:34 -0800
Subject: [PATCH xserver 05/22] Disable input thread code with
 --disable-input-thread. RECURSIVE_MUTEX support

This is a pair of changes to the threaded input code which should be
merged with that patch; I'm publishing it separately for review before
doing that.

The first change is to respect the --disable-input-thread
configuration option and disable all of the threaded input code in
that case. What remains are just stubs that get input drivers to work
in this situation without changing the API or ABI.

The second is to add ax_tls.m4 which detects
PTHREAD_RECURSIVE_MUTEX_INITIALIZER and either __thread or
__declspec(thread) support in the system and to use that to figure out
how to get recursive mutex support in the server. We prefer
PTHREAD_RECURSIVE_MUTEX_SUPPORt where available, falling back to
__thread/__declspec(thread) support if necessary.

Signed-off-by: Keith Packard <kei...@keithp.com>

fixup for thread variables
---
 configure.ac            | 21 ++++++++++---
 hw/xfree86/sdksyms.sh   |  4 ---
 include/dix-config.h.in |  9 ++++++
 include/input.h         | 23 ++------------
 m4/ax_tls.m4            | 78 +++++++++++++++++++++++++++++++++++++++++++++++
 os/inputthread.c        | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 187 insertions(+), 28 deletions(-)
 create mode 100644 m4/ax_tls.m4

diff --git a/configure.ac b/configure.ac
index bc15581..6f04062 100644
--- a/configure.ac
+++ b/configure.ac
@@ -821,13 +821,25 @@ SDK_REQUIRED_MODULES="$XPROTO $RANDRPROTO $RENDERPROTO $XEXTPROTO $INPUTPROTO $K
 # Make SDK_REQUIRED_MODULES available for inclusion in xorg-server.pc
 AC_SUBST(SDK_REQUIRED_MODULES)
 
-# input thread setup
-case $host_os in
-linux*)
+AC_CHECK_DECL([PTHREAD_RECURSIVE_MUTEX_INITIALIZER], [HAVE_RECURSIVE_MUTEX=yes], [HAVE_RECURSIVE_MUTEX=no], [[#include <pthread.h>]])
+
+AX_TLS()
+
+THREAD_DEFAULT=no
+
+case x$HAVE_RECURSIVE_MUTEX in
+xyes)
+	AC_DEFINE(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER, 1, [Have PTHREAD_RECURSIVE_MUTEX_INITIALIZER])
 	THREAD_DEFAULT=yes ;;
 *)
-	THREAD_DEFAULT=no ;;
+	case "x$ac_cv_tls" in
+	xnone)
+		;;
+	*)
+		THREAD_DEFAULT=yes ;;
+	esac
 esac
+
 AC_ARG_ENABLE(input-thread, AS_HELP_STRING([--enable-input-thread],
 	     [Enable input threads]),
 	     [INPUTTHREAD=$enableval], [INPUTTHREAD=$THREAD_DEFAULT])
@@ -848,6 +860,7 @@ if test "x$INPUTTHREAD" = "xyes" ; then
     esac
     SYS_LIBS="$SYS_LIBS $THREAD_LIB"
     CFLAGS="$CFLAGS $THREAD_CFLAGS"
+    AC_DEFINE(INPUTTHREAD, 1, [Use a separate input thread])
 fi
 
 REQUIRED_MODULES="$FIXESPROTO $DAMAGEPROTO $XCMISCPROTO $XTRANS $BIGREQSPROTO $SDK_REQUIRED_MODULES"
diff --git a/hw/xfree86/sdksyms.sh b/hw/xfree86/sdksyms.sh
index fb2eaa1..5391b72 100755
--- a/hw/xfree86/sdksyms.sh
+++ b/hw/xfree86/sdksyms.sh
@@ -344,10 +344,6 @@ BEGIN {
            n = 1;
         }
 
-	if ($n ~ /__thread/) {
-	   next;
-	}
-
 	# skip attribute, if any
 	while ($n ~ /^(__attribute__|__global)/ ||
 	    # skip modifiers, if any
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index 940d2b7..7d1774f 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -521,4 +521,13 @@
 /* Have setitimer support */
 #undef HAVE_SETITIMER
 
+/* Have recursive mutexes */
+#undef HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER
+
+/* Use this define for thread-specific variables */
+#undef TLS
+
+/* Use input thread */
+#undef INPUTTHREAD
+
 #endif /* _DIX_CONFIG_H_ */
diff --git a/include/input.h b/include/input.h
index 01ea4d9..afd066f 100644
--- a/include/input.h
+++ b/include/input.h
@@ -713,26 +713,9 @@ extern _X_HIDDEN void input_constrain_cursor(DeviceIntPtr pDev, ScreenPtr screen
                                              int *out_x, int *out_y,
                                              int *nevents, InternalEvent* events);
 
-extern _X_EXPORT pthread_mutex_t input_mutex;
-extern _X_EXPORT __thread int input_mutex_count;
-
-static inline void input_lock(void) {
-    if (input_mutex_count++ == 0)
-        pthread_mutex_lock(&input_mutex);
-}
-
-static inline void input_unlock(void) {
-    if (--input_mutex_count == 0)
-        pthread_mutex_unlock(&input_mutex);
-    assert(input_mutex_count >= 0);
-}
-
-static inline void input_force_unlock(void) {
-    if (input_mutex_count > 0) {
-        input_mutex_count = 0;
-        pthread_mutex_unlock(&input_mutex);
-    }
-}
+extern _X_EXPORT void input_lock(void);
+extern _X_EXPORT void input_unlock(void);
+extern _X_EXPORT void input_force_unlock(void);
 
 extern void InputThreadPreInit(void);
 extern void InputThreadInit(void);
diff --git a/m4/ax_tls.m4 b/m4/ax_tls.m4
new file mode 100644
index 0000000..41620a7
--- /dev/null
+++ b/m4/ax_tls.m4
@@ -0,0 +1,78 @@
+# ===========================================================================
+#                 http://autoconf-archive.cryp.to/ax_tls.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_TLS
+#
+# DESCRIPTION
+#
+#   Provides a test for the compiler support of thread local storage (TLS)
+#   extensions. Defines TLS if it is found. Currently only knows about GCC
+#   and MSVC. I think SunPro uses the same as GCC, and Borland apparently
+#   supports either.
+#
+# LAST MODIFICATION
+#
+#   2008-04-12
+#
+# COPYLEFT
+#
+#   Copyright (c) 2008 Alan Woodland <aj...@aber.ac.uk>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Macro Archive. When you make and
+#   distribute a modified version of the Autoconf Macro, you may extend this
+#   special exception to the GPL to apply to your modified version as well.
+
+AC_DEFUN([AX_TLS], [
+  AC_MSG_CHECKING(for thread local storage (TLS) class)
+  AC_CACHE_VAL(ac_cv_tls, [
+    ax_tls_keywords="__thread __declspec(thread) none"
+    for ax_tls_keyword in $ax_tls_keywords; do
+       case $ax_tls_keyword in
+          none) ac_cv_tls=none ; break ;;
+	  *)
+             AC_TRY_COMPILE(
+                [#include <stdlib.h>
+                 static void
+                 foo(void) {
+                 static ] $ax_tls_keyword [ int bar;
+                 exit(1);
+                 }],
+                 [],
+                 [ac_cv_tls=$ax_tls_keyword ; break],
+                 ac_cv_tls=none
+             )
+	  esac
+    done
+])
+
+  if test "$ac_cv_tls" != "none"; then
+    dnl AC_DEFINE([TLS], [], [If the compiler supports a TLS storage class define it to that here])
+    AC_DEFINE_UNQUOTED([TLS], $ac_cv_tls, [If the compiler supports a TLS storage class define it to that here])
+  fi
+  AC_MSG_RESULT($ac_cv_tls)
+])
diff --git a/os/inputthread.c b/os/inputthread.c
index 7c87e87..a80b8b6 100644
--- a/os/inputthread.c
+++ b/os/inputthread.c
@@ -40,6 +40,8 @@
 #include "opaque.h"
 #include "osdep.h"
 
+#if INPUTTHREAD
+
 Bool InputThreadEnable = TRUE;
 
 /**
@@ -377,3 +379,81 @@ InputThreadFini(void)
     free(inputThreadInfo);
     inputThreadInfo = NULL;
 }
+
+#if HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER
+
+static pthread_mutex_t input_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
+static int input_mutex_count;
+
+void input_lock(void) {
+    pthread_mutex_lock(&input_mutex);
+    ++input_mutex_count;
+}
+
+void input_unlock(void) {
+    --input_mutex_count;
+    pthread_mutex_unlock(&input_mutex);
+}
+
+void input_force_unlock(void) {
+    if (pthread_mutex_trylock(&input_mutex) == 0) {
+        /* unlock +1 times for the trylock */
+        while (input_mutex_count-- >= 0)
+            pthread_mutex_unlock(&input_mutex);
+    }
+}
+
+#else
+
+#ifdef TLS
+
+static __thread int input_mutex_count;
+static pthread_mutex_t input_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void input_lock(void) {
+    if (input_mutex_count++ == 0)
+        pthread_mutex_lock(&input_mutex);
+}
+
+void input_unlock(void) {
+    if (--input_mutex_count == 0)
+        pthread_mutex_unlock(&input_mutex);
+}
+
+void input_force_unlock(void) {
+    if (input_mutex_count) {
+        input_mutex_count = 0;
+        pthread_mutex_unlock(&input_mutex);
+    }
+}
+
+#endif /* TLS */
+
+#endif /* HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER */
+
+#else /* INPUTTHREAD */
+
+Bool InputThreadEnable = FALSE;
+
+void input_lock(void) {}
+void input_unlock(void) {}
+void input_force_unlock(void) {}
+
+void InputThreadPreInit(void) {}
+void InputThreadInit(void) {}
+void InputThreadFini(void) {}
+
+int InputThreadRegisterDev(int fd,
+                           NotifyFdProcPtr readInputProc,
+                           void *readInputArgs)
+{
+    return SetNotifyFd(fd, readInputProc, X_NOTIFY_READ, readInputArgs);
+}
+
+extern int InputThreadUnregisterDev(int fd)
+{
+    RemoveNotifyFd(fd);
+    return 1;
+}
+
+#endif
-- 
2.6.4


-- 
-keith

Attachment: signature.asc
Description: PGP signature

_______________________________________________
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

Reply via email to