1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 03:40:34 +02:00

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.
This commit is contained in:
Andy Wingo 2016-12-29 18:46:16 +01:00
parent 0ce8a9a5e0
commit a0656ad4cf
4 changed files with 142 additions and 56 deletions

View file

@ -149,32 +149,83 @@ 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;
wake = scm_gc_typed_calloc (struct scm_thread_wake_data);
wake->mutex = sleep_mutex;
wake->fd = sleep_fd;
scm_atomic_set_pointer ((void **)&t->wake, wake);
return !scm_is_null (scm_atomic_ref_scm (&t->pending_asyncs));
/* 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_reset_sleep (scm_i_thread *t)
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->kind = WAIT_FD;
wake->data.wait_fd.fd = fd;
return scm_i_prepare_to_wait (t, 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);
}
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_c_wait_finished (void)
{
scm_i_wait_finished (SCM_I_CURRENT_THREAD);
}
SCM_DEFINE (scm_system_async_mark_for_thread, "system-async-mark", 1, 1, 0,
(SCM proc, SCM thread),
"Mark @var{proc} (a procedure with zero arguments) for future execution\n"
@ -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;