Task or thread for blocking reads on multiple /dev/input/

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

Task or thread for blocking reads on multiple /dev/input/

Postby MartinH » Fri Jun 26, 2020 8:10 am

Hello community,
I need some design advice for Tasks/Threads in offscreen mode, as well as mouse/keyboard recommondations for windowless mode.

I want to run CEF in windowless mode on a ARM64 system on a Yocto Linux without X or Wayland. I build a simple proof of concept using cefsimple, adding windowless_rendering_enabled=1 and writing my own renderer based on CefRenderHandler. Works so far so good.

I would like to add rudimentary USB mouse and keyboard support for very simple user input. As I have no window manager I have to do this manually (as per my understanding). So I have written small code pieces that basically run endless loops, blocking read on /dev/input/eventX, parse the input and send mouse/keyboard events to the browser class. The code pieces are posted as tasks to TID_FILE_USER_BLOCKING. This however works only for the first posted task, the second task is never started (Execute() never called).
Code: Select all
CefPostTask(TID_FILE_USER_BLOCKING, task_mouse);
CefPostTask(TID_FILE_USER_BLOCKING, task_keyboard);


My questions regarding tasking/threading:
Am I going the wrong way? Can I actually run multiple endless tasks parallel?
Or should I rather create a thread / multiple threads for endless blocking file read loops?
Can someone recommend a CEF thread example?

In addition, if someone can recommend a better solution than writing my own mouse / keyboard handlers without a window manager, your advice would be very appreciated.
Cheers, Martin
MartinH
Techie
 
Posts: 10
Joined: Wed Jun 17, 2020 8:16 am

Re: Task or thread for blocking reads on multiple /dev/input

Postby magreenblatt » Fri Jun 26, 2020 9:36 am

run endless loops, blocking read on /dev/input/eventX

You should use a separate thread for that, or use non-blocking I/O functions without an endless loop (e.g. by posting async tasks to check for more input).
magreenblatt
Site Admin
 
Posts: 12383
Joined: Fri May 29, 2009 6:57 pm

Re: Task or thread for blocking reads on multiple /dev/input

Postby MartinH » Mon Jun 29, 2020 9:00 am

magreenblatt wrote:You should use a separate thread for that, or use non-blocking I/O functions without an endless loop (e.g. by posting async tasks to check for more input).

Thank you for the design cosiderations. I will go for a seperate thread. However as a newbie to CEF I have a hard time wrapping my head around the thread usage in CEF. Is my understanding correct:
Create an extra thread -> Post a task to that thread (here: the endless loop task)?

Code: Select all
// Create and start the evdev thread.
CefRefPtr<CefThread> thread = CefThread::CreateThread("evdev_thread");
if (!thread) {
  perror("failed to create evdev thread");
}
else {
  // Create the task that will be posted to the thread!
  CefRefPtr<CefTask> evDevTask = new EvDevTask("/dev/input/event0", "/dev/input/event1"); // base class: CefTask

  // Run the task on the new thread!
  thread->GetTaskRunner()->PostTask(evDevTask);
}

At/after which point in CEF initialization can I create the thread? When integrating the code into cefsimple example either the application crashes (creation before SimpleApp::OnContextInitialized()) or the new thread blocks the whole application (creation within SimpleApp::OnContextInitialized())?

Any additional code example / reading material regarding CefThread would be appreciated.
MartinH
Techie
 
Posts: 10
Joined: Wed Jun 17, 2020 8:16 am

Re: Task or thread for blocking reads on multiple /dev/input

Postby magreenblatt » Mon Jun 29, 2020 9:39 am

A CefThread can be created on any known CEF thread. In OnContextCreated should be fine.

In the EvDevTask implementation are you performing work only when the Run() method is called? If you set a breakpoint in that method, is it executing on your new thread?
magreenblatt
Site Admin
 
Posts: 12383
Joined: Fri May 29, 2009 6:57 pm

Re: Task or thread for blocking reads on multiple /dev/input

Postby MartinH » Mon Jun 29, 2020 10:58 am

magreenblatt wrote:In the EvDevTask implementation are you performing work only when the Run() method is called?

Yes, only the constructor, destructor and the Execute() functions do work and only Execute() blocks.

Which Run() function are you refering to? As EvDevTask inherits from CefTask I have not implemented a run function, neither am I explicitly calling a run function from CefThread, nor have I used base::Bind() (yet) to connect a callback when the task is done (and I don't expect the task to ever end).
Code: Select all
class EvDevTask : public CefTask {
public:
    EvDevTask(std::string mouseDev, std::string keyboardDev);
    ~EvDevManager();

    // Main endless loop with blocking call to pselect()
    virtual void Execute();

private:
[...]

    IMPLEMENT_REFCOUNTING(EvDevTask);
};

magreenblatt wrote: If you set a breakpoint in that method, is it executing on your new thread?

I haven't tried it yet with a debugger, but when calling CefCurrentlyOn() from the Execute() function it is not on any of the CefThreadId TIDs.
MartinH
Techie
 
Posts: 10
Joined: Wed Jun 17, 2020 8:16 am

Re: Task or thread for blocking reads on multiple /dev/input

Postby magreenblatt » Mon Jun 29, 2020 11:41 am

MartinH wrote:Which Run() function are you refering to?

Sorry, I meant Execute().

MartinH wrote:I haven't tried it yet with a debugger, but when calling CefCurrentlyOn() from the Execute() function it is not on any of the CefThreadId TIDs.

In that case it sounds like you're on a new thread, as expected.

Is the whole application still blocked if you replace the contents of Execute() with something simple like "while(true) { sleep(100); }" ?
magreenblatt
Site Admin
 
Posts: 12383
Joined: Fri May 29, 2009 6:57 pm

Re: Task or thread for blocking reads on multiple /dev/input

Postby MartinH » Tue Jun 30, 2020 2:57 am

magreenblatt wrote:Is the whole application still blocked if you replace the contents of Execute() with something simple like "while(true) { sleep(100); }" ?

Unfortunately yes. I see that the task is running, but the rest of the browser(?) process is not (aka: no browser window appearing).

I have attached a patch demonstrating the minimum changes necessary to cefsimple to demonstrate this. Run as ./cefsimple without(!) --use-views, no browser window will appear.

The patch is based on the spotify binary prebuild cef_binary_83.3.11+g1fac1e5+chromium-83.0.4103.61_linux64. Please ignore the git commit numbers in the patch as they are from a local repo. I have tested the code on x64 Ubuntu 18.04 LTS and on ARM64 with Yocto Linux. (Please Note: I had to rename the patch file as *.c as the forum rejects *.patch files).
Attachments
simple-example-thread-blocking.c
Patch for a simple example of a thread with an endless loop task blocking CEF.
(2.56 KiB) Downloaded 384 times
MartinH
Techie
 
Posts: 10
Joined: Wed Jun 17, 2020 8:16 am

Re: Task or thread for blocking reads on multiple /dev/input

Postby Czarek » Tue Jun 30, 2020 4:37 am

Keep references to thread and simpleTask while they're running. In yours case these are destroyed when OnContextInitialized returns.
Maintainer of the CEF Python, PHP Desktop and CEF C API projects. My LinkedIn.
User avatar
Czarek
Virtuoso
 
Posts: 1927
Joined: Sun Nov 06, 2011 2:12 am

Re: Task or thread for blocking reads on multiple /dev/input

Postby MartinH » Tue Jun 30, 2020 6:40 am

That solved the issue, thank you! Stupid CEF noob error of mine :?

Thanks to you both for your effort and support! Big shoutout to the whole community!

However a side note, the application segfaults if I create the thread already in the SimpleApp constructor. It seems like the CreateThread() method is sensitive to when it is called during the initialization chain. However I can live with that, as it is somewhat to be expected when messing with any framework initialization order :lol:

EDIT: and a follow up question. When I clean away the thread with CefThread::Stop() how does this event reach the task inside the thread? I have not found any suitable API method for that. How can I make sure my task finishes itself for a good cleanup on shutdown... :roll:
MartinH
Techie
 
Posts: 10
Joined: Wed Jun 17, 2020 8:16 am

Re: Task or thread for blocking reads on multiple /dev/input

Postby magreenblatt » Tue Jun 30, 2020 9:35 am

MartinH wrote:When I clean away the thread with CefThread::Stop() how does this event reach the task inside the thread? I have not found any suitable API method for that. How can I make sure my task finishes itself for a good cleanup on shutdown... :roll:

I would suggest using a series of tasks posted to the thread message loop instead of a busy loop. That way calling Stop() will be sufficient by itself. Alternately, you can use a boolean to stop the loop before stopping the thread (either a global variable or a bool* passed to the bound function).
magreenblatt
Site Admin
 
Posts: 12383
Joined: Fri May 29, 2009 6:57 pm

Next

Return to Support Forum

Who is online

Users browsing this forum: Google [Bot] and 61 guests