]> git.eshelyaron.com Git - emacs.git/commitdiff
Enable thread support in the MS-Windows build.
authorEli Zaretskii <eliz@gnu.org>
Fri, 30 Aug 2013 14:19:16 +0000 (17:19 +0300)
committerEli Zaretskii <eliz@gnu.org>
Fri, 30 Aug 2013 14:19:16 +0000 (17:19 +0300)
 src/systhread.h (w32thread_critsect, w32thread_cond_t, sys_mutex_t)
 (sys_cond_t, sys_thread_t) [WINDOWSNT]: New data types.
 src/systhread.c (sys_mutex_init, sys_mutex_lock, sys_mutex_unlock)
 (sys_mutex_destroy, sys_cond_init, sys_cond_wait)
 (sys_cond_signal, sys_cond_broadcast, sys_cond_destroy)
 (sys_thread_self, sys_thread_equal, w32_beginthread_wrapper)
 (sys_thread_create, sys_thread_yield) [WINDOWSNT]: New functions.

 configure.ac (THREADS_ENABLED): Enable threads for MinGW, even
 if pthreads is not available.

ChangeLog
configure.ac
src/ChangeLog
src/systhread.c
src/systhread.h

index 35dbeb6065c815631572b270377412561b6f256f..50a11186221543b0ea5708c6fc2527daf47a2a65 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-08-30  Eli Zaretskii  <eliz@gnu.org>
+
+       * configure.ac (THREADS_ENABLED): Enable threads for MinGW, even
+       if pthreads is not available.
+
 2013-08-22  Paul Eggert  <eggert@cs.ucla.edu>
 
        * configure.ac (EMACS_CONFIG_OPTIONS): Quote systematically (Bug#13274).
index 6b22cd0cfab3410122014f4069d44deb898114bb..f8938d07dbf99ab3708a911891707d6f1d09a4f1 100644 (file)
@@ -1956,6 +1956,11 @@ if test "$with_threads" = yes; then
       AC_DEFINE(THREADS_ENABLED, 1,
                 [Define to 1 if you want elisp thread support.])
       threads_enabled=yes
+   elif test "${opsys}" = "mingw32"; then
+      dnl MinGW can do native Windows threads even without pthreads
+      AC_DEFINE(THREADS_ENABLED, 1,
+                [Define to 1 if you want elisp thread support.])
+      threads_enabled=yes
    fi
 fi
 AC_MSG_RESULT([$threads_enabled])
index a0682bdfd48572d7b56a373374a98c480115463d..0aef16d34e3c463933e17359ca856bf1b2491e03 100644 (file)
@@ -1,3 +1,14 @@
+2013-08-30  Eli Zaretskii  <eliz@gnu.org>
+
+       * systhread.h (w32thread_critsect, w32thread_cond_t, sys_mutex_t)
+       (sys_cond_t, sys_thread_t) [WINDOWSNT]: New data types.
+
+       * systhread.c (sys_mutex_init, sys_mutex_lock, sys_mutex_unlock)
+       (sys_mutex_destroy, sys_cond_init, sys_cond_wait)
+       (sys_cond_signal, sys_cond_broadcast, sys_cond_destroy)
+       (sys_thread_self, sys_thread_equal, w32_beginthread_wrapper)
+       (sys_thread_create, sys_thread_yield) [WINDOWSNT]: New functions.
+
 2013-08-26  Eli Zaretskii  <eliz@gnu.org>
 
        * callproc.c: 
index 8c9ec438d9656fbc6851ec88ff42f4dcc6d7a130..b154abaecd6ba4b894179fa5fd42f0acba7fa0ff 100644 (file)
@@ -197,6 +197,155 @@ sys_thread_yield (void)
   sched_yield ();
 }
 
