1 /* Copyright (C) 2002 Free Software Foundation, Inc.
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "libguile/validate.h"
22 #include "libguile/root.h"
23 #include "libguile/stackchk.h"
24 #include "libguile/async.h"
26 #include <sys/types.h>
30 void *scm_null_threads_data
;
32 static SCM main_thread
;
43 scm_threads_init (SCM_STACKITEM
*i
)
45 scm_tc16_thread
= scm_make_smob_type ("thread", 0);
46 scm_tc16_mutex
= scm_make_smob_type ("mutex", sizeof (scm_null_mutex
));
47 scm_tc16_condvar
= scm_make_smob_type ("condition-variable",
48 sizeof (scm_null_cond
));
50 main_thread
= scm_permanent_object (scm_cell (scm_tc16_thread
, 0));
51 scm_null_threads_data
= NULL
;
55 # define SCM_MARK_BACKING_STORE() do { \
57 SCM_STACKITEM * top, * bot; \
59 scm_mark_locations ((SCM_STACKITEM *) &ctx.uc_mcontext, \
60 ((size_t) (sizeof (SCM_STACKITEM) - 1 + sizeof ctx.uc_mcontext) \
61 / sizeof (SCM_STACKITEM))); \
62 bot = (SCM_STACKITEM *) __libc_ia64_register_backing_store_base; \
63 top = (SCM_STACKITEM *) ctx.uc_mcontext.sc_ar_bsp; \
64 scm_mark_locations (bot, top - bot); } while (0)
66 # define SCM_MARK_BACKING_STORE()
70 scm_threads_mark_stacks (void)
72 /* Mark objects on the C stack. */
73 SCM_FLUSH_REGISTER_WINDOWS
;
74 /* This assumes that all registers are saved into the jmp_buf */
75 setjmp (scm_save_regs_gc_mark
);
76 scm_mark_locations ((SCM_STACKITEM
*) scm_save_regs_gc_mark
,
77 ( (size_t) (sizeof (SCM_STACKITEM
) - 1 +
78 sizeof scm_save_regs_gc_mark
)
79 / sizeof (SCM_STACKITEM
)));
82 unsigned long stack_len
= scm_stack_size (scm_stack_base
);
83 #if SCM_STACK_GROWS_UP
84 scm_mark_locations (scm_stack_base
, stack_len
);
86 scm_mark_locations (scm_stack_base
- stack_len
, stack_len
);
89 SCM_MARK_BACKING_STORE();
93 scm_call_with_new_thread (SCM argl
)
94 #define FUNC_NAME s_call_with_new_thread
96 SCM_MISC_ERROR ("threads are not supported in this version of Guile",
103 scm_spawn_thread (scm_t_catch_body body
, void *body_data
,
104 scm_t_catch_handler handler
, void *handler_data
)
106 scm_misc_error ("scm_spawn_thread",
107 "threads are not supported in this version of Guile",
113 scm_current_thread (void)
119 scm_all_threads (void)
121 return scm_list_1 (main_thread
);
125 scm_i_thread_root (SCM thread
)
127 return (scm_root_state
*)scm_null_threads_data
;
131 scm_join_thread (SCM thread
)
132 #define FUNC_NAME s_join_thread
134 SCM_MISC_ERROR ("threads are not supported in this version of Guile",
141 scm_c_thread_exited_p (SCM thread
)
142 #define FUNC_NAME s_scm_thread_exited_p
155 scm_make_mutex (void)
157 SCM m
= scm_make_smob (scm_tc16_mutex
);
158 scm_null_mutex
*mx
= SCM_MUTEX_DATA(m
);
164 scm_lock_mutex (SCM m
)
167 SCM_ASSERT (SCM_MUTEXP (m
), m
, SCM_ARG1
, s_lock_mutex
);
168 mx
= SCM_MUTEX_DATA(m
);
174 scm_try_mutex (SCM m
)
176 return scm_lock_mutex (m
); /* will always succeed right away. */
180 scm_unlock_mutex (SCM m
)
183 SCM_ASSERT (SCM_MUTEXP (m
), m
, SCM_ARG1
, s_unlock_mutex
);
184 mx
= SCM_MUTEX_DATA(m
);
186 scm_misc_error (s_unlock_mutex
, "mutex is not locked", SCM_EOL
);
192 scm_make_condition_variable (void)
195 SCM c
= scm_make_smob (scm_tc16_condvar
);
196 cv
= SCM_CONDVAR_DATA (c
);
201 /* Subtract the `struct timeval' values X and Y,
202 storing the result in RESULT. Might modify Y.
203 Return 1 if the difference is negative or zero, otherwise 0. */
206 timeval_subtract (result
, x
, y
)
207 struct timeval
*result
, *x
, *y
;
209 /* Perform the carry for the later subtraction by updating Y. */
210 if (x
->tv_usec
< y
->tv_usec
) {
211 int nsec
= (y
->tv_usec
- x
->tv_usec
) / 1000000 + 1;
212 y
->tv_usec
-= 1000000 * nsec
;
215 if (x
->tv_usec
- y
->tv_usec
> 1000000) {
216 int nsec
= (x
->tv_usec
- y
->tv_usec
) / 1000000;
217 y
->tv_usec
+= 1000000 * nsec
;
221 /* Compute the time remaining to wait.
222 `tv_usec' is certainly positive. */
223 result
->tv_sec
= x
->tv_sec
- y
->tv_sec
;
224 result
->tv_usec
= x
->tv_usec
- y
->tv_usec
;
226 /* Return 1 if result is negative or zero. */
227 return x
->tv_sec
< y
->tv_sec
228 || (result
->tv_sec
== 0 && result
->tv_usec
== 0);
232 scm_timed_wait_condition_variable (SCM c
, SCM m
, SCM t
)
233 #define FUNC_NAME s_wait_condition_variable
236 struct timeval waittime
;
238 SCM_ASSERT (SCM_CONDVARP (c
),
241 s_wait_condition_variable
);
242 SCM_ASSERT (SCM_MUTEXP (m
),
245 s_wait_condition_variable
);
250 SCM_VALIDATE_UINT_COPY (3, SCM_CAR(t
), waittime
.tv_sec
);
251 SCM_VALIDATE_UINT_COPY (3, SCM_CDR(t
), waittime
.tv_usec
);
255 SCM_VALIDATE_UINT_COPY (3, t
, waittime
.tv_sec
);
256 waittime
.tv_usec
= 0;
260 cv
= SCM_CONDVAR_DATA (c
);
262 scm_unlock_mutex (m
);
263 while (!cv
->signalled
)
266 select (0, NULL
, NULL
, NULL
, NULL
);
269 struct timeval now
, then
, diff
;
271 gettimeofday (&now
, NULL
);
272 if (timeval_subtract (&diff
, &then
, &now
))
274 select (0, NULL
, NULL
, NULL
, &diff
);
289 scm_signal_condition_variable (SCM c
)
292 SCM_ASSERT (SCM_CONDVARP (c
),
295 s_signal_condition_variable
);
296 cv
= SCM_CONDVAR_DATA (c
);
302 scm_broadcast_condition_variable (SCM c
)
304 return scm_signal_condition_variable (c
); /* only one thread anyway. */
308 scm_thread_usleep (unsigned long usec
)
310 struct timeval timeout
;
312 timeout
.tv_usec
= usec
;
313 select (0, NULL
, NULL
, NULL
, &timeout
);
314 return 0; /* Maybe we should calculate actual time slept,
315 but this is faster... :) */
319 scm_thread_sleep (unsigned long sec
)
321 time_t now
= time (NULL
);
322 struct timeval timeout
;
324 timeout
.tv_sec
= sec
;
326 select (0, NULL
, NULL
, NULL
, &timeout
);
327 slept
= time (NULL
) - now
;
328 return slept
> sec
? 0 : sec
- slept
;