Introduce threads.
[emacs.git] / src / thread.c
blob44ee3cd71ed85473c37b6212309fbc7efaeaec2e
2 #include <config.h>
3 #include "lisp.h"
4 #include <pthread.h>
6 void mark_byte_stack P_ ((struct byte_stack *));
7 void mark_backtrace P_ ((struct backtrace *));
8 void mark_catchlist P_ ((struct catchtag *));
9 void mark_stack P_ ((char *, char *));
10 void flush_stack_call_func P_ ((void (*) (char *)));
13 static struct thread_state primary_thread;
15 static struct thread_state *all_threads = &primary_thread;
17 __thread struct thread_state *current_thread = &primary_thread;
19 static pthread_mutex_t global_lock;
21 static void
22 mark_one_thread (struct thread_state *thread)
24 register struct specbinding *bind;
25 struct handler *handler;
27 for (bind = thread->m_specpdl; bind != thread->m_specpdl_ptr; bind++)
29 mark_object (bind->symbol);
30 mark_object (bind->old_value);
33 #if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \
34 || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS)
35 mark_stack (thread->stack_bottom, thread->stack_top);
36 #else
38 register struct gcpro *tail;
39 for (tail = thread->m_gcprolist; tail; tail = tail->next)
40 for (i = 0; i < tail->nvars; i++)
41 mark_object (tail->var[i]);
43 #endif
45 mark_byte_stack (thread->m_byte_stack_list);
47 mark_catchlist (thread->m_catchlist);
49 for (handler = thread->m_handlerlist; handler; handler = handler->next)
51 mark_object (handler->handler);
52 mark_object (handler->var);
55 mark_backtrace (thread->m_backtrace_list);
57 if (thread->func)
58 mark_object (thread->func);
61 static void
62 mark_threads_continuation (char *end)
64 struct thread_state *iter;
66 current_thread->stack_top = end;
67 for (iter = all_threads; iter; iter = iter->next)
68 mark_one_thread (iter);
71 void
72 mark_threads (void)
74 flush_stack_call_func (mark_threads_continuation);
77 void
78 unmark_threads (void)
80 struct thread_state *iter;
82 for (iter = all_threads; iter; iter = iter->next)
83 unmark_byte_stack (iter->m_byte_stack_list);
86 static void
87 thread_yield_continuation (char *end)
89 current_thread->stack_top = end;
90 pthread_mutex_unlock (&global_lock);
91 sched_yield ();
92 pthread_mutex_lock (&global_lock);
95 void
96 thread_yield (void)
98 /* Note: currently it is safe to check this here, but eventually it
99 will require a lock to ensure non-racy operation. */
100 /* Only yield if there is another thread to yield to. */
101 if (all_threads->next)
102 flush_stack_call_func (thread_yield_continuation);
105 DEFUN ("yield", Fyield, Syield, 0, 0, 0,
106 doc: /* Yield to the next thread. */)
107 (void)
109 thread_yield ();
112 static void *
113 run_thread (void *state)
115 char stack_bottom_variable;
116 struct thread_state *self = state;
117 struct thread_state **iter;
119 self->stack_bottom = &stack_bottom_variable;
121 self->m_specpdl_size = 50;
122 self->m_specpdl = xmalloc (self->m_specpdl_size
123 * sizeof (struct specbinding));
124 self->m_specpdl_ptr = self->m_specpdl;
126 /* Thread-local assignment. */
127 current_thread = self;
129 pthread_mutex_lock (&global_lock);
131 /* FIXME: unwind protect here. */
132 Ffuncall (1, &self->func);
134 /* Unlink this thread from the list of all threads. */
135 for (iter = &all_threads; *iter != self; iter = &(*iter)->next)
137 *iter = (*iter)->next;
139 xfree (self->m_specpdl);
140 /* FIXME: other cleanups here. */
141 xfree (self);
143 pthread_mutex_unlock (&global_lock);
145 return NULL;
148 DEFUN ("run-in-thread", Frun_in_thread, Srun_in_thread, 1, 1, 0,
149 doc: /* Start a new thread and run FUNCTION in it.
150 When the function exits, the thread dies. */)
151 (function)
152 Lisp_Object function;
154 pthread_t thr;
155 struct thread_state *new_thread;
157 /* Can't start a thread in temacs. */
158 if (!initialized)
159 abort ();
161 new_thread = xmalloc (sizeof (struct thread_state));
162 memset (new_thread, 0, sizeof (struct thread_state));
164 new_thread->func = function;
166 /* We'll need locking here. */
167 new_thread->next = all_threads;
168 all_threads = new_thread;
170 /* FIXME check result */
171 pthread_create (&thr, NULL, run_thread, new_thread);
174 void
175 init_threads (void)
177 pthread_mutex_init (&global_lock, NULL);
178 pthread_mutex_lock (&global_lock);
181 void
182 syms_of_threads (void)
184 defsubr (&Srun_in_thread);
185 defsubr (&Syield);