+#elif defined (WINDOWSNT)
+
+#include <windows.h>
+
+/* Cannot include <process.h> because of the local header by the same
+   name, sigh.  */
+uintptr_t _beginthread (void (__cdecl *)(void *), unsigned, void *);
+
+/* Mutexes are implemented as critical sections, because they are
+   faster than Windows mutex objects (implemented in userspace), and
+   satisfy the requirements, since we only needto synchronize within a
+   single process.  */
+void
+sys_mutex_init (sys_mutex_t *mutex)
+{
+  InitializeCriticalSection ((LPCRITICAL_SECTION)mutex);
+}
+
+void
+sys_mutex_lock (sys_mutex_t *mutex)
+{
+  /* FIXME: What happens if the owning thread exits without releasing
+     the mutex?  Accoding to MSDN, the result is undefined behavior.  */
+  EnterCriticalSection ((LPCRITICAL_SECTION)mutex);
+}
+
+void
+sys_mutex_unlock (sys_mutex_t *mutex)
+{
+  LeaveCriticalSection ((LPCRITICAL_SECTION)mutex);
+}
+
+void
+sys_mutex_destroy (sys_mutex_t *mutex)
+{
+  /* FIXME: According to MSDN, deleting a critical session that is
+     owned by a thread leaves the other threads waiting for the
+     critical session in an undefined state.  Posix docs seems to say
+     the same about pthread_mutex_destroy.  Do we need to protect
+     against such calamities?  */
+  DeleteCriticalSection ((LPCRITICAL_SECTION)mutex);
+}
+
+void
+sys_cond_init (sys_cond_t *cond)
+{
+  cond->events[CONDV_SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL);
+  cond->events[CONDV_BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL);
+}
+
+void
+sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex)
+{
+  /* FIXME: This implementation is simple, but incorrect.  Stay tuned
+     for better and more complicated implementation.  */
+  LeaveCriticalSection ((LPCRITICAL_SECTION)mutex);
+  WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
+  EnterCriticalSection ((LPCRITICAL_SECTION)mutex);
+}
+
+void
+sys_cond_signal (sys_cond_t *cond)
+{
+  PulseEvent (cond->events[CONDV_SIGNAL]);
+}
+
+void
+sys_cond_broadcast (sys_cond_t *cond)
+{
+  PulseEvent (cond->events[CONDV_BROADCAST]);
+}
+
+void
+sys_cond_destroy (sys_cond_t *cond)
+{
+  CloseHandle (cond->events[CONDV_SIGNAL]);
+  CloseHandle (cond->events[CONDV_BROADCAST]);
+}
+
+sys_thread_t
+sys_thread_self (void)
+{
+  return (sys_thread_t) GetCurrentThreadId ();
+}
+
+int
+sys_thread_equal (sys_thread_t one, sys_thread_t two)
+{
+  return one == two;
+}
+
+static thread_creation_function *thread_start_address;
+
+static void
+w32_beginthread_wrapper (void *arg)
+{
+  (void)thread_start_address (arg);
+}
+
+int
+sys_thread_create (sys_thread_t *thread_ptr, const char *name,
+                  thread_creation_function *func, void *arg)
+{
+  /* FIXME: Do threads that run Lisp require some minimum amount of
+     stack?  Zero here means each thread will get the same amount as
+     the main program.  On GNU/Linux, it seems like the stack is 2MB
+     by default, overridden by RLIMIT_STACK at program start time.
+     Not sure what to do with this.  See also the comment in
+     w32proc"new_child.  */
+  const unsigned stack_size = 0;
+  uintptr_t thandle;
+
+  /* _beginthread wants a void function, while we are passed a
+     function that returns a pointer.  So we use a wrapper.  */
+  thread_start_address = func;
+
+  /* We use _beginthread rather than CreateThread because the former
+     arranges for the thread handle to be automatically closed when
+     the thread exits, thus preventing handle leaks and/or the need to
+     track all the threads and close their handles when they exit.
+     Also, MSDN seems to imply that code which uses CRT _must_ call
+     _beginthread, although if that is true, we already violate that
+     rule in many places...  */
+  thandle = _beginthread (w32_beginthread_wrapper, stack_size, arg);
+  if (thandle == (uintptr_t)-1L)
+    return errno;
+
+  /* Kludge alert!  We use the Windows thread ID, an unsigned 32-bit
+     number, as the sys_thread_t type, because that ID is the only
+     unique identifier of a thread on Windows.  But _beginthread
+     returns a handle of the thread, and there's no easy way of
+     getting the thread ID given a handle (GetThreadId is available
+     only since Vista, so we cannot use it portably).  Fortunately,
+     the value returned by sys_thread_create is not used by its
+     callers; instead, run_thread, which runs in the context of the
+     new thread, calls sys_thread_self and uses its return value;
+     sys_thread_self in this implementation calls GetCurrentThreadId.
+     Therefore, we return some more or less arbitrary value of the
+     thread ID from this function. */
+  *thread_ptr = thandle & 0xFFFFFFFF;
+  return 0;
+}
+
+void
+sys_thread_yield (void)
+{
+  Sleep (0);
+}
+
 #else
 
 #error port me
index eb9cde78b61c8fcfe789b19fda185fd6242e1963..52735449a5ef086209e53491eadb5a4e5305e68f 100644 (file)
@@ -36,8 +36,42 @@ typedef pthread_t sys_thread_t;
 
 #else /* HAVE_PTHREAD */
 
+#ifdef WINDOWSNT
+
+/* This header is indirectly included in every source file.  We don't
+   want to include windows.h in every source file, so we repeat
+   declarations of the few necessary data types here (under different
+   names, to avoid conflicts with files that do include
+   windows.h).  */
+
+typedef struct {
+  struct _CRITICAL_SECTION_DEBUG *DebugInfo;
+  long LockCount;
+  long RecursionCount;
+  void *OwningThread;
+  void *LockSemaphore;
+  unsigned long SpinCount;
+} w32thread_critsect;
+
+enum { CONDV_SIGNAL = 0, CONDV_BROADCAST = 1, CONDV_MAX = 2 };
+
+typedef struct {
+  unsigned waiters_count;
+  w32thread_critsect waiters_count_lock;
+  void *events[CONDV_MAX];
+} w32thread_cond_t;
+
+typedef w32thread_critsect sys_mutex_t;
+
+typedef w32thread_cond_t sys_cond_t;
+
+typedef unsigned long sys_thread_t;
+
+#else  /* !WINDOWSNT */
+
 #error port me
 
+#endif /* WINDOWSNT */
 #endif /* HAVE_PTHREAD */
 
 #else /* THREADS_ENABLED */