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 XSETBUFFER (tem
, thread
->m_current_buffer
);
63 mark_threads_callback (char *end
, void *ignore
)
65 struct thread_state
*iter
;
67 current_thread
->stack_top
= end
;
68 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
70 Lisp_Object thread_obj
;
71 XSETTHREAD (thread_obj
, iter
);
72 mark_object (thread_obj
);
73 mark_one_thread (iter
);
80 flush_stack_call_func (mark_threads_callback
, NULL
);
86 struct thread_state
*iter
;
88 for (iter
= all_threads
; iter
; iter
= iter
->next_thread
)
89 unmark_byte_stack (iter
->m_byte_stack_list
);
93 thread_yield_callback (char *end
, void *ignore
)
95 current_thread
->stack_top
= end
;
96 pthread_mutex_unlock (&global_lock
);
98 pthread_mutex_lock (&global_lock
);
104 /* Note: currently it is safe to check this here, but eventually it
105 will require a lock to ensure non-racy operation. */
106 /* Only yield if there is another thread to yield to. */
107 if (all_threads
->next_thread
)
108 flush_stack_call_func (thread_yield_callback
, NULL
);
111 DEFUN ("yield", Fyield
, Syield
, 0, 0, 0,
112 doc
: /* Yield to the next thread. */)
119 invoke_thread_function (void)
123 int count
= SPECPDL_INDEX ();
125 /* Set up specpdl. */
126 for (iter
= current_thread
->initial_specpdl
;
130 /* We may bind a variable twice -- but it doesn't matter because
131 there is no way to undo these bindings without exiting the
133 specbind (XCAR (XCAR (iter
)), XCDR (XCAR (iter
)));
135 current_thread
->initial_specpdl
= Qnil
;
137 Ffuncall (1, ¤t_thread
->func
);
138 return unbind_to (count
, Qnil
);
142 do_nothing (Lisp_Object whatever
)
148 run_thread (void *state
)
151 struct thread_state
*self
= state
;
152 struct thread_state
**iter
;
156 self
->stack_top
= self
->stack_bottom
= &stack_pos
;
158 self
->m_specpdl_size
= 50;
159 self
->m_specpdl
= xmalloc (self
->m_specpdl_size
160 * sizeof (struct specbinding
));
161 self
->m_specpdl_ptr
= self
->m_specpdl
;
163 /* Thread-local assignment. */
164 current_thread
= self
;
166 pthread_mutex_lock (&global_lock
);
168 /* We need special handling to set the initial buffer. Our parent
169 thread is very likely to be using this same buffer so we will
170 typically wait for the parent thread to release it first. */
171 XSETBUFFER (buffer
, self
->m_current_buffer
);
173 self
->m_current_buffer
= 0;
174 set_buffer_internal (XBUFFER (buffer
));
176 /* It might be nice to do something with errors here. */
177 internal_condition_case (invoke_thread_function
, Qt
, do_nothing
);
179 /* Unlink this thread from the list of all threads. */
180 for (iter
= &all_threads
; *iter
!= self
; iter
= &(*iter
)->next_thread
)
182 *iter
= (*iter
)->next_thread
;
184 release_buffer (self
);
186 xfree (self
->m_specpdl
);
189 pthread_mutex_unlock (&global_lock
);
194 DEFUN ("run-in-thread", Frun_in_thread
, Srun_in_thread
, 1, 1, 0,
195 doc
: /* Start a new thread and run FUNCTION in it.
196 When the function exits, the thread dies. */)
198 Lisp_Object function
;
201 struct thread_state
*new_thread
;
202 struct specbinding
*p
;
204 /* Can't start a thread in temacs. */
208 new_thread
= (struct thread_state
*) allocate_pseudovector (VECSIZE (struct thread_state
),
210 memset ((char *) new_thread
+ OFFSETOF (struct thread_state
, m_gcprolist
),
211 0, sizeof (struct thread_state
) - OFFSETOF (struct thread_state
,
214 new_thread
->func
= function
;
215 new_thread
->initial_specpdl
= Qnil
;
216 new_thread
->m_current_buffer
= current_thread
->m_current_buffer
;
218 for (p
= specpdl
; p
!= specpdl_ptr
; ++p
)
222 Lisp_Object sym
= p
->symbol
;
225 new_thread
->initial_specpdl
226 = Fcons (Fcons (sym
, find_symbol_value (sym
)),
227 new_thread
->initial_specpdl
);
231 /* We'll need locking here. */
232 new_thread
->next_thread
= all_threads
;
233 all_threads
= new_thread
;
235 /* FIXME check result */
236 pthread_create (&thr
, NULL
, run_thread
, new_thread
);
241 /* Get the current thread as a lisp object. */
243 get_current_thread (void)
246 XSETTHREAD (result
, current_thread
);
250 /* Get the main thread as a lisp object. */
252 get_main_thread (void)
255 XSETTHREAD (result
, &primary_thread
);
260 other_threads_p (void)
262 return all_threads
->next_thread
!= NULL
;
268 pthread_mutex_init (&global_lock
, NULL
);
269 pthread_mutex_lock (&global_lock
);
273 syms_of_threads (void)
275 defsubr (&Srun_in_thread
);