Can't get Haiku UI to work at all (various problems)

I’m hitting a road block here and I’m at a total loss what is going on. To see if it is possible I tried porting the GUI launcher of my game engine to Haiku using the native API. I think the code seems good (not finished yet) but the result is anything else but good.

I’m seeing various problems which happen randomly ranging from glitching UI elements (randomly missing text, randomly incorrect layout) all the way to spontanous crashes inside BMessage or related classes. All these problems are accompanied by spamming logs int he console in the form of

Unlocking BLocker with sem xxx from wrong thread yyy, current holder -1 (see issue #6400).

I googled everything to no avail. I tried GDB to no avail. I tried Debugger to no avail. I see nothing wrong with the basic way I do things.

For example clicking on the menu bar items and moving the cursor around a bit spams the console with these logs and suddenly the menu bar context menus zip to the side of the screen super thin and tiny staying broken until closing the application. Opening dialogs also randomly garbles things.

I have no other option than dropping the code in here hoping somebody sees what’s going on as I’m out of ideas:

https://github.com/LordOfDragons/dragengine/tree/copilot/feature-beosguilauncher/src/launcher/beosgui/src/gui

deglbWindowMain is the main window. Just fiddling with the menu bar triggers already these problems. Switching to deglbPanelEngine and double clicking an item to bring up the deglbDialogModuleProps is another way to trigger all kinds of problems. Unfortunately this is all I can provide.

1 Like

The ticket explains why one would see those messages. Have you checked what the thread is running and what it is unlocking that shouldn’t? For the crashes you can run the debugger or at least see the message and the stack trace to know what’s happened, though I guess those will probably be just a result of corruption caused somewhere else.

Unfortunately I can’t. Debugger nor GDB break on these messages so I have no clue what thread this is. I assume though menubar windows since the threads vanish and the numbers keep changing.

Concerning the crash I get no useful information. The stack trace is fully inside Haiku and usually starts with BMessage::BMessage underneath BLooper. But inside Haiku code I can not debug.

So I’m looking right now more for what could be wrong. I’ve written the code so I don’t need Lock/Unlock (fully asynchronous if I understand Haiku API correctly there) and I don’t use semaphores. So whatever is doing wrong unlocking is happening somewhere in Haiku but I don’t know how I could have triggered this.

Also if this happens and I try to shut down I get a kernel panic so I think something inside Haiku goes haywire in one way or the other.

Most of the threads are the same: the app_server window thread.

The semaphore is the same in all the message. listsem obviously shows it doesn’t exist anymore when the message is shown. But it is not even listed when run just after starting the app, so I guess it was removed at the beginning. I also see a message about a process being terminated at the beginning, possibly expected, but also possibly the first owner related? (Edited: the owner of the semaphore when some other thread unlocks it is the app_server window thread).

I’m thinking it might be related not to the menu bar, but to one of the components below in the window, the problem being at redrawing it after the menus disappear. I also see the lowest line of the main blank are not being redrawn (put a window of some other color on top then remove it to see it).

(Edited: yep, you can trigger it just by the context menu in the game list view)

The main window just has the menubar, the game and engine panel (only one set visible) and the status bar (label + progressbar(hidden)). I think the game and engine panels should be fine now as I changed them to use BColumnListView. That would leave the menubar and statusbar. But there I don’t see what could go wrong.

Concerning the ended process a separate process is used to probe the game engine as well as loading delga files. It is torn down once the data is obtained.

Probably none of the GUI components. I see (thankfully I remembered we have strace) the semaphore is deleted by a thread previously forked from the main one, and the same that appears as terminated in those messages. Of course once the semaphore mediating communication with the app server is deleted, everything goes downhill.

Enough from me tonight. I may chase that thread tomorrow if nothing is found, chaging the locker warning to a debugger call if needed.

It seems you’ll need some Haiku-specific work in delEngineInstanceThreaded::StartEngine(). It is called from the main application thread, forks, and the child does whatever and exit, taking the app_server communication semaphore (and who knows what else) with it. I removed the exit call and the issue disappears, even though I also see the process being stopped a little later, I guess through SIGKILL and so not cleaning up.

So you say regular process forking is not working on Haiku? What is the correct way to do this?

This is probably a bug; forked GUI applications should not try to delete their app_server communications semaphore.

Actually, this may be the cause of #18576 also, which I never got around to investigating?

Given the comment in the thread that

I’m just calling ‘exit’ after that in the child process.

it looks like exactly the same issue. Not claiming I understand any of this, though. I expected exit to take down even the windows, which it doesn’t. I went with “fork clones basically everything, and on exit the BLocker (and other objects’) dtor is called and that will delete the very same semaphore the parent uses”. Maybe delete_sem_internal should check the owner, not just that is has one?

I obviously don’t know if this is a problem of expectations or a bug in Haiku, so don’t take my words as truths to follow. I also don’t know what you need, and any of these may result in quite a few changes to your code only for Haiku. For simple task offloading I’d go with spawn_thread. For something more elaborate, maybe a BLooper and messages for communication. In both cases I’d finish them in their natural way, not through exit.

Perhaps we should document that fork from GUI processes is not supported, only vfork followed by _exit (which, as per POSIX, doesn’t call destructors)? Though admittedly vfork has been destandardized due to how many footguns it has; but on Haiku at least it’s well-defined (it’s regular fork but without calling any hooks or reinitializing anything.)

The alternative is trying to fix the Application Kit to deal with forks properly (by reinitializing), but I don’t think we should do this. Instead, at most, we should add some atfork hook inside kit initialization that sets up some sort of trap to detect when exit is called, and then invoke debugger.

I don’t think spawn_thread works here as I want a separate process for stability. I first try going by the BMessage way but hit a brick wall due to some unfortunate design principles. Scrapped it all and then went the posix_spawn way and that worked. The problems are now gone and the UI works as expected.

I’d say posix_spawn is indeed the cleanest and more efficient way to do this. No need for fork or vfork which are quite confusing to get right.

I don’t think it should reinitialize? But setting O_CLOFORK or similar options to prevent key application kit things from being forwarded to the forked process may be a good idea. I don’t know if we have an equivalent of that for semaphores, however.

1 Like

Indeed, we should have some mechanism to block ports and semaphores from being deleted (or even used) by anyone except their owning thread. Right now we don’t (and neither did BeOS). I added a note to “APIChangesOnCompatibilityDrop”, but if we are careful, we can do this before dropping compatibility, too.

1 Like

Anyway, I fixed some of the problems encountered here in hrev59410 and also added an assertion that will catch this problem more directly, instead of leading to cryptic issues like this one.

1 Like

I’m hitting another problem but that’s maybe a restriction on Haiku itself.

I’ve got the main Window. In this one I show a dialog with the feel B_MODAL_APP_WINDOW_FEEL. Now I want to show another dialog which is modal to this dialog (so MainWindow → Dialog1 → Dialog2). But this I can’t get working.

If I use B_MODAL_APP_WINDOW_FEEL then I can bring Dialog1 in front of Dialog2 which is bad.

If I use B_MODAL_SUBSET_WINDOW_FEEL (or B_FLOATING_SUBSET_WINDOW_FEEL) and add Dialog1 as subset of Dialog2 then Dialog2 does not show at all.

Can this be solved or do I need to “hack” around this somehow?

Recursive modals are not allowed. We decided that it’s too complicated for the users to understand such a locking sequence. Closing windows shouldn’t be a puzzle :slight_smile:

1 Like

I guess we agree to disagree then. Not allowing a dialog to modal another dialog can lead to application inconsistency or crashes. But then I’ll leave it as it is and for crashes I will simply redirect to this topic then :stuck_out_tongue:

One idea to maybe work around this issue: Why not hide the first modal before opening a second modal,and bring back the first modal after the second is closed?
Not checked if it works,but I think it should and it would also solve the UI/UX issue of confusing users which modal they should look at right now.

I already feel a bit constrained when I get a modal on Haiku.

I remember a few days ago, I wanted to see the filename, which was behind a modal dialog (probably the Save As), but I couldn’t, so I had to save under a temporary name and then later rename the file. This is a little inconvenient, when you’ve gotten yourself used to that ”modals” can be moved around.

I can try and recreate what exactly happend, so I can explain it properly, if need be.

Modals-on-modals … is that a Microsoft thing ? - I think I’ve experienced that a few years ago, but haven’t used Windows since then.