summaryrefslogtreecommitdiff
path: root/libguile/async.c
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2016-12-29 18:46:16 +0100
committerAndy Wingo <wingo@pobox.com>2016-12-29 18:46:16 +0100
commita0656ad4cf976b3845e9b9663a90b46b4cf9fc5a (patch)
tree22e621b5b32acb84fcbd82b1b7ff7d7f9e303740 /libguile/async.c
parent0ce8a9a5e01d3a12d83fea85968e1abb602c9298 (diff)
downloadguile-a0656ad4cf976b3845e9b9663a90b46b4cf9fc5a.tar.gz
New interfaces to help wait on fd/cond
* libguile/async.h: * libguile/async.c (struct scm_thread_wake_data): Include the cond to signal. Be a union and include a tag. (scm_i_prepare_to_wait): Rename from scm_i_setup_sleep and take wake data directly. Also call scm_i_wait_finished as appropriate. (scm_i_wait_finished): Rename from scm_i_reset_sleep. (scm_i_prepare_to_wait_on_fd, scm_c_prepare_to_wait_on_fd): (scm_i_prepare_to_wait_on_cond, scm_c_prepare_to_wait_on_cond): New functions. (scm_c_wait_finished): New function. (scm_system_async_mark_for_thread): Adapt to wake data change. * libguile/threads.c (block_self, scm_std_select): Adapt to async interface changes. * doc/ref/api-scheduling.texi (Asyncs): Doc new public interfaces.
Diffstat (limited to 'libguile/async.c')
-rw-r--r--libguile/async.c98
1 files changed, 75 insertions, 23 deletions
diff --git a/libguile/async.c b/libguile/async.c
index df8064107..7b3ccb850 100644
--- a/libguile/async.c
+++ b/libguile/async.c
@@ -149,30 +149,81 @@ scm_async_tick (void)
}
struct scm_thread_wake_data {
- scm_i_pthread_mutex_t *mutex;
- int fd;
+ enum { WAIT_FD, WAIT_COND } kind;
+ union {
+ struct {
+ int fd;
+ } wait_fd;
+ struct {
+ scm_i_pthread_mutex_t *mutex;
+ scm_i_pthread_cond_t *cond;
+ } wait_cond;
+ } data;
};
int
-scm_i_setup_sleep (scm_i_thread *t,
- scm_i_pthread_mutex_t *sleep_mutex,
- int sleep_fd)
+scm_i_prepare_to_wait (scm_i_thread *t,
+ struct scm_thread_wake_data *wake)
{
- struct scm_thread_wake_data *wake;
+ scm_atomic_set_pointer ((void **)&t->wake, wake);
+
+ /* If no interrupt was registered in the meantime, then any future
+ wakeup will signal the FD or cond var. */
+ if (scm_is_null (scm_atomic_ref_scm (&t->pending_asyncs)))
+ return 0;
+
+ /* Otherwise clear the wake pointer and indicate that the caller
+ should handle interrupts directly. */
+ scm_i_wait_finished (t);
+ return 1;
+}
+void
+scm_i_wait_finished (scm_i_thread *t)
+{
+ scm_atomic_set_pointer ((void **)&t->wake, NULL);
+}
+
+int
+scm_i_prepare_to_wait_on_fd (scm_i_thread *t, int fd)
+{
+ struct scm_thread_wake_data *wake;
wake = scm_gc_typed_calloc (struct scm_thread_wake_data);
- wake->mutex = sleep_mutex;
- wake->fd = sleep_fd;
+ wake->kind = WAIT_FD;
+ wake->data.wait_fd.fd = fd;
+ return scm_i_prepare_to_wait (t, wake);
+}
- scm_atomic_set_pointer ((void **)&t->wake, wake);
+int
+scm_c_prepare_to_wait_on_fd (int fd)
+{
+ return scm_i_prepare_to_wait_on_fd (SCM_I_CURRENT_THREAD, fd);
+}
+
+int
+scm_i_prepare_to_wait_on_cond (scm_i_thread *t,
+ scm_i_pthread_mutex_t *m,
+ scm_i_pthread_cond_t *c)
+{
+ struct scm_thread_wake_data *wake;
+ wake = scm_gc_typed_calloc (struct scm_thread_wake_data);
+ wake->kind = WAIT_COND;
+ wake->data.wait_cond.mutex = m;
+ wake->data.wait_cond.cond = c;
+ return scm_i_prepare_to_wait (t, wake);
+}
- return !scm_is_null (scm_atomic_ref_scm (&t->pending_asyncs));
+int
+scm_c_prepare_to_wait_on_cond (scm_i_pthread_mutex_t *m,
+ scm_i_pthread_cond_t *c)
+{
+ return scm_i_prepare_to_wait_on_cond (SCM_I_CURRENT_THREAD, m, c);
}
void
-scm_i_reset_sleep (scm_i_thread *t)
+scm_c_wait_finished (void)
{
- scm_atomic_set_pointer ((void **)&t->wake, NULL);
+ scm_i_wait_finished (SCM_I_CURRENT_THREAD);
}
SCM_DEFINE (scm_system_async_mark_for_thread, "system-async-mark", 1, 1, 0,
@@ -210,19 +261,18 @@ SCM_DEFINE (scm_system_async_mark_for_thread, "system-async-mark", 1, 1, 0,
might even be in the next, unrelated sleep. Interrupting it
anyway does no harm, however.
- The important thing to prevent here is to signal sleep_cond
- before T waits on it. This can not happen since T has
- sleep_mutex locked while setting t->sleep_mutex and will only
- unlock it again while waiting on sleep_cond.
+ The important thing to prevent here is to signal the cond
+ before T waits on it. This can not happen since T has its
+ mutex locked while preparing the wait and will only unlock it
+ again while waiting on the cond.
*/
- if (wake->mutex)
+ if (wake->kind == WAIT_COND)
{
- scm_i_scm_pthread_mutex_lock (wake->mutex);
- scm_i_pthread_cond_signal (&t->sleep_cond);
- scm_i_pthread_mutex_unlock (wake->mutex);
+ scm_i_scm_pthread_mutex_lock (wake->data.wait_cond.mutex);
+ scm_i_pthread_cond_signal (wake->data.wait_cond.cond);
+ scm_i_pthread_mutex_unlock (wake->data.wait_cond.mutex);
}
-
- if (wake->fd >= 0)
+ else if (wake->kind == WAIT_FD)
{
char dummy = 0;
@@ -231,8 +281,10 @@ SCM_DEFINE (scm_system_async_mark_for_thread, "system-async-mark", 1, 1, 0,
not yet have started sleeping, but this is no problem
either since the data written to a pipe will not be lost,
unlike a condition variable signal. */
- full_write (wake->fd, &dummy, 1);
+ full_write (wake->data.wait_fd.fd, &dummy, 1);
}
+ else
+ abort ();
}
return SCM_UNSPECIFIED;