xlib vs usleep

Programming applications for making music on Linux.

Moderators: MattKingUSA, khz

User avatar
skei
Established Member
Posts: 343
Joined: Sun May 18, 2014 4:24 pm
Has thanked: 8 times
Been thanked: 58 times
Contact:

xlib vs usleep

Post by skei »

i'm going through the low levels of my plugin framework now, tying up some loose ends, fixing some of the "todo" stuff..

i have a gui thread like this:

Code: Select all

#define SKEI_LINUX_THREADPROC_IDLESLEEP 30

void* skei_xlib_threadproc(void* AData) {
  SWindow_Xlib* win = (SWindow_Xlib*)AData;
  if (win) {
    while (win->MEventThreadActive) {
      while (XPending(win->MDisplay) > 0) {
        XEvent ev;
        XNextEvent(win->MDisplay, &ev);
        win->eventHandler(&ev);
      }
      win->sendEvent(sts_idle);
      usleep( SKEI_LINUX_THREADPROC_IDLESLEEP * 1000);
    }
  }
  return SKEI_NULL;
}
this seems to work quite well.. but i'm wondering.. what happens if xlib sends events to my window when the thread is sleeping? will it wake up, or will it sleep through the full 30ms, before waking up and checking for new events?

or is there a better way to do this?

- tor-helge
tramp
Established Member
Posts: 2347
Joined: Mon Jul 01, 2013 8:13 am
Has thanked: 9 times
Been thanked: 466 times

Re: xlib vs usleep

Post by tramp »

usleep is deprecated now, you should use nanosleep instead.
4.3BSD, POSIX.1-2001. POSIX.1-2001 declares this function obsolete; use nanosleep(2) instead. POSIX.1-2008 removes the specification of usleep().
On the road again.
User avatar
skei
Established Member
Posts: 343
Joined: Sun May 18, 2014 4:24 pm
Has thanked: 8 times
Been thanked: 58 times
Contact:

Re: xlib vs usleep

Post by skei »

ok, thanks..
will change to nanosleep..
- th
j_e_f_f_g
Established Member
Posts: 2032
Joined: Fri Aug 10, 2012 10:48 pm
Been thanked: 358 times

Re: xlib vs usleep

Post by j_e_f_f_g »

skei wrote:will it sleep through the full 30ms, before waking up and checking for new events? is there a better way to do this?
Yes and yes. Do it like this:

Code: Select all

void skei_xlib_threadabort(void* AData) {
  SWindow_Xlib* win = (SWindow_Xlib*)AData;
  if (win) {
    register void *display;
    XClientMessageEvent	xevent;

    win->MEventThreadActive = 0;

    // Signal gui thread by sending it a
    // ClientMessage with 1000 as the message_type.
    // X Windows sucks! Kill the idiot who thought up the idea of
    // fracturing the UI between two systems, and therefore requiring
    // a foolish "display handle" -- especially one that isn't good
    // between threads!
    xevent.type = ClientMessage;
    xevent.message_type = 1000;
    xevent.format = 32;
    display = XOpenDisplay(0);
    XSendEvent(display, win->MWindow, 0, 0, (XEvent *)&xevent);
    XCloseDisplay(display);
  }
}

void* skei_xlib_threadproc(void* AData) {
  SWindow_Xlib* win = (SWindow_Xlib*)AData;
  if (win) {
    while (win->MEventThreadActive) {
        XEvent ev;
        XNextEvent(win->MDisplay, &ev);
        {
            register XClientMessageEvent *  evt;

            evt = (XClientMessageEvent *)&ev;
            if (evt->message_type != 1000)
                  win->eventHandler(&ev);
        }
    }
  }
  return SKEI_NULL;
}
Make sure your window is set to receive clientmessage signals:

Code: Select all

XSelectInput(Display, Window, ExposureMask|StructureNotifyMask|ButtonPressMask|ButtonReleaseMask|KeyPressMask);
Call skei_xlib_threadabort from your thread that aborts the gui thread, Then throw away this code for Wayland.

Author of BackupBand at https://sourceforge.net/projects/backupband/files/
My fans show their support by mentioning my name in their signature.

User avatar
skei
Established Member
Posts: 343
Joined: Sun May 18, 2014 4:24 pm
Has thanked: 8 times
Been thanked: 58 times
Contact:

Re: xlib vs usleep

Post by skei »

i think i might have been describing my question poorly.. :-/
the problem is not communicating with, or terminating the thread(s)..
that works well, and i haven't been able to crash or hang the plugins in any of the hosts i've tested them in, no matter how much i try..
i just wondered what (if anything) would make the thread wake up from sleeping..

