From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Tom Tromey Newsgroups: gmane.emacs.devel Subject: [PATCH 03/10] introduce systhread layer Date: Thu, 09 Aug 2012 13:38:33 -0600 Message-ID: <87mx23etza.fsf@fleche.redhat.com> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: dough.gmane.org 1344541123 11509 80.91.229.3 (9 Aug 2012 19:38:43 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Thu, 9 Aug 2012 19:38:43 +0000 (UTC) To: Emacs discussions Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Thu Aug 09 21:38:44 2012 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1SzYZ9-0004EY-BA for ged-emacs-devel@m.gmane.org; Thu, 09 Aug 2012 21:38:43 +0200 Original-Received: from localhost ([::1]:47469 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SzYZ8-0001M6-K6 for ged-emacs-devel@m.gmane.org; Thu, 09 Aug 2012 15:38:42 -0400 Original-Received: from eggs.gnu.org ([208.118.235.92]:46799) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SzYZ4-0001Ln-SD for emacs-devel@gnu.org; Thu, 09 Aug 2012 15:38:40 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SzYZ2-0003eS-S4 for emacs-devel@gnu.org; Thu, 09 Aug 2012 15:38:38 -0400 Original-Received: from mx1.redhat.com ([209.132.183.28]:30356) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SzYZ2-0003eJ-JC for emacs-devel@gnu.org; Thu, 09 Aug 2012 15:38:36 -0400 Original-Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q79JcZsY015356 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 9 Aug 2012 15:38:36 -0400 Original-Received: from barimba (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q79JcXuQ009662 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Thu, 9 Aug 2012 15:38:34 -0400 X-Attribution: Tom User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux) X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:152377 Archived-At: 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. 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. Thoughts on this? 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. --- src/Makefile.in | 2 +- src/emacs.c | 1 + src/lisp.h | 2 + src/systhread.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/systhread.h | 80 +++++++++++++++++++++++++ src/thread.c | 9 +++ src/thread.h | 4 + 7 files changed, 275 insertions(+), 1 deletions(-) create mode 100644 src/systhread.c create mode 100644 src/systhread.h diff --git a/src/Makefile.in b/src/Makefile.in index c5f36c0..6270bd8 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 e1acd36..443fe59 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 db8d9b4..8f3afa7 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -28,6 +28,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 0000000..d5f00ba --- /dev/null +++ b/src/systhread.c @@ -0,0 +1,178 @@ +/* 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) +{ + return pthread_create (thread_ptr, NULL, func, arg) == 0; +} + +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 0000000..bf9358c --- /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 ba2d663..19faa1b 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 6d61d0e..020346b 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 */ -- 1.7.7.6