mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-20 18:17:20 +00:00
Enable thread support in the MS-Windows build.
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.
This commit is contained in:
parent
0e82377a2d
commit
dbe17fefcc
@ -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).
|
||||
|
@ -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])
|
||||
|
@ -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:
|
||||
|
149
src/systhread.c
149
src/systhread.c
@ -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
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user