-
Notifications
You must be signed in to change notification settings - Fork 278
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
NSRunLoop + dispatch_main_queue = 100% CPU --- SOLVED #378
Comments
I believe calling |
Thanks for the feedback. It's good to know a similar solution has been done on your other project using libdispatch. I'll put in the appropriate #ifdef LINUX_ so that this only happens on Linux. |
Sounds good. Not sure if LINUX includes platforms like Android, so maybe |
LINUX definitely doesn't cover the BSD's, so _WIN32 sounds good. |
The definition of the FD is protected by linux in dispatch/queue.c, I believe because eventfd() is linux-specific (doesn't exist elsewhere). So the corresponding dispatch code only gets executed for defined(linux).
|
Here's what i'm thinking the fix will look like
|
I think that's probably a mistake in dispatch/queue.c since eventfd is not linux specific - at least one BSD system has it too. That may mean that the libdispatch implementation doesn't support BSD unix etc, but if/when it does that code would need to change. I suppose the portable way to handle this would be with an autoconf test to determine how libdispatch is actually operating. For instance it might be using an eventfd on some operating systems and a pipe on other operating systems, so the code might need to use read() (to read from a pipe), and I suppose the number of bytes to be read might vary between systems too. |
Here's the part that uses the FD with If and when other OSs are handled, the watcher would need to handle them too. But for now, linux can operate correctly.
|
(On Linux.)
In programs using AppKit, GUI operations run on the main thread. With libdispatch, it's nice to be able to run GUI ops on the main thread using dispatch syntax
What I observed when I used such a construct with AppKit was that after the first
dispatch_async(dispatch_get_main_queue() ...) callback occurs the CPU usage would go
to 100%.
This is using
with
I had some time to work on this and believe I have solved the problem. NSRunLoop does integrate libdispatch, but does not seem to address what I'm describing.
There is the main NSRunLoop and a subordinate dispatch main run loop. My theory was that "dispatch" was signaling that its runloop needed to run with a file descriptor, and that when it was woken up, the FD was never "cleared", so that NSRunLoop always woke up GSMainQueueDrainer because it thought here was work to do in the dispatch run loop, even when there wasn't.
I believe that the way the dispatch main queue"notifies" the FD is through the function
_dispatch_runloop_queue_class_poke()
, which callseventfd_write(fd, 1)
.(See
and also
The corresponding call to "receive" this event is
eventfd_read(fd, &value)
but this is never called in the libdispatch code. So I believe that the event is "signalled" but never "cleared" and so NSRunLoop keeps trying to satisfy this notification.
I modified the following method to receive the event, and also "clear" the notification by reading it. With the modification, a simple test program that mixes NSRunLoop using AppKit and libdispatch works correctly now. (this small demo suffices https://github.com/sheffler/gnustep-rowcol-layout-examples/tree/main/10-manual-layout)
Tested on Debian 12 Bookworm and Ubuntu 22. Observed 100% CPU without the modification, and low CPU use with it.
I can prepare a pull-request, but i'd like some feedback too if anyone has some.
=== NSRunLoop.m ================
================================================
The text was updated successfully, but these errors were encountered: