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. */)
129 invoke_thread_function (void)
133 int count
= SPECPDL_INDEX ();
135 /* Set up specpdl. */
136 for (iter
= current_thread
->initial_specpdl
;
140 /* We may bind a variable twice -- but it doesn't matter because
141 there is no way to undo these bindings without exiting the
143 specbind (XCAR (XCAR (iter
)), XCDR (XCAR (iter
)));
145 current_thread
->initial_specpdl
= Qnil
;
147 Feval (current_thread
->func
);
148 return unbind_to (count
, Qnil
);
152 do_nothing (Lisp_Object whatever
)
158 run_thread (void *state
)
160 struct thread_state
*self
= state
;
161 struct thread_state
**iter
;
166 self
->stack_top
= self
->stack_bottom
= &stack_pos
;
168 self
->m_specpdl_size
= 50;
169 self
->m_specpdl
= xmalloc (self
->m_specpdl_size
170 * sizeof (struct specbinding
));
171 self
->m_specpdl_ptr
= self
->m_specpdl
;
172 self
->pthread_id
= pthread_self ();
174 /* Thread-local assignment. */
175 current_thread
= self
;
177 pthread_mutex_lock (&global_lock
);
179 /* We need special handling to set the initial buffer. Our parent
180 thread is very likely to be using this same buffer so we will
181 typically wait for the parent thread to release it first. */
182 XSETBUFFER (buffer
, self
->m_current_buffer
);
184 self
->m_current_buffer
= 0;
185 set_buffer_internal (XBUFFER (buffer
));
187 /* It might be nice to do something with errors here. */
188 internal_condition_case (invoke_thread_function
, Qt
, do_nothing
);
190 /* Unlink this thread from the list of all threads. */
191 for (iter
= &all_threads
; *iter
!= self
; iter
= &(*iter
)->next_thread
)
193 *iter
= (*iter
)->next_thread
;
195 release_buffer (self
);
196 xfree (self
->m_specpdl
);
198 pthread_mutex_unlock (&global_lock
);
203 DEFUN ("run-in-thread", Frun_in_thread
, Srun_in_thread
, 1, 1, 0,
204 doc
: /* Start a new thread and run FUNCTION in it.
205 When the function exits, the thread dies. */)
207 Lisp_Object function
;
211 struct thread_state
*new_thread
;
212 struct specbinding
*p
;
214 /* Can't start a thread in temacs. */
218 new_thread
= (struct thread_state
*) allocate_pseudovector (VECSIZE (struct thread_state
),
220 memset ((char *) new_thread
+ OFFSETOF (struct thread_state
, m_gcprolist
),
221 0, sizeof (struct thread_state
) - OFFSETOF (struct thread_state
,
224 new_thread
->func
= function
;
225 new_thread
->initial_specpdl
= Qnil
;
226 new_thread
->m_current_buffer
= current_thread
->m_current_buffer
;
227 new_thread
->stack_bottom
= &stack_pos
;
229 for (p
= specpdl
; p
!= specpdl_ptr
; ++p
)
233 Lisp_Object sym
= p
->symbol
;
236 new_thread
->initial_specpdl
237 = Fcons (Fcons (sym
, find_symbol_value (sym
)),
238 new_thread
->initial_specpdl
);
242 /* We'll need locking here. */
243 new_thread
->next_thread
= all_threads
;
244 all_threads
= new_thread
;
246 if (pthread_create (&thr
, NULL
, run_thread
, new_thread
))
248 /* Restore the previous situation. */
249 all_threads
= all_threads
->next_thread
;
255 /* Get the current thread as a lisp object. */
257 get_current_thread (void)
260 XSETTHREAD (result
, current_thread
);
264 /* Get the main thread as a lisp object. */
266 get_main_thread (void)
269 XSETTHREAD (result
, &primary_thread
);
273 /* Is the current an user thread. */
277 struct thread_state
*it
= all_threads
;
278 pthread_t self
= pthread_self ();
281 if (it
->pthread_id
== self
)
284 while (it
= it
->next_thread
);
289 DEFUN ("inhibit-yield", Finhibit_yield
, Sinhibit_yield
, 1, 1, 0,
290 doc
: /* Inhibit the yield function. */)
295 inhibit_yield_counter
++;
296 else if (inhibit_yield_counter
> 0)
297 inhibit_yield_counter
--;
304 other_threads_p (void)
306 return all_threads
->next_thread
!= NULL
;
312 pthread_mutex_init (&global_lock
, NULL
);
313 pthread_mutex_lock (&global_lock
);
314 primary_thread
.pthread_id
= pthread_self ();
318 syms_of_threads (void)
320 defsubr (&Srun_in_thread
);
322 defsubr (&Sinhibit_yield
);