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 if (thread
->m_current_buffer
)
60 XSETBUFFER (tem
, thread
->m_current_buffer
);
66 mark_threads_callback (char *end
, void *ignore
)
68 struct thread_state
*iter
;
70 current_thread
->stack_top
= end
;
71 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
73 Lisp_Object thread_obj
;
74 XSETTHREAD (thread_obj
, iter
);
75 mark_object (thread_obj
);
76 mark_one_thread (iter
);
83 flush_stack_call_func (mark_threads_callback
, NULL
);
89 struct thread_state
*iter
;
91 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
92 unmark_byte_stack (iter
->m_byte_stack_list
);
96 thread_yield_callback (char *end
, void *ignore
)
98 current_thread
->stack_top
= end
;
99 pthread_mutex_unlock (&global_lock
);
101 pthread_mutex_lock (&global_lock
);
107 /* Note: currently it is safe to check this here, but eventually it
108 will require a lock to ensure non-racy operation. */
109 /* Only yield if there is another thread to yield to. */
110 if (all_threads
->next_thread
)
111 flush_stack_call_func (thread_yield_callback
, NULL
);
114 DEFUN ("yield", Fyield
, Syield
, 0, 0, 0,
115 doc
: /* Yield to the next thread. */)
122 invoke_thread_function (void)
126 int count
= SPECPDL_INDEX ();
128 /* Set up specpdl. */
129 for (iter
= current_thread
->initial_specpdl
;
133 /* We may bind a variable twice -- but it doesn't matter because
134 there is no way to undo these bindings without exiting the
136 specbind (XCAR (XCAR (iter
)), XCDR (XCAR (iter
)));
138 current_thread
->initial_specpdl
= Qnil
;
140 Ffuncall (1, ¤t_thread
->func
);
141 return unbind_to (count
, Qnil
);
145 do_nothing (Lisp_Object whatever
)
151 run_thread (void *state
)
153 struct thread_state
*self
= state
;
158 self
->stack_top
= self
->stack_bottom
= &stack_pos
;
160 self
->m_specpdl_size
= 50;
161 self
->m_specpdl
= xmalloc (self
->m_specpdl_size
162 * sizeof (struct specbinding
));
163 self
->m_specpdl_ptr
= self
->m_specpdl
;
165 /* Thread-local assignment. */
166 current_thread
= self
;
168 pthread_mutex_lock (&global_lock
);
170 /* We need special handling to set the initial buffer. Our parent
171 thread is very likely to be using this same buffer so we will
172 typically wait for the parent thread to release it first. */
173 XSETBUFFER (buffer
, self
->m_current_buffer
);
175 self
->m_current_buffer
= 0;
176 set_buffer_internal (XBUFFER (buffer
));
178 /* It might be nice to do something with errors here. */
179 internal_condition_case (invoke_thread_function
, Qt
, do_nothing
);
181 /* Unlink this thread from the list of all threads. */
182 if (all_threads
== self
)
183 all_threads
= all_threads
->next_thread
;
186 struct thread_state
*prev
;
187 for (prev
= all_threads
; prev
->next_thread
!= self
;
188 prev
= prev
->next_thread
)
190 prev
->next_thread
= self
->next_thread
;
193 release_buffer (self
);
195 pthread_mutex_unlock (&global_lock
);
200 DEFUN ("run-in-thread", Frun_in_thread
, Srun_in_thread
, 1, 1, 0,
201 doc
: /* Start a new thread and run FUNCTION in it.
202 When the function exits, the thread dies. */)
204 Lisp_Object function
;
208 struct thread_state
*new_thread
;
209 struct specbinding
*p
;
211 /* Can't start a thread in temacs. */
215 new_thread
= (struct thread_state
*) allocate_pseudovector (VECSIZE (struct thread_state
),
217 memset ((char *) new_thread
+ OFFSETOF (struct thread_state
, m_gcprolist
),
218 0, sizeof (struct thread_state
) - OFFSETOF (struct thread_state
,
221 new_thread
->func
= function
;
222 new_thread
->initial_specpdl
= Qnil
;
223 new_thread
->m_current_buffer
= current_thread
->m_current_buffer
;
224 new_thread
->stack_bottom
= &stack_pos
;
226 for (p
= specpdl
; p
!= specpdl_ptr
; ++p
)
230 Lisp_Object sym
= p
->symbol
;
233 new_thread
->initial_specpdl
234 = Fcons (Fcons (sym
, find_symbol_value (sym
)),
235 new_thread
->initial_specpdl
);
239 /* We'll need locking here. */
240 new_thread
->next_thread
= all_threads
;
241 all_threads
= new_thread
;
243 if (pthread_create (&thr
, NULL
, run_thread
, new_thread
))
245 /* Restore the previous situation. */
246 all_threads
= all_threads
->next_thread
;
252 /* Get the current thread as a lisp object. */
254 get_current_thread (void)
257 XSETTHREAD (result
, current_thread
);
261 /* Get the main thread as a lisp object. */
263 get_main_thread (void)
266 XSETTHREAD (result
, &primary_thread
);
271 other_threads_p (void)
273 return all_threads
->next_thread
!= NULL
;
279 pthread_mutex_init (&global_lock
, NULL
);
280 pthread_mutex_lock (&global_lock
);
284 syms_of_threads (void)
286 defsubr (&Srun_in_thread
);