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 static int inhibit_yield_counter
= 0;
21 pthread_mutex_t global_lock
;
24 mark_one_thread (struct thread_state
*thread
)
26 register struct specbinding
*bind
;
27 struct handler
*handler
;
30 for (bind
= thread
->m_specpdl
; bind
!= thread
->m_specpdl_ptr
; bind
++)
32 mark_object (bind
->symbol
);
33 mark_object (bind
->old_value
);
36 #if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \
37 || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS)
38 mark_stack (thread
->stack_bottom
, thread
->stack_top
);
41 register struct gcpro
*tail
;
42 for (tail
= thread
->m_gcprolist
; tail
; tail
= tail
->next
)
43 for (i
= 0; i
< tail
->nvars
; i
++)
44 mark_object (tail
->var
[i
]);
48 if (thread
->m_byte_stack_list
)
49 mark_byte_stack (thread
->m_byte_stack_list
);
51 mark_catchlist (thread
->m_catchlist
);
53 for (handler
= thread
->m_handlerlist
; handler
; handler
= handler
->next
)
55 mark_object (handler
->handler
);
56 mark_object (handler
->var
);
59 mark_backtrace (thread
->m_backtrace_list
);
61 if (thread
->m_current_buffer
)
63 XSETBUFFER (tem
, thread
->m_current_buffer
);
69 mark_threads_callback (char *end
, void *ignore
)
71 struct thread_state
*iter
;
73 current_thread
->stack_top
= end
;
74 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
76 Lisp_Object thread_obj
;
77 XSETTHREAD (thread_obj
, iter
);
78 mark_object (thread_obj
);
79 mark_one_thread (iter
);
86 flush_stack_call_func (mark_threads_callback
, NULL
);
92 struct thread_state
*iter
;
94 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
95 if (iter
->m_byte_stack_list
)
96 unmark_byte_stack (iter
->m_byte_stack_list
);
100 thread_inhibit_yield_p ()
102 return inhibit_yield_counter
> 0;
106 thread_yield_callback (char *end
, void *ignore
)
108 if (thread_inhibit_yield_p ())
111 current_thread
->stack_top
= end
;
112 pthread_mutex_unlock (&global_lock
);
114 pthread_mutex_lock (&global_lock
);
120 /* Note: currently it is safe to check this here, but eventually it
121 will require a lock to ensure non-racy operation. */
122 /* Only yield if there is another thread to yield to. */
123 if (all_threads
->next_thread
)
124 flush_stack_call_func (thread_yield_callback
, NULL
);
127 DEFUN ("yield", Fyield
, Syield
, 0, 0, 0,
128 doc
: /* Yield to the next thread. */)
136 invoke_thread_function (void)
140 int count
= SPECPDL_INDEX ();
142 /* Set up specpdl. */
143 for (iter
= current_thread
->initial_specpdl
;
147 /* We may bind a variable twice -- but it doesn't matter because
148 there is no way to undo these bindings without exiting the
150 specbind (XCAR (XCAR (iter
)), XCDR (XCAR (iter
)));
152 current_thread
->initial_specpdl
= Qnil
;
154 Feval (current_thread
->func
);
155 return unbind_to (count
, Qnil
);
159 do_nothing (Lisp_Object whatever
)
165 run_thread (void *state
)
167 struct thread_state
*self
= state
;
168 struct thread_state
**iter
;
173 self
->stack_top
= self
->stack_bottom
= &stack_pos
;
175 self
->m_specpdl_size
= 50;
176 self
->m_specpdl
= xmalloc (self
->m_specpdl_size
177 * sizeof (struct specbinding
));
178 self
->m_specpdl_ptr
= self
->m_specpdl
;
179 self
->pthread_id
= pthread_self ();
181 /* Thread-local assignment. */
182 current_thread
= self
;
184 pthread_mutex_lock (&global_lock
);
186 /* We need special handling to set the initial buffer. Our parent
187 thread is very likely to be using this same buffer so we will
188 typically wait for the parent thread to release it first. */
189 XSETBUFFER (buffer
, self
->m_current_buffer
);
191 self
->m_current_buffer
= 0;
192 set_buffer_internal (XBUFFER (buffer
));
194 /* It might be nice to do something with errors here. */
195 internal_condition_case (invoke_thread_function
, Qt
, do_nothing
);
197 /* Unlink this thread from the list of all threads. */
198 for (iter
= &all_threads
; *iter
!= self
; iter
= &(*iter
)->next_thread
)
200 *iter
= (*iter
)->next_thread
;
202 release_buffer (self
);
203 xfree (self
->m_specpdl
);
205 pthread_mutex_unlock (&global_lock
);
210 DEFUN ("run-in-thread", Frun_in_thread
, Srun_in_thread
, 1, 1, 0,
211 doc
: /* Start a new thread and run FUNCTION in it.
212 When the function exits, the thread dies. */)
214 Lisp_Object function
;
218 struct thread_state
*new_thread
;
219 struct specbinding
*p
;
221 /* Can't start a thread in temacs. */
225 new_thread
= (struct thread_state
*) allocate_pseudovector (VECSIZE (struct thread_state
),
227 memset ((char *) new_thread
+ OFFSETOF (struct thread_state
, m_gcprolist
),
228 0, sizeof (struct thread_state
) - OFFSETOF (struct thread_state
,
231 new_thread
->func
= function
;
232 new_thread
->initial_specpdl
= Qnil
;
233 new_thread
->m_current_buffer
= current_thread
->m_current_buffer
;
234 new_thread
->stack_bottom
= &stack_pos
;
236 for (p
= specpdl
; p
!= specpdl_ptr
; ++p
)
240 Lisp_Object sym
= p
->symbol
;
243 new_thread
->initial_specpdl
244 = Fcons (Fcons (sym
, find_symbol_value (sym
)),
245 new_thread
->initial_specpdl
);
249 /* We'll need locking here. */
250 new_thread
->next_thread
= all_threads
;
251 all_threads
= new_thread
;
253 if (pthread_create (&thr
, NULL
, run_thread
, new_thread
))
255 /* Restore the previous situation. */
256 all_threads
= all_threads
->next_thread
;
262 /* Get the current thread as a lisp object. */
264 get_current_thread (void)
267 XSETTHREAD (result
, current_thread
);
271 /* Get the main thread as a lisp object. */
273 get_main_thread (void)
276 XSETTHREAD (result
, &primary_thread
);
280 /* Is the current an user thread. */
284 struct thread_state
*it
= all_threads
;
285 pthread_t self
= pthread_self ();
288 if (it
->pthread_id
== self
)
291 while (it
= it
->next_thread
);
296 DEFUN ("inhibit-yield", Finhibit_yield
, Sinhibit_yield
, 1, 1, 0,
297 doc
: /* Inhibit the yield function. */)
302 inhibit_yield_counter
++;
303 else if (inhibit_yield_counter
> 0)
304 inhibit_yield_counter
--;
311 other_threads_p (void)
313 return all_threads
->next_thread
!= NULL
;
319 pthread_mutex_init (&global_lock
, NULL
);
320 pthread_mutex_lock (&global_lock
);
321 primary_thread
.pthread_id
= pthread_self ();
325 syms_of_threads (void)
327 defsubr (&Srun_in_thread
);
329 defsubr (&Sinhibit_yield
);