[previous] [up] [next]     [contents] [index]
Next: Sleeping by Embedded MzScheme Up: Threads in Embedded MzScheme Previous: Threads in Embedded MzScheme

Callbacks for Blocked Threads

Scheme threads are sometimes blocked on file descriptors, such as an input file or the X event socket. Blocked non-main threads do not block the main thread, and therefore do not affect the event loop, so scheme_check_threads is sufficient to implement this case correctly. However, it is wasteful to poll these descriptors with scheme_check_threads when nothing else is happening in the application and when a lower-level poll on the file descriptors can be installed. If the global function pointer scheme_wakeup_on_input is set, then this case is handled more efficiently by turning off thread checking and issuing a ``wakeup'' request on the blocking file descriptors through scheme_wakeup_on_input. (The scheme_wakeup_on_input function is only used on platforms with file descriptions.)

A scheme_wakeup_on_input procedure takes a pointer to an array of three fd_sets (sortof[footnote]) and returns void. The scheme_wakeup_on_input does not sleep; it just sets up callbacks on the specified file descriptors. When input is ready on any of those file descriptors, the callbacks are be removed and scheme_wake_up is called.

For example, the X Windows version of MrEd formerly set scheme_wakeup_on_input to this MrEdNeedWakeup:

static XtInputId *scheme_cb_ids = NULL;
static int num_cbs;

static void MrEdNeedWakeup(void *fds)
{
  int limit, count, i, p;
  fd_set *rd, *wr, *ex;

  rd = (fd_set *)fds;
  wr = ((fd_set *)fds) + 1;
  ex = ((fd_set *)fds) + 2;

  limit = getdtablesize();

  /* See if we need to do any work, really: */
  count = 0;
  for (i = 0; i < limit; i++) {
    if (MZ_FD_ISSET(i, rd))
      count++;
    if (MZ_FD_ISSET(i, wr))
      count++;
    if (MZ_FD_ISSET(i, ex))
      count++;
  }

  if (!count)
    return;

  /* Remove old callbacks: */
  if (scheme_cb_ids)
    for (i = 0; i < num_cbs; i++)
      notify_set_input_func((Notify_client)NULL, (Notify_func)NULL, 
                            scheme_cb_ids[i]);

  num_cbs = count;
  scheme_cb_ids = new int[num_cbs];

  /* Install callbacks */
  p = 0;
  for (i = 0; i < limit; i++) {
    if (MZ_FD_ISSET(i, rd))
      scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i, 
                                         (XtPointer *)XtInputReadMask, 
                                         (XtInputCallbackProc)MrEdWakeUp, NULL);
    if (MZ_FD_ISSET(i, wr))
      scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i, 
                                         (XtPointer *)XtInputWriteMask, 
                                         (XtInputCallbackProc)MrEdWakeUp, NULL);
    if (MZ_FD_ISSET(i, ex))
      scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i, 
                                         (XtPointer *)XtInputExceptMask, 
                                         (XtInputCallbackProc)MrEdWakeUp, 
                                         NULL);
  }
}

/* callback function when input/exception is detected: */
Bool MrEdWakeUp(XtPointer, int *, XtInputId *)
{
  int i;

  if (scheme_cb_ids) {
    /* Remove all callbacks: */
    for (i = 0; i < num_cbs; i++)
     XtRemoveInput(scheme_cb_ids[i]);

    scheme_cb_ids = NULL;
    
    /* ``wake up'' */
    scheme_wake_up();
  }

  return FALSE;
}



PLT