Fellow Genodians, what follows is a minor observation and two (more serious) questions.
1) Suspend/resume
The introduction of that feature in 23.02 triggered some "geek lust" in this aging geek, and now with 23.05 I got around to attempting system integration of suspend/resume in my stack.
In Qemu it seems to all work fine (after I realized the vesa and input driver need to be restarted, reading acpi_suspend.run more carefully). However on bare metal (admittely years old), S3-suspend works well, but at resume time, the screen remains black. I thought maybe if the video driver causes trouble, I can try the "back door" (vnc), to validate the concept that everything works except vesa, and confirm I need to revisit my integration of vesa_drv. So I tried to connect via VNC, but no go, coming back from suspend. Could be that the nic_driver needs to be restarted as well (I didn't handle that, I only restart vesa and ps2_drv currently).
I could persist, but this is not a feature I really need (just wanted it for "bragging rights" :^) so I'll probably wait for newer Genode releases, in case it's a matter of waiting for Genode upgrades. Very cool to have that feature almost at reach though.
2) Launching apps A newbie question ! (yes even after 5 years I still have those :-) How to launch components (applications). Grepping through the Genode repo, I came up with:
- use a sub init with a generous RAM alotment (2 GB), and drive its config ROM through a report_rom: a list of launched apps has to be maintained by a "third actor" (not the sub-init, and not any of the client apps that require launching a process, but rather some sort of stand-by "registrar"), and its job would be to re-generate the sub's config ROM whenever that list grows as a new app is launched. Problem is, what happens when the user *quits* an application ? When that occurs, the app is still part of the sub-init's config, so next time sub reads its config, it's going to re-launch it, right ? This would otherwise seem to fit the bill well, if not for that problem of un-desired app relaunch. Maybe I can solve that problem by sending notifications every time an app is quit (if it's quit cleanly rather than crashing, at least), and the notification recipient (probably the "registrar" ?) would remove the relevant snippet from the sub-init's config.
- loader_session: seems close enough too, and simplier to use, but the README says the ram/caps of the created child will be substracted from the caller, instead of from the launcher (i.e. the opposite of a sub-init). But I want to do the reverse.
- fork/exec from libc : same as launcher_session, but seemingly with the (additional) awkwardness of old-style UNIX, where fork() creates a full duplicate of the caller, at least until exec() is called (so the caller app would need to have twice as much ram/caps as it needs, even if it just spawns something tiny like /bin/ls !).
- sandbox.h : couldn't find a "tutorial" style usage of it via grep -r sandbox repos/, but maybe I should dive right in and experiment until I understand the gist of it, using the more complex use-cases in the repos ?
- anything I missed ?
3) capability leak in pthread_create() (regression in 23.05 ?)
Seems my stack triggers some sort of corner case that it did'nt before. This is a little more mission-critical, though it's a small leak and I haven't seen it really impact my apps so far. Anyway the observed behavior is, in many cases, pthread_create() behaves as it always had, allocates a new capability for the created thread, which is returned when the thread ends. But in some scenarios, the cap is not returned, so I'm leaking a cap for each created thread, or pthread_create() allocates _two_ caps instead of one ; this seems to depend on how soon the spawned thread is scheduled (i.e. before or after libc returns from create). Could be that the "corner case" is in my stack, not in Genode, of course. What angle to take to debug that ? I should probably create a ticket to discuss that issue.
Cédric
Hi Cedrik,
regarding your question 2, you did a good job with exploring the options. Let me try to fill out the few missing pieces of the picture.
On 2023-07-25 21:08, ttcoder@netcourrier.com wrote:
- Launching apps
A newbie question ! (yes even after 5 years I still have those :-) How to launch components (applications). Grepping through the Genode repo, I came up with:
- use a sub init with a generous RAM alotment (2 GB), and drive its config ROM through a report_rom:
a list of launched apps has to be maintained by a "third actor" (not the sub-init, and not any of the client apps that require launching a process, but rather some sort of stand-by "registrar"), and its job would be to re-generate the sub's config ROM whenever that list grows as a new app is launched. Problem is, what happens when the user *quits* an application ? When that occurs, the app is still part of the sub-init's config, so next time sub reads its config, it's going to re-launch it, right ? This would otherwise seem to fit the bill well, if not for that problem of un-desired app relaunch. Maybe I can solve that problem by sending notifications every time an app is quit (if it's quit cleanly rather than crashing, at least), and the notification recipient (probably the "registrar" ?) would remove the relevant snippet from the sub-init's config.
This is generally the most advised option. It is promoted in the "Foundations" book [1], and is prominently employed by Sculpt's Leitzentrale UI.
[1] https://genode.org/documentation/genode-foundations/23.05/components/Compone...
The re-use of the regular init component relieves you from low-level technicalities like the child-component creation via Genode's low-level C++ API, the parent-child protocol, or the routing of sessions. As the approach is solely based on exchanging plain text (XML) between the dynamic init instance and the manager, a manager could in principle be written in any programming language that is able to handle XML.
You apparently just missed one little detail, which is the "state" report generated by init. Whenever something interesting happens (e.g., a child exits), init reflects this information in an updated state report, which can then be inspected by the management component ("registrar") to take action, like removing the <start> node from the init config when spotting an 'exited="yes"' attribute for a child. The level of detail of the state report is configurable. One can go as far as letting init list all sessions used by each child, which gives the "registrar" deep insights into the interplay and state of the hosted components.
As an experiment, in Sculpt you can peek into the state report of the runtime init by looking at /report/runtime/state using Vim in the inspect view. After adding the attribute 'requested="yes"' to the <report> node of /config/managed/runtime, the state report becomes much more detailed.
For forcibly re-starting a component, the "registrar" can make use of the 'version' attribute of the <start> node. Whenever the version is changed, init replaces the existing component by a new instance. This is what happens when pressing a "Restart" button for a component in Sculpt.
- loader_session: seems close enough too, and simplier to use, but the README says the ram/caps of the created child
will be substracted from the caller, instead of from the launcher (i.e. the opposite of a sub-init). But I want to do the reverse.
The loader session is a relic, which will eventually be removed.
- fork/exec from libc : same as launcher_session, but seemingly with the (additional) awkwardness of old-style UNIX,
where fork() creates a full duplicate of the caller, at least until exec() is called (so the caller app would need to have twice as much ram/caps as it needs, even if it just spawns something tiny like /bin/ls !).
The fork/exec mechanism is nice as a bridging solution to host existing POSIX software. But it cannot give you the flexibility and level of control that Genode offers. E.g., when spawning a child using fork, the child's resource allocations are not capped but paid for by the parent.
- sandbox.h : couldn't find a "tutorial" style usage of it via grep
-r sandbox repos/, but maybe I should dive right in and experiment until I understand the gist of it, using the more complex use-cases in the repos ?
The sandbox library covers use cases where the dynamic init approach is not flexible enough. The library is actually the same code as used by init internally. By using this library, one can create custom incarnations of init that provide local services to the hosted children.
These cases are rare but they exist. E.g., the (emerging) debug monitor [2] uses the sandbox library to intercept Genode's low-level services used by the hosted children. Another example is a GUI application that wants to use a 'menu_view' as a child component and needs to intercept the menu_view's interplay with the GUI server, e.g., to get hold of keyboard input [3].
[2] https://github.com/genodelabs/genode/tree/master/repos/os/src/monitor [3] https://github.com/genodelabs/genode/tree/master/repos/gems/src/app/text_are...
In short, I recommend taking the dynamic-init approach. Should you encounter its limitations, switch to the sandbox library. Better don't touch the low-level C++ APIs like 'base/child.h'. Please ignore the loader session.
Cheers Norman
Hello Cédric,
On 7/25/23 9:08 PM, ttcoder@netcourrier.com wrote:
- Suspend/resume
The introduction of that feature in 23.02 triggered some "geek lust" in this aging geek, and now with 23.05 I got around to attempting system integration of suspend/resume in my stack.
In Qemu it seems to all work fine (after I realized the vesa and input driver need to be restarted, reading acpi_suspend.run more carefully). However on bare metal (admittely years old), S3-suspend works well, but at resume time, the screen remains black. I thought maybe if the video driver causes trouble, I can try the "back door" (vnc), to validate the concept that everything works except vesa, and confirm I need to revisit my integration of vesa_drv. So I tried to connect via VNC, but no go, coming back from suspend. Could be that the nic_driver needs to be restarted as well (I didn't handle that, I only restart vesa and ps2_drv currently).
I could persist, but this is not a feature I really need (just wanted it for "bragging rights" :^) so I'll probably wait for newer Genode releases, in case it's a matter of waiting for Genode upgrades. Very cool to have that feature almost at reach though.
currently, it is too early to use this feature productively. In principal all hardware must be re-initialized after resume, since they were powered off potentially and lost configuration. In the current state, the kernels (nova and hw) reinitialize the devices used by them (CPUs, lapic, ioapic, iommu (nova) and serial), but nothing more. The port of acpica does additional wakeup handling, but must also be considered non complete yet.
For Intel graphic devices we have a, in principal capable driver, to do the job, so intel_fb and intel_gpu works on some systems. By restarting them, they initialize the hardware again into a usable state.
In contrast, vesa_drv or boot_fb expects that someone (e.g. Bios/UEFI) did the job of setting up the hardware, which is not the case after ACPI resume (as far as I can tell). That means also, that for AMD or NVDIDA devices you will have to have "real" drivers, so that they can work after ACPI resume. So, AMD/NVDIDA cards are not what GenodeLabs is focusing on at all, beside some hobby interests/experiments of some of us. If this is a target hardware for you/someone, first the drivers need to written or ported ...
By restarting the network driver after resume, the hardware should be get back into a usable state, but I did not tried so far. It may happen that new code paths in the ported drivers get triggered, which needs to be implemented/inspected. Lucky, who gets a working serial interface after resume for doing the debugging job ...
So for now, I think you should consider this feature experimental, as you guessed already.
Cheers,
Alex.