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_yield_callback (char *end
, void *ignore
)
102 if (inhibit_yield_counter
)
105 current_thread
->stack_top
= end
;
106 pthread_mutex_unlock (&global_lock
);
108 pthread_mutex_lock (&global_lock
);
114 /* Note: currently it is safe to check this here, but eventually it
115 will require a lock to ensure non-racy operation. */
116 /* Only yield if there is another thread to yield to. */
117 if (all_threads
->next_thread
)
118 flush_stack_call_func (thread_yield_callback
, NULL
);
121 DEFUN ("yield", Fyield
, Syield
, 0, 0, 0,
122 doc
: /* Yield to the next thread. */)
130 invoke_thread_function (void)
134 int count
= SPECPDL_INDEX ();
136 /* Set up specpdl. */
137 for (iter
= current_thread
->initial_specpdl
;
141 /* We may bind a variable twice -- but it doesn't matter because
142 there is no way to undo these bindings without exiting the
144 specbind (XCAR (XCAR (iter
)), XCDR (XCAR (iter
)));
146 current_thread
->initial_specpdl
= Qnil
;
148 Feval (current_thread
->func
);
149 return unbind_to (count
, Qnil
);
153 do_nothing (Lisp_Object whatever
)
159 run_thread (void *state
)
161 struct thread_state
*self
= state
;
162 struct thread_state
**iter
;
167 self
->stack_top
= self
->stack_bottom
= &stack_pos
;
169 self
->m_specpdl_size
= 50;
170 self
->m_specpdl
= xmalloc (self
->m_specpdl_size
171 * sizeof (struct specbinding
));
172 self
->m_specpdl_ptr
= self
->m_specpdl
;
173 self
->pthread_id
= pthread_self ();
175 /* Thread-local assignment. */
176 current_thread
= self
;
178 pthread_mutex_lock (&global_lock
);
180 /* We need special handling to set the initial buffer. Our parent
181 thread is very likely to be using this same buffer so we will
182 typically wait for the parent thread to release it first. */
183 XSETBUFFER (buffer
, self
->m_current_buffer
);
185 self
->m_current_buffer
= 0;
186 set_buffer_internal (XBUFFER (buffer
));
188 /* It might be nice to do something with errors here. */
189 internal_condition_case (invoke_thread_function
, Qt
, do_nothing
);
191 /* Unlink this thread from the list of all threads. */
192 for (iter
= &all_threads
; *iter
!= self
; iter
= &(*iter
)->next_thread
)
194 *iter
= (*iter
)->next_thread
;
196 release_buffer (self
);
197 xfree (self
->m_specpdl
);
199 pthread_mutex_unlock (&global_lock
);
204 DEFUN ("run-in-thread", Frun_in_thread
, Srun_in_thread
, 1, 1, 0,
205 doc
: /* Start a new thread and run FUNCTION in it.
206 When the function exits, the thread dies. */)
208 Lisp_Object function
;
212 struct thread_state
*new_thread
;
213 struct specbinding
*p
;
215 /* Can't start a thread in temacs. */
219 new_thread
= (struct thread_state
*) allocate_pseudovector (VECSIZE (struct thread_state
),
221 memset ((char *) new_thread
+ OFFSETOF (struct thread_state
, m_gcprolist
),
222 0, sizeof (struct thread_state
) - OFFSETOF (struct thread_state
,
225 new_thread
->func
= function
;
226 new_thread
->initial_specpdl
= Qnil
;
227 new_thread
->m_current_buffer
= current_thread
->m_current_buffer
;
228 new_thread
->stack_bottom
= &stack_pos
;
230 for (p
= specpdl
; p
!= specpdl_ptr
; ++p
)
234 Lisp_Object sym
= p
->symbol
;
237 new_thread
->initial_specpdl
238 = Fcons (Fcons (sym
, find_symbol_value (sym
)),
239 new_thread
->initial_specpdl
);
243 /* We'll need locking here. */
244 new_thread
->next_thread
= all_threads
;
245 all_threads
= new_thread
;
247 if (pthread_create (&thr
, NULL
, run_thread
, new_thread
))
249 /* Restore the previous situation. */
250 all_threads
= all_threads
->next_thread
;
256 /* Get the current thread as a lisp object. */
258 get_current_thread (void)
261 XSETTHREAD (result
, current_thread
);
265 /* Get the main thread as a lisp object. */
267 get_main_thread (void)
270 XSETTHREAD (result
, &primary_thread
);
274 /* Is the current an user thread. */
278 struct thread_state
*it
= all_threads
;
279 pthread_t self
= pthread_self ();
282 if (it
->pthread_id
== self
)
285 while (it
= it
->next_thread
);
290 DEFUN ("inhibit-yield", Finhibit_yield
, Sinhibit_yield
, 1, 1, 0,
291 doc
: /* Inhibit the yield function. */)
296 inhibit_yield_counter
++;
297 else if (inhibit_yield_counter
> 0)
298 inhibit_yield_counter
--;
305 other_threads_p (void)
307 return all_threads
->next_thread
!= NULL
;
313 pthread_mutex_init (&global_lock
, NULL
);
314 pthread_mutex_lock (&global_lock
);
315 primary_thread
.pthread_id
= pthread_self ();
319 syms_of_threads (void)
321 defsubr (&Srun_in_thread
);
323 defsubr (&Sinhibit_yield
);