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
)
154 struct thread_state
*self
= state
;
155 struct thread_state
**iter
;
159 self
->stack_top
= self
->stack_bottom
= &stack_pos
;
161 self
->m_specpdl_size
= 50;
162 self
->m_specpdl
= xmalloc (self
->m_specpdl_size
163 * sizeof (struct specbinding
));
164 self
->m_specpdl_ptr
= self
->m_specpdl
;
166 /* Thread-local assignment. */
167 current_thread
= self
;
169 pthread_mutex_lock (&global_lock
);
171 /* We need special handling to set the initial buffer. Our parent
172 thread is very likely to be using this same buffer so we will
173 typically wait for the parent thread to release it first. */
174 XSETBUFFER (buffer
, self
->m_current_buffer
);
176 self
->m_current_buffer
= 0;
177 set_buffer_internal (XBUFFER (buffer
));
179 /* It might be nice to do something with errors here. */
180 internal_condition_case (invoke_thread_function
, Qt
, do_nothing
);
182 /* Unlink this thread from the list of all threads. */
183 for (iter
= &all_threads
; *iter
!= self
; iter
= &(*iter
)->next_thread
)
185 *iter
= (*iter
)->next_thread
;
187 release_buffer (self
);
189 xfree (self
->m_specpdl
);
192 pthread_mutex_unlock (&global_lock
);
197 DEFUN ("run-in-thread", Frun_in_thread
, Srun_in_thread
, 1, 1, 0,
198 doc
: /* Start a new thread and run FUNCTION in it.
199 When the function exits, the thread dies. */)
201 Lisp_Object function
;
204 struct thread_state
*new_thread
;
205 struct specbinding
*p
;
207 /* Can't start a thread in temacs. */
211 new_thread
= (struct thread_state
*) allocate_pseudovector (VECSIZE (struct thread_state
),
213 memset ((char *) new_thread
+ OFFSETOF (struct thread_state
, m_gcprolist
),
214 0, sizeof (struct thread_state
) - OFFSETOF (struct thread_state
,
217 new_thread
->func
= function
;
218 new_thread
->initial_specpdl
= Qnil
;
219 new_thread
->m_current_buffer
= current_thread
->m_current_buffer
;
221 for (p
= specpdl
; p
!= specpdl_ptr
; ++p
)
225 Lisp_Object sym
= p
->symbol
;
228 new_thread
->initial_specpdl
229 = Fcons (Fcons (sym
, find_symbol_value (sym
)),
230 new_thread
->initial_specpdl
);
234 /* We'll need locking here. */
235 new_thread
->next_thread
= all_threads
;
236 all_threads
= new_thread
;
238 /* FIXME check result */
239 pthread_create (&thr
, NULL
, run_thread
, new_thread
);
244 /* Get the current thread as a lisp object. */
246 get_current_thread (void)
249 XSETTHREAD (result
, current_thread
);
253 /* Get the main thread as a lisp object. */
255 get_main_thread (void)
258 XSETTHREAD (result
, &primary_thread
);
263 other_threads_p (void)
265 return all_threads
->next_thread
!= NULL
;
271 pthread_mutex_init (&global_lock
, NULL
);
272 pthread_mutex_lock (&global_lock
);
276 syms_of_threads (void)
278 defsubr (&Srun_in_thread
);