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 *, void *), void *));
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 pthread_mutex_t global_lock
;
22 mark_one_thread (struct thread_state
*thread
)
24 register struct specbinding
*bind
;
25 struct handler
*handler
;
28 for (bind
= thread
->m_specpdl
; bind
!= thread
->m_specpdl_ptr
; bind
++)
30 mark_object (bind
->symbol
);
31 mark_object (bind
->old_value
);
34 #if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \
35 || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS)
36 mark_stack (thread
->stack_bottom
, thread
->stack_top
);
39 register struct gcpro
*tail
;
40 for (tail
= thread
->m_gcprolist
; tail
; tail
= tail
->next
)
41 for (i
= 0; i
< tail
->nvars
; i
++)
42 mark_object (tail
->var
[i
]);
46 mark_byte_stack (thread
->m_byte_stack_list
);
48 mark_catchlist (thread
->m_catchlist
);
50 for (handler
= thread
->m_handlerlist
; handler
; handler
= handler
->next
)
52 mark_object (handler
->handler
);
53 mark_object (handler
->var
);
56 mark_backtrace (thread
->m_backtrace_list
);
58 XSETBUFFER (tem
, thread
->m_current_buffer
);
63 mark_threads_callback (char *end
, void *ignore
)
65 struct thread_state
*iter
;
67 current_thread
->stack_top
= end
;
68 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
70 Lisp_Object thread_obj
;
71 XSETTHREAD (thread_obj
, iter
);
72 mark_object (thread_obj
);
73 mark_one_thread (iter
);
80 flush_stack_call_func (mark_threads_callback
, NULL
);
86 struct thread_state
*iter
;
88 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
89 unmark_byte_stack (iter
->m_byte_stack_list
);
93 thread_yield_callback (char *end
, void *ignore
)
95 current_thread
->stack_top
= end
;
96 pthread_mutex_unlock (&global_lock
);
98 pthread_mutex_lock (&global_lock
);
104 /* Note: currently it is safe to check this here, but eventually it
105 will require a lock to ensure non-racy operation. */
106 /* Only yield if there is another thread to yield to. */
107 if (all_threads
->next_thread
)
108 flush_stack_call_func (thread_yield_callback
, NULL
);
111 DEFUN ("yield", Fyield
, Syield
, 0, 0, 0,
112 doc
: /* Yield to the next thread. */)
119 invoke_thread_function (void)
123 int count
= SPECPDL_INDEX ();
125 /* Set up specpdl. */
126 for (iter
= current_thread
->initial_specpdl
;
130 /* We may bind a variable twice -- but it doesn't matter because
131 there is no way to undo these bindings without exiting the
133 specbind (XCAR (XCAR (iter
)), XCDR (XCAR (iter
)));
135 current_thread
->initial_specpdl
= Qnil
;
137 Ffuncall (1, ¤t_thread
->func
);
138 return unbind_to (count
, Qnil
);
142 do_nothing (Lisp_Object whatever
)
148 run_thread (void *state
)
150 char stack_bottom_variable
;
151 struct thread_state
*self
= state
;
152 struct thread_state
**iter
;
156 self
->stack_bottom
= &stack_bottom_variable
;
158 self
->m_specpdl_size
= 50;
159 self
->m_specpdl
= xmalloc (self
->m_specpdl_size
160 * sizeof (struct specbinding
));
161 self
->m_specpdl_ptr
= self
->m_specpdl
;
163 /* Thread-local assignment. */
164 current_thread
= self
;
166 pthread_mutex_lock (&global_lock
);
168 /* We need special handling to set the initial buffer. Our parent
169 thread is very likely to be using this same buffer so we will
170 typically wait for the parent thread to release it first. */
171 XSETBUFFER (buffer
, self
->m_current_buffer
);
173 self
->m_current_buffer
= 0;
174 set_buffer_internal (XBUFFER (buffer
));
176 /* It might be nice to do something with errors here. */
177 internal_condition_case (invoke_thread_function
, Qt
, do_nothing
);
179 /* Unlink this thread from the list of all threads. */
180 for (iter
= &all_threads
; *iter
!= self
; iter
= &(*iter
)->next_thread
)
182 *iter
= (*iter
)->next_thread
;
184 xfree (self
->m_specpdl
);
187 pthread_mutex_unlock (&global_lock
);
192 DEFUN ("run-in-thread", Frun_in_thread
, Srun_in_thread
, 1, 1, 0,
193 doc
: /* Start a new thread and run FUNCTION in it.
194 When the function exits, the thread dies. */)
196 Lisp_Object function
;
199 struct thread_state
*new_thread
;
200 struct specbinding
*p
;
202 /* Can't start a thread in temacs. */
206 new_thread
= (struct thread_state
*) allocate_pseudovector (VECSIZE (struct thread_state
),
208 memset (new_thread
, OFFSETOF (struct thread_state
,
210 sizeof (struct thread_state
) - OFFSETOF (struct thread_state
,
213 new_thread
->func
= function
;
214 new_thread
->initial_specpdl
= Qnil
;
216 for (p
= specpdl
; p
!= specpdl_ptr
; ++p
)
220 Lisp_Object sym
= p
->symbol
;
223 new_thread
->initial_specpdl
224 = Fcons (Fcons (sym
, find_symbol_value (sym
)),
225 new_thread
->initial_specpdl
);
229 /* We'll need locking here. */
230 new_thread
->next_thread
= all_threads
;
231 all_threads
= new_thread
;
233 /* FIXME check result */
234 pthread_create (&thr
, NULL
, run_thread
, new_thread
);
239 /* Get the current thread as a lisp object. */
241 get_current_thread (void)
244 XSETTHREAD (result
, current_thread
);
248 /* Get the main thread as a lisp object. */
250 get_main_thread (void)
253 XSETTHREAD (result
, &primary_thread
);
258 other_threads_p (void)
260 return all_threads
->next_thread
!= NULL
;
266 pthread_mutex_init (&global_lock
, NULL
);
267 pthread_mutex_lock (&global_lock
);
271 syms_of_threads (void)
273 defsubr (&Srun_in_thread
);