Le 19/07/2025 à 12:48, aitor a écrit :
>
> Hi Rainer,
>
> On 17/7/25 13:49, Rainer Weikusat via Dng wrote:
>>>> enum {
>>>> FD_POLL_SIGNAL = 0,
>>>> FD_POLL_PIPE,
>>>> FD_POLL_NETLINK,
>>>> FD_POLL_MAX
>>>> };
>> This means FD_POLL_PIPE has the value 1.
>
> Yes.
>
>> pfd[FD_POLL_PIPE].fd = pipe[1];
>
>> Which means this is polling the write end of the pipe on systems where
>> pipes are indeed unidirectional. The convention is the same here as for
>> standard I/O file descriptors. File descriptor 0 is the standard input
>> and 1 is the standard output. When creating a pipe, the first file
>> descriptor (offset 0) is for reading and the second one for writing.
> I did mistakes in my example. As Didier has pointed out in another email, it should be pipefd[0].
>
> Nevertheless, I'm considering a new approach because I don't like the idea of forking a new process
> in the function:
> int vdev_os_next_device(struct vdev_device_request* vreq, void* cls)
> that yields the next device event (see line 471 of vdevd/os/linux.c) and is invoked over and over
> again within the loop:
>
> int vdev_os_main(struct vdev_os_context* vos) { int rc = 0;
> while(vos->running) { (......) } }
> in vdevd/os/common.c
>
> On the other hand, if we fork a new process outside the loop in common.c the linux netlink would be used
> in a file that, according to Jude Nelson's design, aims to be OS-agnostic with the purpose of serving as
> an example for future ports, say BSD. And I don't want to affect the legibility of the original program.
>
> This brings me to the idea of using a daemonlet in common.c. If you read the **Advanced device handling**
> in the 'how-to-test.md' file:
>
>
> /*------------------------- JUDE NELSON's EXPLANTIONS ---------------------------*/
>
> By default, `vdevd` will `fork()` and `exec()` the `command` for each device request in the system shell.
> However, as an optimization, `vdevd` can run the command as a *daemonlet*. This means that the `command`
> will be expected to stay resident once it proceses a device request, and receive and process subsequent
> device requests from `vdevd` instead of simply exiting after each one. Doing so saves `vdevd` from having
> to `fork()` and `exec()` the same command over and over again for common types of devices, and lets it avoid
> having to repeatly incur long `command` start-up times. It also allows the administrator to define stateful
> or long-running actions that can work on sets of devices.
>
> The programming model for daemonlet commands is as follows:
>
> 1. `vdevd` will `fork()` and `exec()` the command directly. It will *not* invoke the system shell to run it.
> 2. `vdevd` will write a sequence of newline-terminated strings to the command's `stdin`, followed by an empty
> newline string. These strings encode the request's environment variables, and are in the form `NAME=VALUE\n`.
> 3. The `command` is expected to write an ASCII-encoded exit code to `stdout` to indicate the success/failure of
> processing the request. 0 indicates success, and non-zero indicates failure.
>
> If the `command` crashes or misbehaves, `vdevd` will log as such and attempt to restart it.
>
> /* ----------------------------------- END --------------------------------------------*/
>
>
> Time ago I moved part of the code from vdevd/* to libvdev/* and built a shared library in a way that standalone
> vdev helpers can make use of these *daemonlets*. For instance, there is 'tiny vdev' that works fine during the
> initrd phase, but I still didn't implement it in gnuinos because it fails for some unknown reason in virtual
> machines (at least in qemu). However, I'll push these examples to git because I think they illustrate very well
> the use of daemonlets.
>
> This said, in my new approach the daemonlet would be started in an OS-agnostic way before the while() loop in
> vdev_os_main(). In the next iteration, the function vdev_os_next_device() would look for the next coldplugged
> device or, on the contrary, for the next hotplugged device, depending on what we got when feeding the already
> running daemonlet at the end of the previous iteration.
>
Note that, maybe you don't need to execve(). Since the scanning
function is relatively small, fork() would suffice. Not even speaking of
doing it via yet another fork+exec of the shell...
-- Didier