Quantcast
Channel: User Kamil Maciorowski - Super User
Viewing all articles
Browse latest Browse all 837

Answer by Kamil Maciorowski for How to run an infinite loop program on startup on a Raspberry Pi without halting boot up

$
0
0

Analysis

  • ; is a command terminator that makes the shell run the command synchronously.
  • & is a command terminator that makes the shell run the command asynchronously.

&; in your augmented code is two terminators where the shell expects exactly one. To terminate a command use either & or ;, not both.

Do not try to use & where you tried to use it. Using & instead of &; would make the shell code syntactically valid, yet wrong for reasons stated below. & here makes no sense, because while whatever & do :; done would make the shell interpreting the script run whatever asynchronously and then:

  • The exit status of whatever would not matter because the shell would not wait for it. The exit status of a command is known after the command exits. Having just run whatever &, the shell proceeds past & when the exit status of whatever still belongs to the future.* Normally starting a command asynchronously is a success (see false & echo "$?").

    * It may happen whatever is scheduled early and exits before the shell is scheduled to continue, still the shell cannot count on this. It doesn't even try and reports a success. Not relying on a race condition is a good thing.

  • As the shell would not wait for whatever to exit and it would see success from whatever &, it would proceed to : and loop again and again. In effect it would keep spawning whatevers. Then:

    • It may happen whatevers exit fast enough to balance the inflow of new whatevers from the loop. The script will never exit by itself, its parent will forever wait for it to exit.

    • Or whatevers will accumulate until some resource (e.g. memory or number of processes) is depleted. When some resource is depleted, whatever & will fail and the loop will end, so the script will proceed to echo. Note that other processes may suffer first, including the shell interpreting the script (so it may be killed before it gets to echo) and the parent of the script (so instead of unblocking the startup you may get it killed).

      In the best (or rather "least bad") scenario the parent survives, the script exits or gets killed and the parent continues. Even then few ((hundreds of) thousands of) whatevers may survive. This will be especially likely if whatever is designed to be a long-running process.

None of these is what you want.


Solutions

(Note: each numbered point is an independent solution; choose one that fits you most; there should never be a need for mixing them.)

  1. If you can, make the parent run your original script asynchronously. If the parent is itself a shell interpreting some script then the syntax in that script will be:

    /path/to/original/script &

    E.g. the above should work in rc.local (if your OS uses this file) or in your ~/.bashrc.

  2. Make your original script run its entire body asynchronously. The idea is to make the script exit and leave an asynchronous child shell behind. This should unblock the parent, even if the parent invoked the script synchronously.

    This is your original script modified to implement the idea:

    #!/bin/bash(while sudo /home/pi/MyCode; do :; doneecho Error with MyCode) &

In solutions using &, depending on how you want your script to behave, you may need additional steps. For a start read What's the difference between running a program as a daemon and forking it into background with &? to see what I mean. To just unblock the parent a proper use of & should be enough though.

  1. If your OS uses systemd then consider creating a service. The relevant fragment of the .service file will be:

    [Service]Type=execExecStart=/path/to/original/script

    In a system service you don't need sudo. And if /home/pi/MyCode is designed to only occasionally exit (with success) then consider ExecStart=/home/pi/MyCode with Restart=on-success, so you won't need the script implementing the loop at all.

    If you decide to create a system service (rather than user service) then consider moving MyCode to a directory owned by root.


Viewing all articles
Browse latest Browse all 837

Trending Articles