but after thinking more about it, i realized that we're not 'sent' xlib events, we're polling for them, so of course we aren't awakened by any of these incoming events.. we don't know about them until we ask for them.. and while the thread is sleeping, there's no such asking.. :-)

the thing i wanted to get rid of, was the 'latency', the possibly longest time from a parameter is automated by the host, until the thread receives the events and finally updates the widget on screen.. the thread might just have gone to sleep, and won't wake up until 30 ms later.. but when it does, all pending ewvents are handlede, before it goes to sleep again.. so, it handles events in 'chunks' with a 30 ms (or whatever) granularity.. if i tweak the sliders/buttons/etc on the gui manually, i redraw them immediately, so it's only the host -> editor latency that is max 30 ms (or whatever i set the idle/refresh rate to)..

the code is for the editor in a vst plugin (standalone executables use a little different scheme), and my library is completely lock/wait-free, so there's some specific restrictions and things i have to watch out for, thread communication, concurrency, etc, and also, different vst hosts call effEditIdle at very different intervals (i think qtractor calls it only around 5-6 times per second, or something).. that's why i want this idle/timer thing in there, to be sure i have the same smooth animation and response in all hosts..

but, i have been thinking about the issue a bit, looked through my code, checking and rechecking details, reading xlib specs, etc.. and i think that the current scheme works quite well..
i just successfully tested the 64-bit version in: bitwig, qtractor, carla, ardour... 32 bit version tested in: carla, bitwig
and everything seems ok...

anyway, thanks for suggestions and comments..
i will now focus more on the audio- and plugin-specific code again..
and will post a bunch of plugins pretty soon..

- tor-helge

btw: a filesize of around 80k for a 64-bit vst plugin with gui isn't too bad, is it?
j_e_f_f_g
Established Member
Posts: 2032
Joined: Fri Aug 10, 2012 10:48 pm
Been thanked: 358 times

Re: xlib vs usleep

Post by j_e_f_f_g »

skei wrote:i just wondered what (if anything) would make the thread wake up from sleeping..
Um... that's exactly what my code does. Sending a ClientMessage to the window causes XNextEvent to return (with that message). There's no need to poll (XPending) nor sleep (which is a bad thing in a gui thread).

Use my code. It's the correct way to do what you're trying to do. In fact, a XClientMessageEvent struct has several additional long fields you can use to pass any data you like. After all, the purpose of a XClientMessageEvent is for app-specific communication with a gui thread. For example:

Code: Select all

#define MY_COMMAND_1 1000
#define MY_COMMAND_2 1001

xevent.type = ClientMessage;
xevent.message_type = MY_COMMAND_1;
xevent.format = 32;
xevent.data.l[0] = MyLong1;
xevent.data.l[1] = MyLong2;
XSendEvent(display, win->MWindow, 0, 0, (XEvent *)&xevent);

xevent.type = ClientMessage;
xevent.message_type = MY_COMMAND_2;
XSendEvent(display, win->MWindow, 0, 0, (XEvent *)&xevent);
And in your gui thread:

Code: Select all

XEvent ev;
XNextEvent(win->MDisplay, &ev);
switch (ev.type)
{
   case ClientMessage:
   {
     switch (ev.message_type)
     {
        case MY_COMMAND_1:
        {
            XClientMessageEvent * xevent;
            long myLong1,myLong2;
            xevent = (XClientMessageEvent *)&ev;
            myLong1 = xevent->data.l[0];
            myLong2 = xevent->data.l[1];
            break;
        }
        case MY_COMMAND_2:
        {
            break;
        }
   }
}
Do it this way. I know it works because i do this in my multi-threaded xwindows apps.

Author of BackupBand at https://sourceforge.net/projects/backupband/files/
My fans show their support by mentioning my name in their signature.

User avatar
skei
Established Member
Posts: 343
Joined: Sun May 18, 2014 4:24 pm
Has thanked: 8 times
Been thanked: 58 times
Contact:

Re: xlib vs usleep

Post by skei »

i think you misunderstood me, or maybe i am still not explaining myself very well..

i wondered if there were anything that would wake up the thread if it has been sent to sleep with nanosleep (or usleep), not making it return if it was waiting for an event in XNextEvent.. i know i can send a clientmessage.. i already do that for other purposes..

and, why is it bad to sleep in a gui thread? what is the difference between sleeping and blocking? ("If the event queue is empty, XNextEvent flushes the output buffer and blocks until an event is received")..

- tor-helge
j_e_f_f_g
Established Member
Posts: 2032
Joined: Fri Aug 10, 2012 10:48 pm
Been thanked: 358 times

Re: xlib vs usleep

Post by j_e_f_f_g »

skei wrote:why is it bad to sleep in a gui thread?
Because it can make the desktop less responsive. You're not handling messages when you're sleeping, and sometimes the window manager requires you to process a message before it can interact further with the enduser. This is particularly true when the user moves/sizes/reorders windows, or changes focus to another app's window. Granted, you're only sleeping for 30 ms, and most window managers have a longer timeout before they pop up that message box saying "This app is not responding. Terminate it?". But if everyone did what you're doing, it would make every desktop "stutter".

Change your usleep to a couple seconds and see what it does to your desktop and plugin host.

You're not supposed to sleep in a gui thread (nor do anything that would prevent your gui thread from processing messages for "a long time").
what is the difference between sleeping and blocking?
XNextEvent isn't just "blocking". It's "waiting for gui event". It means you're ready to immediately process an event.

usleep means you're not ready, until usleep times out and returns, and then you call XNextEvent.

There is a difference.

You say that you know how to wake up from XNextEvent. Why then are you using XPending and usleep in a busy wait loop? That's unnecessary.

Author of BackupBand at https://sourceforge.net/projects/backupband/files/
My fans show their support by mentioning my name in their signature.

User avatar
skei
Established Member
Posts: 343
Joined: Sun May 18, 2014 4:24 pm
Has thanked: 8 times
Been thanked: 58 times
Contact:

Re: xlib vs usleep

Post by skei »

j_e_f_f_g wrote: Because it can make the desktop less responsive. You're not handling messages when you're sleeping, and sometimes the window manager requires you to process a message before it can interact further with the enduser. This is particularly true when the user moves/sizes/reorders windows, or changes focus to another app's window. Granted, you're only sleeping for 30 ms, and most window managers have a longer timeout before they pop up that message box saying "This app is not responding. Terminate it?". But if everyone did what you're doing, it would make every desktop "stutter".

Change your usleep to a couple seconds and see what it does to your desktop and plugin host.

You're not supposed to sleep in a gui thread (nor do anything that would prevent your gui thread from processing messages for "a long time").
i understand..

first, this is a for the editor of a vst plugin, so the 'window manager' is quite a bit less complex (and also restrictive) than a desktop.. and my window is a child of a host-controlled window, and i don't get many move/resize/minimize, etc, events..

so, hmmm... the problem is the sluggishness that can result from the sleeping and not processing events immediately.. i have not noticed much when sleeping for 30ms.. and 30ms is the worst case, it can be 0, if the sleep is almost over when the event is pushed onto the event queue.. and also, when i wake up, i process all events in the queue, not just one.. so, now and then, there can be a (up to) 30ms delay between the handling of two events..
when i'm recording guitars through my audio interface, with a latency of 128*3 samples (8.71ms) i can not notice any delay.. normally, anything shorter than around 20m feels "instanteous"..

i have been thinking about sleeping for even shorter.. for example 1ms, and then have a counter, and call my update function when this counter has reached 30, or something like that.. or i could have a kind of timer pool, and various widgets could register callbacks, and how many ticks between each call..
j_e_f_f_g wrote:You say that you know how to wake up from XNextEvent. Why then are you using XPending and usleep in a busy wait loop? That's unnecessary.
first i did it the 'normal' way, by using XNextEvent in a thread like you said.. and things worked well.. (this is for a vst plugin editor, not standalone executable, by the way).. my plugin is being called regularly by the host (dispatcher/effEditIdle), and i update the gui in reponse to these calls.. i check if any parameters have changed, and repaint the on-screen widgets, do some animation, etc..

then i noticed that various hosts call this effEditIdle callback at different intervals.. normally around 20-30hz, which is kind of ok, and feels quite smooth.. some call it more often, some a LOT slower.. qtractor only around 5 times per second, it seems.. so, if i animate a parameter in the host, the smoothness of the visual updates depends on the host and how often it calls effEditIdle.. to have a similar experience in various hosts and platforms, and to have a bit more control, i wanted my own timer instead of relying on the host calling my plugin (hopefully) regularly..

so, then i added another thread that just sent a clientmessage ('sts_idle') to my window, went to sleep for 20-30 ms or so, then wake up, and did it all again, until i closed the window.. the main event thread receives the event (with XNextEvent), passed it on to the window class, and then i did the same thing as before, checked parameters, did the painting, etc..

then i combined these two threads into one, so that it works like this (until i close the window):

1. check if there are any events in the queue (XPending)
2. if so, read it, and process it..
3. repeat 1-2 until the event queue is empty
4. do the gui update (effEditIdle/on_idle)
5. sleep for a little while, so that we reach a certain framerate. 30ms = 33.3hz
6. wake up, goto 1

XPending so that it doesn't block.. if i call XNextEvent and the event queue is empty, it would block, and the gui would not be updated until next time an event is coming in..

the sleep is there to control how often the on_idle() method is called.. i don't need (or want) to redraw the gui thousands of times per second :-/

---

as i see it, the alternatives i have:

1. update gui from effEditIdle callback.. accept that i have to live with varying gui updates in various hosts
2. use a second (timer) thread to regularly post (sts_idle) clientmessages to the first/main (event handler) thread, and update the gui when i receive these messages.. this thread can sleep between posting these messages, i guess?
3. combined thread, xpending/sleeping, and accept the (up to/in worst case) 30ms (or lower) delay now and then..

- tor-helge
j_e_f_f_g
Established Member
Posts: 2032
Joined: Fri Aug 10, 2012 10:48 pm
Been thanked: 358 times

Re: xlib vs usleep

Post by j_e_f_f_g »

Oh I see. This is a plugin written to Steinberg's VST spec. I've never written one of those, but I've looked at some code. Doesn't the host have a callback for whenever a control's value needs updating? You're not supposed to do your own message loop, or draw, from an "idle callback"?? That seems kludgey. How do you prevent your XNextEvent from grabbing an event intended for another host/plugin window?

In any event, I'd opt for #1 to ensure my plugin doesn't negatively impact the host's timing. That would be really bad. At least give the enduser a way to disable your endrun around the host, in case it's a problem.

Author of BackupBand at https://sourceforge.net/projects/backupband/files/
My fans show their support by mentioning my name in their signature.

User avatar
skei
Established Member
Posts: 343
Joined: Sun May 18, 2014 4:24 pm
Has thanked: 8 times
Been thanked: 58 times
Contact:

Re: xlib vs usleep

Post by skei »

sorry for not answering earlier..
been busy coding :-)

