diff --git a/src/Makefile.in b/src/Makefile.in index 2d1bdd097ef..01034ca98d5 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -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) diff --git a/src/emacs.c b/src/emacs.c index e1acd365e29..443fe594795 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -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) { diff --git a/src/lisp.h b/src/lisp.h index a6665320da6..b0ed9be9f07 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -29,6 +29,8 @@ along with GNU Emacs. If not, see . */ #include +#include "systhread.h" + INLINE_HEADER_BEGIN #ifndef LISP_INLINE # define LISP_INLINE INLINE diff --git a/src/systhread.c b/src/systhread.c new file mode 100644 index 00000000000..b7147c4fc95 --- /dev/null +++ b/src/systhread.c @@ -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 . */ + +#include +#include +#include "lisp.h" + +#ifdef HAVE_PTHREAD + +#include + +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 diff --git a/src/systhread.h b/src/systhread.h new file mode 100644 index 00000000000..bf9358c21c6 --- /dev/null +++ b/src/systhread.h @@ -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 . */ + +#ifndef SYSTHREAD_H +#define SYSTHREAD_H + +#ifdef HAVE_PTHREAD + +#include + +/* 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 */ diff --git a/src/thread.c b/src/thread.c index ba2d66320fa..19faa1bafae 100644 --- a/src/thread.c +++ b/src/thread.c @@ -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); +} diff --git a/src/thread.h b/src/thread.h index 6d61d0e5fcf..020346b9af2 100644 --- a/src/thread.h +++ b/src/thread.h @@ -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 */