I wrote a script to run specific actions conditional on input events informed by an event monitor, which looks something like
$ cat script.sh
-----------------------------------------------------------
#!/usr/bin/bash
stdbuf -oL /usr/bin/event_monitor | while IFS= read LINE
do
something with $LINE
done
When run as a script from a bash terminal, the script consumes a normal amount of CPU, and executes the action only when a new line is printed. However, when run as a service with the following setup
$ cat event.service
-----------------------------------------------------------
[Unit]
Description=Actions upon events
[Service]
Type=simple
ExecStart=/path/to/script.sh
[Install]
WantedBy=default.target
The event_monitor command now takes over an entire logical core, and strace reveals that read is read()ing nothing as often as the processor allows:
$ strace -p $event_monitor_pid
-----------------------------------------------------------
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
read(0, "", 1) = 0
................ad nauseum
while the service still registers events and executes the conditional commands when real events do occur. What went wrong here?
p.s. this happens with cras_monitor but not with acpi_listen. I tried to ensure that the while loop only starts after ensuring the underlying service successfully starts, but to no avail.
Update: here are some potentially relevant bits of event_monitor's code:
...
#include <headers.h>
...
# Print to console function:
static void event_occurrence(void *context, int32_t attribute)
{
printf("Some attribute has changed to %d.\n", attribute);
}
...
int main(int argc, char **argv)
{
struct some_service_client *client # defined in headers
int rc
...
# Some routine
...
some_service_client_set_event_occurence_callback(client,event_occurence)
...
rc = some_func(client)
...
while (1) {
int rc;
char c;
rc = read(STDIN_FILENO, &c, 1);
if (rc < 0 || c == 'q')
return 0;
}
...
}
$event_monitor_pidthe pid ofbashor ofevent-monitor?event_monitorandscript.shretain their PIDs, I'm rather doubtful that the service is being relaunched.event_monitorwhatever that is is trying to read from its stdin, possibly because it's an interactive tool and when running from systemd, obviously there's no user to interact with it, stdin is /dev/null and that tool fails to detect it's not running interactively (and also fails to detect eof on its stdin which would be a bug). In any case, nothing to do with that bash script itself.</dev/null stdbuf -oL /usr/bin/event_monitor, executed in an interactive shell, shows the same unexpected behavior of the systemd service.