aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Tromey2012-08-15 13:03:17 -0600
committerTom Tromey2012-08-15 13:03:17 -0600
commit14b3dc5e4f2cdefde1ba04ddd3525115e7ca7dce (patch)
treeaf04882e838fea858d9672dac6c19eab374505b9
parent2d525b793f1b0fd2b6f66881310bec8684bceffe (diff)
downloademacs-14b3dc5e4f2cdefde1ba04ddd3525115e7ca7dce.tar.gz
emacs-14b3dc5e4f2cdefde1ba04ddd3525115e7ca7dce.zip
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.
-rw-r--r--src/Makefile.in2
-rw-r--r--src/emacs.c1
-rw-r--r--src/lisp.h2
-rw-r--r--src/systhread.c189
-rw-r--r--src/systhread.h80
-rw-r--r--src/thread.c9
-rw-r--r--src/thread.h4
7 files changed, 286 insertions, 1 deletions
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 \
336 eval.o floatfns.o fns.o font.o print.o lread.o \ 336 eval.o floatfns.o fns.o font.o print.o lread.o \
337 syntax.o $(UNEXEC_OBJ) bytecode.o \ 337 syntax.o $(UNEXEC_OBJ) bytecode.o \
338 process.o gnutls.o callproc.o \ 338 process.o gnutls.o callproc.o \
339 region-cache.o sound.o atimer.o thread.o \ 339 region-cache.o sound.o atimer.o thread.o systhread.o \
340 doprnt.o intervals.o textprop.o composite.o xml.o \ 340 doprnt.o intervals.o textprop.o composite.o xml.o \
341 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) 341 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
342obj = $(base_obj) $(NS_OBJC_OBJ) 342obj = $(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
1270 } 1270 }
1271 1271
1272 init_alloc (); 1272 init_alloc ();
1273 init_threads ();
1273 1274
1274 if (do_initial_setlocale) 1275 if (do_initial_setlocale)
1275 { 1276 {
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 <http://www.gnu.org/licenses/>. */
29 29
30#include <intprops.h> 30#include <intprops.h>
31 31
32#include "systhread.h"
33
32INLINE_HEADER_BEGIN 34INLINE_HEADER_BEGIN
33#ifndef LISP_INLINE 35#ifndef LISP_INLINE
34# define LISP_INLINE INLINE 36# 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 @@
1/* System thread definitions
2 Copyright (C) 2012 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19#include <config.h>
20#include <setjmp.h>
21#include "lisp.h"
22
23#ifdef HAVE_PTHREAD
24
25#include <sched.h>
26
27void
28sys_mutex_init (sys_mutex_t *mutex)
29{
30 pthread_mutex_init (mutex, NULL);
31}
32
33void
34sys_mutex_lock (sys_mutex_t *mutex)
35{
36 pthread_mutex_lock (mutex);
37}
38
39void
40sys_mutex_unlock (sys_mutex_t *mutex)
41{
42 pthread_mutex_unlock (mutex);
43}
44
45void
46sys_mutex_destroy (sys_mutex_t *mutex)
47{
48 pthread_mutex_destroy (mutex);
49}
50
51void
52sys_cond_init (sys_cond_t *cond)
53{
54 pthread_cond_init (cond, NULL);
55}
56
57void
58sys_cond_wait (sys_cond_t *cond, sys_mutex_t *mutex)
59{
60 pthread_cond_wait (cond, mutex);
61}
62
63void
64sys_cond_signal (sys_cond_t *cond)
65{
66 pthread_cond_signal (cond);
67}
68
69void
70sys_cond_broadcast (sys_cond_t *cond)
71{
72 pthread_cond_broadcast (cond);
73}
74
75void
76sys_cond_destroy (sys_cond_t *cond)
77{
78 pthread_cond_destroy (cond);
79}
80
81void
82lisp_mutex_init (lisp_mutex_t *mutex)
83{
84 mutex->owner = NULL;
85 mutex->count = 0;
86 /* A lisp "mutex" is really a condition variable. */
87 pthread_cond_init (&mutex->condition, NULL);
88}
89
90void
91lisp_mutex_lock (lisp_mutex_t *mutex)
92{
93 struct thread_state *self;
94
95 if (mutex->owner == NULL)
96 {
97 mutex->owner = current_thread;
98 mutex->count = 1;
99 return;
100 }
101 if (mutex->owner == current_thread)
102 {
103 ++mutex->count;
104 return;
105 }
106
107 self = current_thread;
108 while (mutex->owner != NULL /* && EQ (self->error_symbol, Qnil) */)
109 pthread_cond_wait (&mutex->condition, &global_lock);
110
111#if 0
112 if (!EQ (self->error_symbol, Qnil))
113 {
114 Lisp_Object error_symbol = self->error_symbol;
115 Lisp_Object data = self->error_data;
116 self->error_symbol = Qnil;
117 self->error_data = Qnil;
118 Fsignal (error_symbol, error_data);
119 }
120#endif
121
122 mutex->owner = self;
123 mutex->count = 1;
124}
125
126void
127lisp_mutex_unlock (lisp_mutex_t *mutex)
128{
129 struct thread_state *self = current_thread;
130
131 if (mutex->owner != current_thread)
132 error ("blah");
133
134 if (--mutex->count > 0)
135 return;
136
137 mutex->owner = NULL;
138 pthread_cond_broadcast (&mutex->condition);
139
140 post_acquire_global_lock (self);
141}
142
143void
144lisp_mutex_destroy (lisp_mutex_t *mutex)
145{
146 sys_cond_destroy (&mutex->condition);
147}
148
149sys_thread_t
150sys_thread_self (void)
151{
152 return pthread_self ();
153}
154
155int
156sys_thread_equal (sys_thread_t one, sys_thread_t two)
157{
158 return pthread_equal (one, two);
159}
160
161int
162sys_thread_create (sys_thread_t *thread_ptr, thread_creation_function *func,
163 void *arg)
164{
165 pthread_attr_t attr;
166 int result = 0;
167
168 if (pthread_attr_init (&attr))
169 return 0;
170
171 if (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED))
172 result = pthread_create (thread_ptr, &attr, func, arg) == 0;
173
174 pthread_attr_destroy (&attr);
175
176 return result;
177}
178
179void
180sys_thread_yield (void)
181{
182 sched_yield ();
183}
184
185#else
186
187#error port me
188
189#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 @@
1/* System thread definitions
2 Copyright (C) 2012 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
19#ifndef SYSTHREAD_H
20#define SYSTHREAD_H
21
22#ifdef HAVE_PTHREAD
23
24#include <pthread.h>
25
26/* A mutex in lisp is represented by a pthread condition variable.
27 The pthread mutex associated with this condition variable is the
28 global lock.
29
30 Using a condition variable lets us implement interruptibility for
31 lisp mutexes. */
32typedef struct
33{
34 struct thread_state *owner;
35 unsigned int count;
36 pthread_cond_t condition;
37} lisp_mutex_t;
38
39/* A system mutex is just a pthread mutex. This is only used for the
40 GIL. */
41typedef pthread_mutex_t sys_mutex_t;
42
43typedef pthread_cond_t sys_cond_t;
44
45/* A system thread. */
46typedef pthread_t sys_thread_t;
47
48#else
49
50#error port me
51
52#endif
53
54typedef void *(thread_creation_function) (void *);
55
56extern void sys_mutex_init (sys_mutex_t *);
57extern void sys_mutex_lock (sys_mutex_t *);
58extern void sys_mutex_unlock (sys_mutex_t *);
59extern void sys_mutex_destroy (sys_mutex_t *);
60
61extern void sys_cond_init (sys_cond_t *);
62extern void sys_cond_wait (sys_cond_t *, sys_mutex_t *);
63extern void sys_cond_signal (sys_cond_t *);
64extern void sys_cond_broadcast (sys_cond_t *);
65extern void sys_cond_destroy (sys_cond_t *);
66
67extern void lisp_mutex_init (lisp_mutex_t *);
68extern void lisp_mutex_lock (lisp_mutex_t *);
69extern void lisp_mutex_unlock (lisp_mutex_t *);
70extern void lisp_mutex_destroy (lisp_mutex_t *);
71
72extern sys_thread_t sys_thread_self (void);
73extern int sys_thread_equal (sys_thread_t, sys_thread_t);
74
75extern int sys_thread_create (sys_thread_t *, thread_creation_function *,
76 void *);
77
78extern void sys_thread_yield (void);
79
80#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;
27 27
28struct thread_state *all_threads = &the_only_thread; 28struct thread_state *all_threads = &the_only_thread;
29 29
30sys_mutex_t global_lock;
31
30static void 32static void
31mark_one_thread (struct thread_state *thread) 33mark_one_thread (struct thread_state *thread)
32{ 34{
@@ -103,3 +105,10 @@ unmark_threads (void)
103 if (iter->m_byte_stack_list) 105 if (iter->m_byte_stack_list)
104 unmark_byte_stack (iter->m_byte_stack_list); 106 unmark_byte_stack (iter->m_byte_stack_list);
105} 107}
108
109void
110init_threads (void)
111{
112 sys_mutex_init (&global_lock);
113 sys_mutex_lock (&global_lock);
114}
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
140 140
141extern struct thread_state *current_thread; 141extern struct thread_state *current_thread;
142 142
143extern sys_mutex_t global_lock;
144
143extern void unmark_threads (void); 145extern void unmark_threads (void);
144 146
147extern void init_threads (void);
148
145#endif /* THREAD_H */ 149#endif /* THREAD_H */