mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-08 20:50:52 -08:00
Run admin/update-copyright in the master branch. This fixes files that were not already fixed in the emacs-25 branch before it was merged here.
417 lines
9.6 KiB
C
417 lines
9.6 KiB
C
/* System thread definitions
|
|
Copyright (C) 2012-2017 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Emacs.
|
|
|
|
GNU Emacs 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.
|
|
|
|
GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include <config.h>
|
|
#include <setjmp.h>
|
|
#include "lisp.h"
|
|
|
|
#ifndef THREADS_ENABLED
|
|
|
|
void
|
|
sys_mutex_init (sys_mutex_t *m)
|
|
{
|
|
*m = 0;
|
|
}
|
|
|
|
void
|
|
sys_mutex_lock (sys_mutex_t *m)
|
|
{
|
|
}
|
|
|
|
void
|
|
sys_mutex_unlock (sys_mutex_t *m)
|
|
{
|
|
}
|
|
|
|
void
|
|
sys_mutex_destroy (sys_mutex_t *m)
|
|
{
|
|
}
|
|
|
|
void
|
|
sys_cond_init (sys_cond_t *c)
|
|
{
|
|
*c = 0;
|
|
}
|
|
|
|
void
|
|
sys_cond_wait (sys_cond_t *c, sys_mutex_t *m)
|
|
{
|
|
}
|
|
|
|
void
|
|
sys_cond_signal (sys_cond_t *c)
|
|
{
|
|
}
|
|
|
|
void
|
|
sys_cond_broadcast (sys_cond_t *c)
|
|
{
|
|
}
|
|
|
|
void
|
|
sys_cond_destroy (sys_cond_t *c)
|
|
{
|
|
}
|
|
|
|
sys_thread_t
|
|
sys_thread_self (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
sys_thread_equal (sys_thread_t x, sys_thread_t y)
|
|
{
|
|
return x == y;
|
|
}
|
|
|
|
int
|
|
sys_thread_create (sys_thread_t *t, const char *name,
|
|
thread_creation_function *func, void *datum)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
sys_thread_yield (void)
|
|
{
|
|
}
|
|
|
|
#elif defined (HAVE_PTHREAD)
|
|
|
|
#include <sched.h>
|
|
|
|
#ifdef HAVE_SYS_PRCTL_H
|
|
#include <sys/prctl.h>
|
|
#endif
|
|
|
|
void
|
|
sys_mutex_init (sys_mutex_t *mutex)
|
|
{
|
|
pthread_mutex_init (mutex, NULL);
|
|
}
|
|
|
|
void
|
|
sys_mutex_lock (sys_mutex_t *mutex)
|
|
{
|
|
pthread_mutex_lock (mutex);
|
|
}
|
|
|
|
void
|
|
sys_mutex_unlock (sys_mutex_t *mutex)
|
|
{
|
|
pthread_mutex_unlock (mutex);
|
|
}
|
|
|
|
void
|
|
sys_mutex_destroy (sys_mutex_t *mutex)
|
|
{
|
|
pthread_mutex_destroy (mutex);
|
|
}
|
|
|
|
void
|
|
sys_cond_init (sys_cond_t *cond)
|
|
{
|
|
pthread_cond_init (cond, NULL);
|
|
}
|
|
|
|
void
|
|
sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex)
|
|
{
|
|
pthread_cond_wait (cond, mutex);
|
|
}
|
|
|
|
void
|
|
sys_cond_signal (sys_cond_t *cond)
|
|
{
|
|
pthread_cond_signal (cond);
|
|
}
|
|
|
|
void
|
|
sys_cond_broadcast (sys_cond_t *cond)
|
|
{
|
|
pthread_cond_broadcast (cond);
|
|
}
|
|
|
|
void
|
|
sys_cond_destroy (sys_cond_t *cond)
|
|
{
|
|
pthread_cond_destroy (cond);
|
|
}
|
|
|
|
sys_thread_t
|
|
sys_thread_self (void)
|
|
{
|
|
return pthread_self ();
|
|
}
|
|
|
|
int
|
|
sys_thread_equal (sys_thread_t one, sys_thread_t two)
|
|
{
|
|
return pthread_equal (one, two);
|
|
}
|
|
|
|
int
|
|
sys_thread_create (sys_thread_t *thread_ptr, const char *name,
|
|
thread_creation_function *func, void *arg)
|
|
{
|
|
pthread_attr_t attr;
|
|
int result = 0;
|
|
|
|
if (pthread_attr_init (&attr))
|
|
return 0;
|
|
|
|
if (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED))
|
|
{
|
|
result = pthread_create (thread_ptr, &attr, func, arg) == 0;
|
|
#if defined (HAVE_SYS_PRCTL_H) && defined (HAVE_PRCTL) && defined (PR_SET_NAME)
|
|
if (result && name != NULL)
|
|
prctl (PR_SET_NAME, name);
|
|
#endif
|
|
}
|
|
|
|
pthread_attr_destroy (&attr);
|
|
|
|
return result;
|
|
}
|
|
|
|
void
|
|
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 need to 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? According 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 seem 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->initialized = false;
|
|
cond->wait_count = 0;
|
|
/* Auto-reset event for signal. */
|
|
cond->events[CONDV_SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL);
|
|
/* Manual-reset event for broadcast. */
|
|
cond->events[CONDV_BROADCAST] = CreateEvent (NULL, TRUE, FALSE, NULL);
|
|
if (!cond->events[CONDV_SIGNAL] || !cond->events[CONDV_BROADCAST])
|
|
return;
|
|
InitializeCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
|
|
cond->initialized = true;
|
|
}
|
|
|
|
void
|
|
sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex)
|
|
{
|
|
DWORD wait_result;
|
|
bool last_thread_waiting;
|
|
|
|
if (!cond->initialized)
|
|
return;
|
|
|
|
/* Increment the wait count avoiding race conditions. */
|
|
EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
|
|
cond->wait_count++;
|
|
LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
|
|
|
|
/* Release the mutex and wait for either the signal or the broadcast
|
|
event. */
|
|
LeaveCriticalSection ((LPCRITICAL_SECTION)mutex);
|
|
wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
|
|
|
|
/* Decrement the wait count and see if we are the last thread
|
|
waiting on the condition variable. */
|
|
EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
|
|
cond->wait_count--;
|
|
last_thread_waiting =
|
|
wait_result == WAIT_OBJECT_0 + CONDV_BROADCAST
|
|
&& cond->wait_count == 0;
|
|
LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
|
|
|
|
/* Broadcast uses a manual-reset event, so when the last thread is
|
|
released, we must manually reset that event. */
|
|
if (last_thread_waiting)
|
|
ResetEvent (cond->events[CONDV_BROADCAST]);
|
|
|
|
/* Per the API, re-acquire the mutex. */
|
|
EnterCriticalSection ((LPCRITICAL_SECTION)mutex);
|
|
}
|
|
|
|
void
|
|
sys_cond_signal (sys_cond_t *cond)
|
|
{
|
|
bool threads_waiting;
|
|
|
|
if (!cond->initialized)
|
|
return;
|
|
|
|
EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
|
|
threads_waiting = cond->wait_count > 0;
|
|
LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
|
|
|
|
if (threads_waiting)
|
|
SetEvent (cond->events[CONDV_SIGNAL]);
|
|
}
|
|
|
|
void
|
|
sys_cond_broadcast (sys_cond_t *cond)
|
|
{
|
|
bool threads_waiting;
|
|
|
|
if (!cond->initialized)
|
|
return;
|
|
|
|
EnterCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
|
|
threads_waiting = cond->wait_count > 0;
|
|
LeaveCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
|
|
|
|
if (threads_waiting)
|
|
SetEvent (cond->events[CONDV_BROADCAST]);
|
|
}
|
|
|
|
void
|
|
sys_cond_destroy (sys_cond_t *cond)
|
|
{
|
|
if (cond->events[CONDV_SIGNAL])
|
|
CloseHandle (cond->events[CONDV_SIGNAL]);
|
|
if (cond->events[CONDV_BROADCAST])
|
|
CloseHandle (cond->events[CONDV_BROADCAST]);
|
|
|
|
if (!cond->initialized)
|
|
return;
|
|
|
|
/* FIXME: What if wait_count is non-zero, i.e. there are still
|
|
threads waiting on this condition variable? */
|
|
DeleteCriticalSection ((LPCRITICAL_SECTION)&cond->wait_count_lock);
|
|
}
|
|
|
|
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;
|
|
|
|
/* _beginthread wants a void function, while we are passed a function
|
|
that returns a pointer. So we use a wrapper. */
|
|
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.c:new_child. */
|
|
const unsigned stack_size = 0;
|
|
uintptr_t thandle;
|
|
|
|
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 0;
|
|
|
|
/* 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 1;
|
|
}
|
|
|
|
void
|
|
sys_thread_yield (void)
|
|
{
|
|
Sleep (0);
|
|
}
|
|
|
|
#else
|
|
|
|
#error port me
|
|
|
|
#endif
|