Skip to content

Add test for main dispatch queue processing in CFRunLoop #2806

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 30, 2020

Conversation

lxbndr
Copy link
Contributor

@lxbndr lxbndr commented May 26, 2020

This ensures CFRunLoop correctly serves main dispatch queue.

Due to event specifics on Windows there was possibility to break
RunLoop making it think that main queue always has pending
work. The issue is adressed in swiftlang/swift-corelibs-libdispatch#542.

@lxbndr
Copy link
Contributor Author

lxbndr commented May 26, 2020

cc @compnerd

@compnerd
Copy link
Member

@lxbndr would you mind testing with the test but instead of the Foundation change, swiftlang/swift-corelibs-libdispatch#524?

@compnerd
Copy link
Member

I managed to run with the test case, it does pass with the associated PR. I think that we should get the test case added to the test suite still.

@lxbndr
Copy link
Contributor Author

lxbndr commented May 26, 2020

@compnerd You mean swiftlang/swift-corelibs-libdispatch#542, right?
Yes, it works as well. I like that solution, looks like what we need.

One thing feels uncomfortable though. I wanted to place event consumption closer to its processing, because there is, probably, small chance that CFRunLoop will not process Dispatch callout even it sees event raised.

Waiting for events is implemented with MsgWaitForMultipleObjectsEx. It actually waits for 3 or more different objects, as I see. It is Main Queue, RunLoop wakeup timer, and something else. I guess there is (really small) chance that some of them will be triggered simultaneously.

In this case only the first event would be processed, and others would be lost if they are kind of auto-reset events.

@compnerd
Copy link
Member

My understanding is that WaitForMultipleObjectsEx will only reset the event that resulted in the trigger.

@lxbndr
Copy link
Contributor Author

lxbndr commented May 26, 2020

That's right. And this could be a problem. We could be triggered by multiple events, but actually take only one of them for further processing. Would you mind to look into __CFRunLoopWaitForMultipleObjects implementation? Result for our case is set on line 2541.

@compnerd
Copy link
Member

Correct, the other events would trigger WFMO to immediately return the next time around in the loop. You have no guarantees on the order in which the events are handled. Im not sure Im understanding the issue.

@lxbndr
Copy link
Contributor Author

lxbndr commented May 26, 2020

Maybe I am just missing something. Here is step by step scenario I see:

  1. __CFRunLoopRun calls __CFRunLoopWaitForMultipleObjects to get single event to process
  2. __CFRunLoopWaitForMultipleObjects calls WinAPI MsgWaitForMultipleObjectsEx to wait for set of events
  3. MsgWaitForMultipleObjectsEx reports that [event1, event2, event3] are triggered. And auto-resets them, if needed.
  4. __CFRunLoopWaitForMultipleObjects tooks event1 and returns it to __CFRunLoopRun.
  5. __CFRunLoopRun processes event1.

event2 and event3 was reset automatically at step 3, but we didn't process them. They will not trigger MsgWaitForMultipleObjectsEx on next tick.

Am I correct with my conclusion?

@compnerd
Copy link
Member

I see the confusion now. That is not how WFMO functions. It is:

MsgWaitForMultipleObjectsEx will trigger for [event1, event2, event] as 3 discrete events resetting them if they are auto-reset. That is, event2 and event3 are not reset after the initial invocation, and you will need to wait for the next invocation to MsgWaitForMultipleObjectsEx to get the trigger for [event2, event3], the subsequent one giving you event2, and the one after that for event3. If you must immediately handle the 3 events you need to do something like:

for (;;) {
  DWORD dwResult = MsgWaitForMultipleObjectsEx(nCount, ..., 0, ...)
  if (dwResult == WAIT_TIMEOUT) break;
  if (dwResult == WAIT_OBJECT_0 && dwResult <= WAIT_OBJECT_0 + nCount - 1) {
  } else if (dwResult == WAIT_FAILED) {
    fatal("WFMO: %u [LastError: %u]", dwResult, GetLastError());
  }
}

You would also need to handle WAIT_ABANDONED_0..<WAIT_ABANDONED_0+nCount and WAIT_IO_COMPLETION.

@lxbndr
Copy link
Contributor Author

lxbndr commented May 27, 2020

Ah, I see now. Thank you for explanation and perfect solution. Had to re-read the docs thrice. Now I am 100% sure everything will be ok.

This ensures CFRunLoop correctly serves main dispatch queue.

Due to event specifics on Windows there was possibility to break
RunLoop making it think that main queue always has pending
work. The issue is adressed in swiftlang/swift-corelibs-libdispatch#542.
@lxbndr lxbndr force-pushed the calm-down-runloop branch from 1cc5a6d to f480953 Compare May 27, 2020 07:07
@lxbndr lxbndr changed the title [Windows] Fix main dispatch queue processing in CFRunLoop Add test for main dispatch queue processing in CFRunLoop May 27, 2020
@lxbndr lxbndr requested a review from compnerd May 27, 2020 07:09
@lxbndr
Copy link
Contributor Author

lxbndr commented May 27, 2020

Removed ResetEvent and updated PR description.

@compnerd
Copy link
Member

@swift-ci please test

2 similar comments
@spevans
Copy link
Contributor

spevans commented May 28, 2020

@swift-ci please test

@compnerd
Copy link
Member

@swift-ci please test

@compnerd
Copy link
Member

@swift-ci please test Linux platform

@compnerd
Copy link
Member

Thanks for investigating the issue, identifying the problem, and the test case!

@compnerd compnerd merged commit 9d31226 into swiftlang:master May 30, 2020
@lxbndr lxbndr deleted the calm-down-runloop branch May 30, 2020 18:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants