Skip to content

On Windows, call some equivalent to R_PolledEvents #1187

@DavisVaughan

Description

@DavisVaughan

See #1180 for more

On Unix we override R_PolledEvents() with

libr::set(R_PolledEvents, Some(r_polled_events));

We can't do this on Windows, this concept does not exist there.

There are 2 places on a Unix system where R_PolledEvents() is really called from that we are missing right now on Windows:

  • R_ProcessEvents() -> R_PolledEvents()`

    • Used in many places, but the main one is from R_CheckUserInterrupt()
    • So on Windows I think our polled events aren't ever running at R_CheckUserInterrupt() time
  • R_runHandlers() -> R_PolledEvents()

    • R_runHandlers() is a unix concept as well
    • Sys.sleep() -> Rsleep() -> R_runHandlers() -> R_PolledEvents()
      • But Rsleep() on Unix also calls R_CheckUserInterrupt(), so using R_ProcessEvents() would work here
      • And Rsleep() on Windows directly calls R_ProcessEvents()

I think for the most part this isn't the end of the world. For tasks that typically get run in polled_events() at interrupt time, they instead get run in the main run_event_loop() at idle time.

But we do do this in polled_events() which isn't replicated elsewhere

        if let Some(text) = self.debug_filter.check_timeout() {
            self.emit_stdout(text);
        }

We could consider removing our polled_events() hook altogether. If it isn't being invoked on Windows right now, how useful is it really? That would force us to remove interrupt tasks as a concept altogether, something we have been interested in. It would be worth finding a case where interrupt tasks are very useful on Mac that we are currently lacking on Windows before discarding this idea.

If we want to keep interrupt tasks, on both OSes, we have access to hook into R_ProcessEvents():

  • Unix: ptr_R_ProcessEvents, settable at any moment
  • Windows: Rp->Callback which sets a static ptr_ProcessEvents, settable only at startup

We'd have to reconcile the fact that we can't set Rp->Callback at any moment on windows, meaning RLocalPolledEventsSuspended wouldn't be precisely reproducible for process events, but maybe we could have a global atomic boolean that we flip instead, and our callback would just bail if that is set to false (i.e. suspended).

We also would need to reconcile with the fact that we currently manually call R_ProcessEvents(), and typically we seem to be expecting that tasks dont run at that time (i.e. the comment says we are typically suspended), so that might need some thinking as well

    fn process_idle_events() {
        // Process regular R events. We're normally running with polled
        // events disabled so that won't run here. We also run with
        // interrupts disabled, so on Windows those won't get run here
        // either (i.e. if `UserBreak` is set), but it will reset `UserBreak`
        // so we need to ensure we handle interrupts right before calling
        // this.
        unsafe { R_ProcessEvents() };

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions