Skip to content
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

Deadlock - Darwin - Keyboard Event #2

Closed
reppners opened this issue Jun 23, 2014 · 9 comments
Closed

Deadlock - Darwin - Keyboard Event #2

reppners opened this issue Jun 23, 2014 · 9 comments

Comments

@reppners
Copy link

When a keyboard event is handled a deadlock occurs on:
https://github.com/kwhat/libuiohook/blob/master/src/darwin/hook_callback.c#L221

I set up a small sample application in XCode to verify. Mouse events are handled well, but as soon as I hit any key on the keyboard the application doesn't output any further event logs any more.

Traced down to a deadlock in the handling procedure for keyboard events - possibly because a mutex is locked two times and never gets unlocked afterwards. When I pause the application in the debugger it shows a thread waiting at this line for the mutex to be unlocked.

I'm running a MacBook Air on OSX Maverix 10.9.3

Keep up the great work, I'm really glad I found this project :)

@kwhat
Copy link
Owner

kwhat commented Jun 24, 2014

Hi,

Thanks for the report! The double lock should cause the calling thread of the second lock to wait until the mutex is unlocked by some other thread. In this case the callback thread should be waiting for the main runloop to execute the message_port_proc function. Either the main runloop never woke up or something is stuck somewhere in this function. There was another report here about a similar issue, but I can't seem to duplicate it. Are you building from source, if so what version? Could you drop a break-point in one of the functions and see if you can figure out where it gets stuck? Much appreciated, and I am glad you are enjoying the project ;)

@reppners
Copy link
Author

Hi,

I'm building from source with the latest repository version of the master branch.
It is basically your demo_hook application.

I put a breakpoint in the message_port_proc and it never got called.

So this seems to be the issue but I'm not an expert in POSIX-thread programming(did some a few years ago) - can you give me any hints about what I could try? Also on which OSX version are you developing the library? Since it seems to be only a problem on MacBook Air/OSX Maverix so far.

Just for checking I commented out the "event.reserved" if-clause where the mutex is locked and it works just fine this way.

QUICK_FIX: To be able to build I had to make a small change here. I changed this line to:
scancode = keycode_scancode_table[keycode][0];

@kwhat
Copy link
Owner

kwhat commented Jun 24, 2014

Alright, I was able to duplicate the issue on a 10.9 machine I have access to. It looks like the main runloop never gets woken up for some reason. Its more of an Apple thread RunLoop issue.

A little background about what is going on with the code in question: In order to get the char associated with the key that was pressed and the current keyboard layout and language the TIS functions in keycode_to_string need to be called. The problem is that the TIS functions can only be called from the "main CFRunLoop." It looks like start_message_port_runloop was called successfully, so the function should be running on the main CFRunLoop but its not starting because it is not receiving the signal or it terminated after starting for some reason.

On to the bizarre: So the code in question works fine in the parent project on the same computer. The only difference being what thread CFRunLoop start_message_port_runloop gets called from. In the demo application, that runloop is main.

If I was to take a guess, we are signaling message_port_proc to start, but it cannot because main never sleeps correctly in the demo. I am guessing that the ideal solution would be to stop the main run loop if it is active, then execute message_port_proc, and resume the main runloop... I just don't have a clue how to do that yet ;)

@kwhat
Copy link
Owner

kwhat commented Jun 24, 2014

I did a little more digging and I don't believe the main runloop was started correctly in the example, also, that double lock you mentioned earlier should use a condition variable instead of a mutex but thats the smaller of the two issues. The main runloop issues is going to take some reworking to fix. I have a feeling I abused that functionality in new and unique ways.

@reppners
Copy link
Author

Thanks for the details, I start to get a clear picture of whats going on. Got to get used to read C-Code again ;)
I read this Apple Doc about RunLoops. Seems like a powerful tool for thread-programming.
Unfortunately at the moment I don't have enough time to start digging deeper and come up with a valid solution.

@kwhat
Copy link
Owner

kwhat commented Jun 25, 2014

This should work for the demo. The issue is the main run loop never started so you cant wake it up. This code needs some improvement so I am going to leave this bug open for a little while.

# This patch file was generated by NetBeans IDE
# It uses platform neutral UTF-8 encoding and \n newlines.
--- origin/master
+++ HEAD
@@ -91,8 +91,12 @@
        #ifdef _WIN32
        Sleep(100);
        #else
+       #if defined(__APPLE__) && defined(__MACH__)
+       CFRunLoopRun();
+       #else
        nanosleep((struct timespec[]) {{0, 100 * 1000000}}, NULL);
        #endif
+       #endif
    }

    if (hook_is_enabled()) {

@kwhat
Copy link
Owner

kwhat commented Jun 25, 2014

Alright I have pushed some changes that will solve the problem and a check to make sure it wont deadlock. I still need to fix the mutex issue. Have you checked the CPU usage for the program? I am wondering if it is using 100% of one or more cores.

@reppners
Copy link
Author

Checked it out and it works like a charm - awesome!
Also had an eye on CPU usage. Nothing suspicious here.
Great work :)

@kwhat
Copy link
Owner

kwhat commented Jun 25, 2014

Awesome! I did notice that the run loop seems to time out after some short period of inactivity... Keep an eye on it, if you notice it stop working please open a new bug. Thanks again for the report!

@kwhat kwhat closed this as completed Jun 25, 2014
kwhat pushed a commit that referenced this issue Jan 20, 2015
Merging 12th of January 2015
theicfire pushed a commit to theicfire/libuiohook that referenced this issue Jul 3, 2019
Update to new way building and prepare for prebuild using
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

No branches or pull requests

2 participants