site  contact  subhomenews

How to run long-time process on udev event

December 08, 2020 — BarryK

I will show the problem, and solution, by example. In EasyOS, also in all the official woof-CE built pups, there is a rule in /etc/udev/rules.d/88-puppy-autodetect.rules, with this in it (a bit different in woof-CE, but same principle):

ACTION=="add", SUBSYSTEM=="usb", ENV{INTERFACE}=="6/1/*", RUN+="/usr/sbin/pupautodetect camera"

Now here is the crux of the problem: the udev daemon is held up until 'pupautodetect' terminates. If 'pupautodetect' takes a long time to terminate, it can cause serious problem with running of the daemon.

So, we need to get out of 'pupautodetect' as soon as possible. The script has a 20-second wait loop, which is bad, but that is only one-off at first pristine bootup. Then, 'pupcamera' is called, like this:

case $1 in
camera)
pupcamera &
;;

...and this is where something happens, or rather doesn't happen, that took me by surprise -- the "&" does not detach the process! This is really the "crux of the crux" of the problem!

I wrote about detaching recently:

https://bkhome.org/news/202009/detach-child-process-from-parent.html

All right, as "&", nor "disown $!" work, I tried "setsid --fork" when I was working on BluePup. I thought that was working, very odd, because it definitely isn't now. Doing this in 'pupautodetect', 'pupautodetect-run' does not even run:

setsid --fork pupautodetect-run $@

The idea was, I would get out of 'pupautodetect' real quick, then 'pupautodetect-run' can run for as long as it wants.

This problem of detaching a process that is called by a udev rule, is one that others have encountered, with various solutions, such as here:

https://unix.stackexchange.com/questions/56243/how-to-run-long-time-process-on-udev-event

...the "at now" solution does not appeal to me, besides, don't have the 'at' executable installed.

...the weird thing is, someone has posted that 'setsid' worked. That is just so weird, because I thought it was working also, pretty sure it was. Yesterday was testing EasyOS 2.5.2 with the simplified 4.19.161 kernel, and setsid did not work, and I thought that I must have made a configure change in the kernel that has broken it. So built 2.5.2.1 with the "full feature" 5.4.81 kernel, same problem. Hmmm...

Could install 'at', but then I remembered busybox's 'cttyhack', that I have used before. Yes, this works, have this in 'pupautodetect':

cttyhack sh pupautodetect-run $@ &

I can confirm, by running "ps | grep pupautodetect'", that 'pupautodetect' is released, and udevd immediately processes the next uevent -- which I also confirmed.

I have accordingly fixed these scripts in woofQ:

/usr/sbin/pupautodetect
/usr/local/pup_event/bluetooth-add, bluetooth-remove, bluetoothhw

I will let 01micko know about this, he might want to look at 'pupautodetect', etc., in woof-CE. jamesbond has in-depth knowledge of udev and how processes work, and might have further thoughts, will contact him also.

EDIT:
I was very puzzled about that person reporting that 'setsid' works, so I did it this way, with full path to 'pupautodetect-run', and the script then did run:

setsid --fork /usr/sbin/pupautodetect-run $@

...however, it did not detach. It still held up udevd. So what that person reported is incorrect. Really odd that needed the full path!

But I now understand why 'setsid' seemed to be working when I was developing BluePup -- I had the full path to the script. It only seemed to be working though, as although it executed the script, it did not detach. 

EDIT:
A bit more information, that might interest 01micko. As posted recently, I have adapted 'pupmtp' from woof-CE:

https://bkhome.org/news/202012/considering-mtp-access-to-an-android-phone.html

However, now that I have freed udevd, when I select PTP mode for the USB connection in my phone (old nexus 5, "Developer options -> Select USB configuration -> PTP", I get both 'pupcamera' and 'pupmtp' popping up. If I choose MTP mode, just get 'pupmtp'. So I modified /usr/sbin/pupautodetect-run:

case $1 in
camera)
pupcamera &
;;
android-device) #20201205
sleep 2 #20201208 do not run pupmtp if running pupcamera
pidof pupcamera >/dev/null
if [ $? -ne 0 ];then
pupmtp &
fi
;;
esac

...select PTP on phone, a uevent occurs that launches 'pupmtp', then another uevent launches 'pupcamera'. This code prevents both from running, only 'pupcamera'. Select MTP on phone, only 'pupmtp' runs.

EDIT:
James (jamesbond in the forums) has responded, with another solution. James posted:

the "&" and "disown" probably won't work because the shell is not connected to a controlling terminal, hence, it doesn't support job control (which is required for "&" and "disown" to work).

Yes, that is the problem that I had in the initrd, and the busybox solution to add job control in the initrd is the 'cttyhack' applet. And as posted above, 'cttyhack' also works for a script called from a udev rule.

However, James has proposed another solution, that works with bash:

#!/bin/sh
set -m
... whatever stuff you want to do.

"set -m" turns on job control, as explained in bash man page:

https://linux.die.net/man/1/bash

"set -m" will probably also work with busybox ash. 

Tags: easy