1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-10 13:40:36 -08:00

This introduces the low-level system threading support. It also adds

the global lock.  The low-level support is a bit over-eager, in that
even at the end of the present series, it will not all be used.  I
think thiat is ok since I plan to use it all eventually -- in
particular for the emacs lisp mutex implementation.

I've only implemented the pthreads-based version.  I think it should
be relatively clear how to port this to other systems, though.

I'd also like to do a "no threads" port that will turn most things
into no-ops, and have thread-creation fail.  I was thinking perhaps
I'd make a future (provide 'threads) conditional on threads actually
working.

One other minor enhancement available here is to make it possible to
set the name of the new thread at the OS layer.  That way gdb, e.g.,
could display thread names.
This commit is contained in:
Tom Tromey 2012-08-15 13:03:17 -06:00
parent 2d525b793f
commit 14b3dc5e4f
7 changed files with 286 additions and 1 deletions

View file

@ -336,7 +336,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
eval.o floatfns.o fns.o font.o print.o lread.o \
syntax.o $(UNEXEC_OBJ) bytecode.o \
process.o gnutls.o callproc.o \
region-cache.o sound.o atimer.o thread.o \
region-cache.o sound.o atimer.o thread.o systhread.o \
doprnt.o intervals.o textprop.o composite.o xml.o \
$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
obj = $(base_obj) $(NS_OBJC_OBJ)

View file

@ -1270,6 +1270,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
}
init_alloc ();
init_threads ();
if (do_initial_setlocale)
{

View file

@ -29,6 +29,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <intprops.h>
#include "systhread.h"
INLINE_HEADER_BEGIN
#ifndef LISP_INLINE
# define LISP_INLINE INLINE

189
src/systhread.c Normal file
View file

@ -0,0 +1,189 @@
/* System thread definitions
Copyright (C) 2012 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"
#ifdef HAVE_PTHREAD
#include <sched.h>
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);
}
void
lisp_mutex_init (lisp_mutex_t *mutex)
{
mutex->owner = NULL;
mutex->count = 0;
/* A lisp "mutex" is really a condition variable. */
pthread_cond_init (&mutex->condition, NULL);
}
void
lisp_mutex_lock (lisp_mutex_t *mutex)
{
struct thread_state *self;
if (mutex->owner == NULL)
{
mutex->owner = current_thread;
mutex->count = 1;
return;
}
if (mutex->owner == current_thread)
{
++mutex->count;
return;
}
self = current_thread;
while (mutex->owner != NULL /* && EQ (self->error_symbol, Qnil) */)
pthread_cond_wait (&mutex->condition, &global_lock);
#if 0
if (!EQ (self->error_symbol, Qnil))
{
Lisp_Object error_symbol = self->error_symbol;
Lisp_Object data = self->error_data;
self->error_symbol = Qnil;
self->error_data = Qnil;
Fsignal (error_symbol, error_data);
}
#endif
mutex->owner = self;
mutex->count = 1;
}
void
lisp_mutex_unlock (lisp_mutex_t *mutex)
{
struct thread_state *self = current_thread;
if (mutex->owner != current_thread)
error ("blah");
if (--mutex->count > 0)
return;
mutex->owner = NULL;
pthread_cond_broadcast (&mutex->condition);
post_acquire_global_lock (self);
}
void
lisp_mutex_destroy (lisp_mutex_t *mutex)
{
sys_cond_destroy (&mutex->condition);
}
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, 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;
pthread_attr_destroy (&attr);
return result;
}
void
sys_thread_yield (void)
{
sched_yield ();
}
#else
#error port me
#endif

80
src/systhread.h Normal file
View file

@ -0,0 +1,80 @@
/* System thread definitions
Copyright (C) 2012 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/>. */
#ifndef SYSTHREAD_H
#define SYSTHREAD_H
#ifdef HAVE_PTHREAD
#include <pthread.h>
/* A mutex in lisp is represented by a pthread condition variable.
The pthread mutex associated with this condition variable is the
global lock.
Using a condition variable lets us implement interruptibility for
lisp mutexes. */
typedef struct
{
struct thread_state *owner;
unsigned int count;
pthread_cond_t condition;
} lisp_mutex_t;
/* A system mutex is just a pthread mutex. This is only used for the
GIL. */
typedef pthread_mutex_t sys_mutex_t;
typedef pthread_cond_t sys_cond_t;
/* A system thread. */
typedef pthread_t sys_thread_t;
#else
#error port me
#endif
typedef void *(thread_creation_function) (void *);
extern void sys_mutex_init (sys_mutex_t *);
extern void sys_mutex_lock (sys_mutex_t *);
extern void sys_mutex_unlock (sys_mutex_t *);
extern void sys_mutex_destroy (sys_mutex_t *);
extern void sys_cond_init (sys_cond_t *);
extern void sys_cond_wait (sys_cond_t *, sys_mutex_t *);
extern void sys_cond_signal (sys_cond_t *);
extern void sys_cond_broadcast (sys_cond_t *);
extern void sys_cond_destroy (sys_cond_t *);
extern void lisp_mutex_init (lisp_mutex_t *);
extern void lisp_mutex_lock (lisp_mutex_t *);
extern void lisp_mutex_unlock (lisp_mutex_t *);
extern void lisp_mutex_destroy (lisp_mutex_t *);
extern sys_thread_t sys_thread_self (void);
extern int sys_thread_equal (sys_thread_t, sys_thread_t);
extern int sys_thread_create (sys_thread_t *, thread_creation_function *,
void *);
extern void sys_thread_yield (void);
#endif /* SYSTHREAD_H */

View file

@ -27,6 +27,8 @@ struct thread_state *current_thread = &the_only_thread;
struct thread_state *all_threads = &the_only_thread;
sys_mutex_t global_lock;
static void
mark_one_thread (struct thread_state *thread)
{
@ -103,3 +105,10 @@ unmark_threads (void)
if (iter->m_byte_stack_list)
unmark_byte_stack (iter->m_byte_stack_list);
}
void
init_threads (void)
{
sys_mutex_init (&global_lock);
sys_mutex_lock (&global_lock);
}

View file

@ -140,6 +140,10 @@ struct thread_state
extern struct thread_state *current_thread;
extern sys_mutex_t global_lock;
extern void unmark_threads (void);
extern void init_threads (void);
#endif /* THREAD_H */