all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* [PATCH 03/10] introduce systhread layer
@ 2012-08-09 19:38 Tom Tromey
  2012-08-10  1:39 ` Daniel Colascione
  0 siblings, 1 reply; 5+ messages in thread
From: Tom Tromey @ 2012-08-09 19:38 UTC (permalink / raw
  To: Emacs discussions

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 <http://www.gnu.org/licenses/>.  */
 
 #include <intprops.h>
 
+#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 <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)
+{
+  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 <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 */
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




^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 03/10] introduce systhread layer
  2012-08-09 19:38 [PATCH 03/10] introduce systhread layer Tom Tromey
@ 2012-08-10  1:39 ` Daniel Colascione
  2012-08-13 10:21   ` Ken Raeburn
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel Colascione @ 2012-08-10  1:39 UTC (permalink / raw
  To: Tom Tromey; +Cc: Emacs discussions

[-- Attachment #1: Type: text/plain, Size: 1002 bytes --]

On 8/9/2012 12:38 PM, Tom Tromey wrote:
> 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?

If threads don't execute simultaneously anyway (and if I understand your design
correctly, the global lock ensures they don't), then it might be worthwhile to
also support a "green threads" implementation like GNU Pth or Windows fibers in
order to avoid OS-level context switch overhead.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 03/10] introduce systhread layer
  2012-08-10  1:39 ` Daniel Colascione
@ 2012-08-13 10:21   ` Ken Raeburn
  2012-08-13 13:21     ` Stefan Monnier
  2012-08-13 14:22     ` Tom Tromey
  0 siblings, 2 replies; 5+ messages in thread
From: Ken Raeburn @ 2012-08-13 10:21 UTC (permalink / raw
  To: Daniel Colascione; +Cc: Tom Tromey, Emacs discussions

> 
> On 8/9/2012 12:38 PM, Tom Tromey wrote:
>> 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?

Unless there's a platform where the support isn't possible, I'd suggest not doing this last bit, so that Emacs code (both Lisp and C) can assume threads are available.  Otherwise, either you can't use threads at all in the release, which means that code won't be exercised very well, or you write code that has to cope with both modes (which may simply mean crippling some features when threads aren't available, and ensuring that the rest of the code still works properly without those features), and probably only really gets tested well in the mode where threads are available.

What benefit do you think providing this "no threads" port would have?

On Aug 9, 2012, at 21:39, Daniel Colascione wrote:
> If threads don't execute simultaneously anyway (and if I understand your design
> correctly, the global lock ensures they don't), then it might be worthwhile to
> also support a "green threads" implementation like GNU Pth or Windows fibers in
> order to avoid OS-level context switch overhead.

Where every I/O operation needs to be rewritten to call some helper function that do the thread switching?  That sounds like a fine way to make the code really ugly. :-(  I think, too, we'd probably want support libraries (X11, image or sound processing, TLS, etc) to be able to do their thing (I/O, parsing, encryption) while another thread runs Lisp code, and if those libraries aren't written to use Pth or whatever, that won't happen.

I've worked on code where performance of the thread-switching support was a big deal.  I don't see Emacs falling into that category, at least not any time soon.  On the other hand, I do hope that people find more uses for thread support than occur to me right now, so….

Ken


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 03/10] introduce systhread layer
  2012-08-13 10:21   ` Ken Raeburn
@ 2012-08-13 13:21     ` Stefan Monnier
  2012-08-13 14:22     ` Tom Tromey
  1 sibling, 0 replies; 5+ messages in thread
From: Stefan Monnier @ 2012-08-13 13:21 UTC (permalink / raw
  To: Ken Raeburn; +Cc: Tom Tromey, Daniel Colascione, Emacs discussions

>>> 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?
> Unless there's a platform where the support isn't possible, I'd suggest not
> doing this last bit, so that Emacs code (both Lisp and C) can assume threads
> are available.

Agreed.

>> like GNU Pth or Windows fibers in order to avoid OS-level context
>> switch overhead.

Thread-switching performance won't be good until we can get rid of the
unwind&rewind of the let-bindings-stack, so "avoid OS-level context
switch overhead" won't bring us any measurable benefit, I think.

> Where every I/O operation needs to be rewritten to call some helper function
> that do the thread switching?

No: for the foreseeable future, the concurrency won't provide any
parallelism at all, so thread-switching will only happen at those few
points were we already allow async operations (sit-for,
accept-process-output and a few more).  So there's no need to make wrap
all I/O operations.


        Stefan



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 03/10] introduce systhread layer
  2012-08-13 10:21   ` Ken Raeburn
  2012-08-13 13:21     ` Stefan Monnier
@ 2012-08-13 14:22     ` Tom Tromey
  1 sibling, 0 replies; 5+ messages in thread
From: Tom Tromey @ 2012-08-13 14:22 UTC (permalink / raw
  To: Ken Raeburn; +Cc: Daniel Colascione, Emacs discussions

>>>>> "Ken" == Ken Raeburn <raeburn@raeburn.org> writes:

Ken> What benefit do you think providing this "no threads" port would have?

Not having to port the thread code to every host platform right away.

Ken> Where every I/O operation needs to be rewritten to call some helper
Ken> function that do the thread switching?

We're going to do this anyway; see the GC patch.

Ken> I've worked on code where performance of the thread-switching support
Ken> was a big deal.  I don't see Emacs falling into that category, at
Ken> least not any time soon.  On the other hand, I do hope that people
Ken> find more uses for thread support than occur to me right now, so….

My new plan is to get something working, then we can refine it.
The critical thing is not to make choices that inhibit future performance.

Tom



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2012-08-13 14:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-09 19:38 [PATCH 03/10] introduce systhread layer Tom Tromey
2012-08-10  1:39 ` Daniel Colascione
2012-08-13 10:21   ` Ken Raeburn
2012-08-13 13:21     ` Stefan Monnier
2012-08-13 14:22     ` Tom Tromey

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.