5 #include "blockinput.h"
10 void mark_byte_stack
P_ ((struct byte_stack
*));
11 void mark_backtrace
P_ ((struct backtrace
*));
12 void mark_catchlist
P_ ((struct catchtag
*));
13 void mark_stack
P_ ((char *, char *));
14 void flush_stack_call_func
P_ ((void (*) (char *, void *), void *));
16 /* Get the next thread as in circular buffer. */
17 #define NEXT_THREAD(x)(x->next_thread ? x->next_thread : all_threads)
19 /* condition var .. w/ global lock */
21 static pthread_cond_t thread_cond
;
23 static struct thread_state primary_thread
;
25 static struct thread_state
*all_threads
= &primary_thread
;
27 __thread
struct thread_state
*current_thread
= &primary_thread
;
29 static int inhibit_yield_counter
= 0;
31 pthread_mutex_t global_lock
;
33 /* Used internally by the scheduler, it is the next that will be executed. */
34 static pthread_t next_thread
;
36 /* Choose the next thread to be executed. */
40 next_thread
= NEXT_THREAD (current_thread
)->pthread_id
;
43 /* Schedule a new thread and block the caller until it is not scheduled
46 reschedule (char *end
, int wait
)
48 current_thread
->stack_top
= end
;
49 if (!thread_inhibit_yield_p ())
52 if (next_thread
!= current_thread
->pthread_id
)
53 pthread_cond_broadcast (&thread_cond
);
58 pthread_mutex_unlock (&global_lock
);
60 pthread_mutex_lock (&global_lock
);
62 while (current_thread
->pthread_id
!= next_thread
)
63 pthread_cond_wait (&thread_cond
, &global_lock
);
67 mark_one_thread (struct thread_state
*thread
)
69 register struct specbinding
*bind
;
70 struct handler
*handler
;
73 for (bind
= thread
->m_specpdl
; bind
!= thread
->m_specpdl_ptr
; bind
++)
75 mark_object (bind
->symbol
);
76 mark_object (bind
->old_value
);
79 #if (GC_MARK_STACK == GC_MAKE_GCPROS_NOOPS \
80 || GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS)
81 mark_stack (thread
->stack_bottom
, thread
->stack_top
);
84 register struct gcpro
*tail
;
85 for (tail
= thread
->m_gcprolist
; tail
; tail
= tail
->next
)
86 for (i
= 0; i
< tail
->nvars
; i
++)
87 mark_object (tail
->var
[i
]);
91 if (thread
->m_byte_stack_list
)
92 mark_byte_stack (thread
->m_byte_stack_list
);
94 mark_catchlist (thread
->m_catchlist
);
96 for (handler
= thread
->m_handlerlist
; handler
; handler
= handler
->next
)
98 mark_object (handler
->handler
);
99 mark_object (handler
->var
);
102 mark_backtrace (thread
->m_backtrace_list
);
104 if (thread
->m_current_buffer
)
106 XSETBUFFER (tem
, thread
->m_current_buffer
);
110 mark_object (thread
->m_last_thing_searched
);
112 if (thread
->m_saved_last_thing_searched
)
113 mark_object (thread
->m_saved_last_thing_searched
);
117 mark_threads_callback (char *end
, void *ignore
)
119 struct thread_state
*iter
;
121 current_thread
->stack_top
= end
;
122 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
124 Lisp_Object thread_obj
;
125 XSETTHREAD (thread_obj
, iter
);
126 mark_object (thread_obj
);
127 mark_one_thread (iter
);
134 flush_stack_call_func (mark_threads_callback
, NULL
);
138 unmark_threads (void)
140 struct thread_state
*iter
;
142 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
143 if (iter
->m_byte_stack_list
)
144 unmark_byte_stack (iter
->m_byte_stack_list
);
148 thread_inhibit_yield_p ()
150 return inhibit_yield_counter
|| interrupt_input_blocked
|| abort_on_gc
;
154 thread_yield_callback (char *end
, void *ignore
)
156 if (!thread_inhibit_yield_p ())
163 /* Note: currently it is safe to check this here, but eventually it
164 will require a lock to ensure non-racy operation. */
165 /* Only yield if there is another thread to yield to. */
166 if (all_threads
->next_thread
)
167 flush_stack_call_func (thread_yield_callback
, NULL
);
170 DEFUN ("yield", Fyield
, Syield
, 0, 0, 0,
171 doc
: /* Yield to the next thread. */)
175 return other_threads_p () ? Qt
: Qnil
;
179 invoke_thread_function (void)
183 int count
= SPECPDL_INDEX ();
185 /* Set up specpdl. */
186 for (iter
= current_thread
->initial_specpdl
;
190 /* We may bind a variable twice -- but it doesn't matter because
191 there is no way to undo these bindings without exiting the
193 specbind (XCAR (XCAR (iter
)), XCDR (XCAR (iter
)));
195 current_thread
->initial_specpdl
= Qnil
;
197 Feval (current_thread
->func
);
198 return unbind_to (count
, Qnil
);
202 do_nothing (Lisp_Object whatever
)
208 run_thread (void *state
)
210 struct thread_state
*self
= state
;
211 struct thread_state
**iter
;
216 self
->stack_top
= self
->stack_bottom
= &stack_pos
;
218 self
->m_specpdl_size
= 50;
219 self
->m_specpdl
= xmalloc (self
->m_specpdl_size
220 * sizeof (struct specbinding
));
221 self
->m_specpdl_ptr
= self
->m_specpdl
;
222 self
->pthread_id
= pthread_self ();
224 /* Thread-local assignment. */
225 current_thread
= self
;
227 /* We need special handling to set the initial buffer. Our parent
228 thread is very likely to be using this same buffer so we will
229 typically wait for the parent thread to release it first. */
230 XSETBUFFER (buffer
, self
->m_current_buffer
);
232 self
->m_current_buffer
= (struct buffer
*) buffer
;
234 pthread_mutex_lock (&global_lock
);
236 set_buffer_internal (XBUFFER (buffer
));
238 /* It might be nice to do something with errors here. */
239 internal_condition_case (invoke_thread_function
, Qt
, do_nothing
);
241 /* Unlink this thread from the list of all threads. */
242 for (iter
= &all_threads
; *iter
!= self
; iter
= &(*iter
)->next_thread
)
244 *iter
= (*iter
)->next_thread
;
247 pthread_cond_broadcast (&thread_cond
);
249 xfree (self
->m_specpdl
);
251 pthread_mutex_unlock (&global_lock
);
256 DEFUN ("run-in-thread", Frun_in_thread
, Srun_in_thread
, 1, 1, 0,
257 doc
: /* Start a new thread and run FUNCTION in it.
258 When the function exits, the thread dies. */)
260 Lisp_Object function
;
264 struct thread_state
*new_thread
;
265 struct specbinding
*p
;
267 /* Can't start a thread in temacs. */
271 new_thread
= ALLOCATE_PSEUDOVECTOR (struct thread_state
, m_gcprolist
,
273 memset ((char *) new_thread
+ OFFSETOF (struct thread_state
, m_gcprolist
),
274 0, sizeof (struct thread_state
) - OFFSETOF (struct thread_state
,
277 new_thread
->func
= function
;
278 new_thread
->blocked
= 0;
279 new_thread
->initial_specpdl
= Qnil
;
280 new_thread
->m_last_thing_searched
= Qnil
; /* copy from parent? */
281 new_thread
->m_saved_last_thing_searched
= Qnil
;
282 new_thread
->m_current_buffer
= current_thread
->m_current_buffer
;
283 new_thread
->stack_bottom
= &stack_pos
;
285 for (p
= specpdl
; p
!= specpdl_ptr
; ++p
)
289 Lisp_Object sym
= p
->symbol
;
292 new_thread
->initial_specpdl
293 = Fcons (Fcons (sym
, find_symbol_value (sym
)),
294 new_thread
->initial_specpdl
);
298 /* We'll need locking here. */
299 new_thread
->next_thread
= all_threads
;
300 all_threads
= new_thread
;
302 if (pthread_create (&thr
, NULL
, run_thread
, new_thread
))
304 /* Restore the previous situation. */
305 all_threads
= all_threads
->next_thread
;
306 error ("Could not start a new thread");
312 /* Get the current thread as a lisp object. */
314 get_current_thread (void)
317 XSETTHREAD (result
, current_thread
);
321 /* Get the main thread as a lisp object. */
323 get_main_thread (void)
326 XSETTHREAD (result
, &primary_thread
);
330 /* Is the current an user thread. */
334 struct thread_state
*it
= all_threads
;
335 pthread_t self
= pthread_self ();
338 if (it
->pthread_id
== self
)
341 while (it
= it
->next_thread
);
346 DEFUN ("inhibit-yield", Finhibit_yield
, Sinhibit_yield
, 1, 1, 0,
347 doc
: /* Inhibit the yield function. */)
352 inhibit_yield_counter
++;
353 else if (inhibit_yield_counter
> 0)
354 inhibit_yield_counter
--;
360 thread_select (n
, rfd
, wfd
, xfd
, tmo
)
362 SELECT_TYPE
*rfd
, *wfd
, *xfd
;
367 current_thread
->blocked
= 1;
369 reschedule (&end
, 0);
371 pthread_mutex_unlock (&global_lock
);
373 ret
= select (n
, rfd
, wfd
, xfd
, tmo
);
374 current_thread
->blocked
= 0;
376 pthread_mutex_lock (&global_lock
);
377 pthread_cond_broadcast (&thread_cond
);
379 while (current_thread
->pthread_id
!= next_thread
)
380 pthread_cond_wait (&thread_cond
, &global_lock
);
386 other_threads_p (void)
389 struct thread_state
*it
= all_threads
;
390 for (; it
&& avail
< 2; it
= it
->next_thread
)
398 thread_notify_kill_buffer (register struct buffer
*b
)
400 register Lisp_Object tem
;
401 struct thread_state
*it
= all_threads
;
402 for (; it
; it
= it
->next_thread
)
404 if (b
== it
->m_current_buffer
)
406 register Lisp_Object buf
;
407 XSETBUFFER (buf
, it
->m_current_buffer
);
408 tem
= Fother_buffer (buf
, Qnil
, Qnil
);
409 it
->m_current_buffer
= XBUFFER (tem
);
410 if (b
== it
->m_current_buffer
)
419 init_threads_once (void)
421 primary_thread
.size
= PSEUDOVECSIZE (struct thread_state
, m_gcprolist
);
422 primary_thread
.next
= NULL
;
423 primary_thread
.func
= Qnil
;
424 primary_thread
.initial_specpdl
= Qnil
;
425 XSETPVECTYPE (&primary_thread
, PVEC_THREAD
);
431 pthread_mutex_init (&global_lock
, NULL
);
432 pthread_cond_init (&thread_cond
, NULL
);
433 pthread_mutex_lock (&global_lock
);
435 primary_thread
.pthread_id
= pthread_self ();
436 primary_thread
.blocked
= 0;
437 primary_thread
.m_last_thing_searched
= Qnil
;
438 next_thread
= primary_thread
.pthread_id
;
442 syms_of_threads (void)
444 defsubr (&Srun_in_thread
);
446 defsubr (&Sinhibit_yield
);