the vst specs is a bit of a mess, yeah, and lacking/missing docs doesn't make it much better.. so i'm making these wrappers/abstractions for various stuff (like vst and xlib)..

the host tells you to open the editor, giving you a parent Window handle as one of the arguments to the function call.. and then you're more or less on your own.. i open a separate display connection for each window (XOpenDisplay(NULL)), create the window itself (as a child of the hosts parent window), then i setup a thread that reads xlib events using this window/display combo.. i only receive events meant for my window, so i just pass the events on to the window instance/class..

i switched back to the 'normal' event-thread way (no sleeping), and relying on the hosts effEditIdle calls for screen updates.. (i can always switch back using a #define).. and it works pretty well, so i'll concentrate on other things for a while now.. (yesterday was gui-widget day.. added stuff like: groupbox, scrollbox, tabs, resizable editor, on-screen keyboard, etc)..

- th
User avatar
skei
Established Member
Posts: 343
Joined: Sun May 18, 2014 4:24 pm
Has thanked: 8 times
Been thanked: 58 times
Contact:

Re: xlib vs usleep

Post by skei »

ok, a little update:

https://www.youtube.com/watch?v=kckybX1ng20

the current state of my framework's gui subsystem.. note that gtk-recordmydesktop recorded at 15fps, so the video looks more jerky than it is in reality.. here, on my machine, it's smooth as silk! :-) some of the widgets (like the waveform and grid widgets) in the video doesn't do much, since this is mainly a gui-test, and mainly testing the hierarchy and audio alignment/layout stuff.. also, i have a few new widgets that i didn't add to the test yet: menus, modal popups, png decoding, flex surfaces, and i'm working on a timeline, and a modular/graph widgets, which is almost done.. and also, the widgets have been made as basic as possible.. it's extremely simple to make new widgets.. for example, both the knob and slider widgets, are exactly the same as the value widget, but with a different, overloaded on_paint method.. the .so file is quite small, around 200k here, and only needs xlib/xrender..

- th
j_e_f_f_g
Established Member
Posts: 2032
Joined: Fri Aug 10, 2012 10:48 pm
Been thanked: 358 times

Re: xlib vs usleep

Post by j_e_f_f_g »

You're not using any toolkit? Just xlib?

Author of BackupBand at https://sourceforge.net/projects/backupband/files/
My fans show their support by mentioning my name in their signature.

User avatar
skei
Established Member
Posts: 343
Joined: Sun May 18, 2014 4:24 pm
Has thanked: 8 times
Been thanked: 58 times
Contact:

Re: xlib vs usleep

Post by skei »

j_e_f_f_g wrote:You're not using any toolkit? Just xlib?
yes, just xlib, and optionally xrender for bitmap stretching & blending..
j_e_f_f_g
Established Member
Posts: 2032
Joined: Fri Aug 10, 2012 10:48 pm
Been thanked: 358 times

Re: xlib vs usleep

Post by j_e_f_f_g »

Cool. I've been using pure xlib for my gui, but I'm moving all drawing to Cairo in preparation of Wayland.

Author of BackupBand at https://sourceforge.net/projects/backupband/files/
My fans show their support by mentioning my name in their signature.

Post Reply