* libguile/threads.c (timed_wait): When looping to reacquire mutex,
check if mutex owner after dropping mutex to run asyncs when the
reacquire is interrupted.
Also for asyncs that interrupted the initial wait, just return #t
directly, and allow the caller to loop. Fixes a deadlock in which a
thread could have pending asyncs after dropping a mutex and which
prevent it from going to wait on a cond, but then the broadcast comes
while nobody is waiting and the mutex is dropped, then after
reacquiring the mutex when we go to wait again, we wait forever.
The correct thing to do is after reacquiring the mutex, to allow the
application to check if waiting is appropriate.
* libguile/root.h:
* libguile/root.c: Remove these files.
* libguile/deprecated.h:
* libguile/deprecated.c (scm_internal_cwdr, scm_call_with_dynamic_root)
(scm_dynamic_root, scm_apply_with_dynamic_root): Deprecate.
Remove all root.h usage, which was vestigial.
* module/ice-9/serialize.scm: Use (current-thread) instead
of (dynamic-root).
* module/ice-9/threads.scm (join-thread): Implement in Scheme.
(call-with-new-thread): Arrange to record values in a weak table and
signal the join cond.
(with-mutex): Move up definition; call-with-new-thread needs it. (How
was this working before?)
* libguile/threads.c (guilify_self_1, guilify_self_2, do_thread_exit):
Remove join queue management.
* libguile/threads.c (scm_join_thread, scm_join_thread_timed): Call out
to Scheme.
(scm_init_ice_9_threads): Capture join-thread var.
* libguile/throw.h (scm_i_make_catch_body_closure)
(scm_i_make_catch_handler_closure): Add scm_i_ prefix and make
available for internal use.
* libguile/throw.c: Adapt.
* libguile/threads.c (scm_spawn_thread): Rewrite in terms of
scm_call_with_new_thread.
* libguile/threads.c (lock_mutex, scm_timed_lock_mutex): As with
unlock_mutex before, optimize by specializing to the mutex kind.
Also, avoid lock thrashing after a return from block_self.
* libguile/threads.c (scm_timed_lock_mutex): Use "level" field only for
recursive mutexes.
(unlock_mutex, scm_unlock_mutex): Factor implementation back out of
scm_unlock_mutex (doh?), but in such a way that can specialize against
mutex type.
(scm_mutex_level): Only look at level for recursive mutexes.
(scm_mutex_locked_p): Look at owner field, not level field.
(timed_wait, scm_timed_wait_condition_variable): Factor implementation
out, as above with unlock-mutex. Specialize relocking of the Guile
mutex.
* libguile/threads.c (scm_unlock_mutex): Bind to unlock-mutex.
* libguile/threads.h: Remove scm_unlock_mutex_timed.
* libguile/deprecated.h: Add scm_unlock_mutex_timed.
* libguile/deprecated.c (scm_unlock_mutex_timed): Deprecate.
* test-suite/tests/threads.test: Update unlock-mutex tests to use
wait-condition-variable if they would wait on a cond.
* libguile/threads.c (enum fat_mutex_kind): New data type, replacing
separate flags.
(struct fat_mutex): Adapt.
(make_fat_mutex): Fat mutexes can only be one of three kinds, not one
of 4 kinds. (Recursive unowned mutexes are not a thing.)
(scm_make_mutex): Adapt.
(scm_make_mutex_with_kind): New function, replacing
scm_make_mutex_with_flags. Still bound to make-mutex.
(scm_make_recursive_mutex): Adapt.
(fat_mutex_lock, fat_mutex_unlock): Adapt.
* libguile/threads.h (scm_make_mutex_with_kind): New decl.
* libguile/deprecated.h:
* libguile/deprecated.c (scm_make_mutex_with_flags): Deprecate.
* libguile/threads.c (fat_mutex_lock): allow-external-unlock mutexes
can't be recursive, but a recursive lock attempt can be unblocked by
an external thread, so these mutexes shouldn't throw an error on
recursive lock attempts.
* test-suite/tests/srfi-18.test: Add tests.
* libguile/threads.h (scm_i_thread):
* libguile/threads.c (guilify_self_1, on_thread_exit)
(scm_pthread_cond_wait, scm_pthread_cond_timedwait): The thread-local
held_mutex field is no longer needed, now that we cancel threads via
interrupts instead of pthread_cancel.
* module/ice-9/threads.scm (cancel-tag): New variable.
(cancel-thread): New Scheme function.
(call-with-new-thread): Install a prompt around the thread.
* libguile/threads.h (scm_i_thread): Remove cancelled member.
* libguile/threads.c (scm_cancel_thread): Call out to Scheme. Always
available, and works on the current thread too.
(scm_set_thread_cleanup_x, scm_thread_cleanup): Adapt.
(scm_init_ice_9_threads): Capture cancel-thread var.
* doc/ref/api-scheduling.texi (Threads): Update.
* NEWS: Update.
* libguile/__scm.h (SCM_TICK): Always define as scm_async_tick().
* libguile/error.c (scm_syserror, scm_syserror_msg):
* libguile/fports.c (fport_read, fport_write):
* libguile/_scm.h (SCM_SYSCALL): Replace SCM_ASYNC_TICK with
scm_async_tick ().
(SCM_ASYNC_TICK, SCM_ASYNC_TICK_WITH_CODE)
(SCM_ASYNC_TICK_WITH_GUARD_CODE): Remove internal definitions. We
inline into vm-engine.c, the only place where it matters.
* libguile/async.h:
* libguile/async.c (scm_async_tick, scm_i_setup_sleep):
(scm_i_reset_sleep, scm_system_async_mark_for_thread):
* libguile/threads.h (struct scm_thread_wake_data):
* libguile/threads.h (scm_i_thread):
* libguile/threads.c (block_self, guilify_self_1, scm_std_select):
Rewrite to use sequentially-consistent atomic references.
* libguile/atomics-internal.h (scm_atomic_set_pointer):
(scm_atomic_ref_pointer): New definitions.
* libguile/finalizers.c (queue_finalizer_async): We can allocate, so
just use scm_system_async_mark_for_thread instead of the set-cdr!
shenanigans.
* libguile/scmsigs.c (take_signal):
* libguile/gc.c (queue_after_gc_hook): Adapt to new asyncs mechanism.
Can't allocate but we're just manipulating the current thread when no
other threads are running so we should be good.
* libguile/vm-engine.c (VM_HANDLE_INTERRUPTS): Inline the async_tick
business.
Reported by Sylvain Beucler <beuc@beuc.net>.
* configure.ac: Check for 'pthread_cancel'.
* libguile/threads.c (scm_cancel_thread): Conditionalize on
!SCM_USE_PTHREAD_THREADS || defined HAVE_PTHREAD_CANCEL.
* test-suite/tests/threads.test (require-cancel-thread): New procedure.
("timed joining fails if timeout exceeded", "join-thread returns
timeoutval on timeout", "cancel succeeds", "handler result passed to
join", "can cancel self"): Use it.
* libguile/threads.c (thread_mark): There is a window in which the
thread has a handle but doesn't yet have the set of pointerless
freelists, so don't unconditionally dereference
t->pointerless_freelists.
* libguile/iselect.h:
* libguile/threads.c:
* libguile/deprecated.h: Rely on Gnulib for sys/select.h.
* libguile/filesys.c: Rely on Gnulib for 'lstat' and 'mkstemp'.
* libguile/bdw-gc.h: Remove a needless compatibility hack.
* libguile/gc-inline.h: New file, implementing thread-local freelists
providing faster allocation if we already have a scm_i_thread*
pointer. Based on gc_inline.h from libgc.
* libguile/threads.h (scm_i_thread): Add freelists here.
* libguile/threads.c (guilify_self_1, guilify_self_2): Initialize
freelists.
* libguile/vm.c: Include gc-inline.h.
* libguile/vm-engine.c: Rename current_thread to thread. Use
scm_inline_cons instead of scm_cons, scm_inline_cell instead of
scm_cell, and scm_inline_words instead of words.
* libguile/threads.c (thread_mark): Mark the VM stack, if we have one.
(on_thread_exit): Free the VM stack here.
* libguile/vm.c (make_vm): Allocate the VM stack using mmap, and arrange
for it to be marked by the thread marker.
(scm_i_vm_mark_stack, scm_i_vm_free_stack): New internal interfaces.
(allocate_stack, free_stack): New helpers.
* libguile/threads.c (thread_mark): A mark procedure for threads.
Eventually will mark the stack.
(guilify_self_1): Move initialization of VP earlier. Allocate thread
using thread_gc_kind.
(scm_threads_prehistory): Initialize thread_gc_kind.
Reported and debugged by Andrew Gaylard <ag@computer.org>.
* libguile/threads.c (remqueue): When removing the last element from a
queue with more than one element, set (car q) to the previous element.
* THANKS: Thank Andrew Gaylard.