Feat: Use named pipe instead of signals and sleep
This is a breaking change and will lead to a new major version.
This commit is contained in:
parent
4ddf06147d
commit
d5c02f8459
20
README.md
20
README.md
@ -9,19 +9,19 @@ The Daemon
|
|||||||
----------
|
----------
|
||||||
|
|
||||||
The daemon creates a modular status bar by updating the X root window name
|
The daemon creates a modular status bar by updating the X root window name
|
||||||
when it receives the USR1 signal. It takes an ordered list of modules as a
|
when it receives a request on its named pipe. It takes an ordered list of
|
||||||
parameter, and calls a function in each module to compute a section of the
|
modules as a parameter, and calls a function in each module to compute a
|
||||||
status bar. Each section is cached and only recomputed upon request. These
|
section of the status bar. Each section is cached and only recomputed upon
|
||||||
requests are made by creating empty files with the same names as the modules
|
request. These requests are made by writing to a named pipe that the daemon
|
||||||
in the `/tmp/avdd` directory, then sending the daemon a USR1 signal.
|
creates, `/tmp/avdd-fifo`.
|
||||||
|
|
||||||
The Scheduler
|
The Scheduler
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The scheduler creates request files in `/tmp/avdd`, then sends the USR1
|
The scheduler creates requests by writing a module name to the named pipe for
|
||||||
signal to the daemon. It can send one signal to update multiple status bar
|
each module it wants the daemon to run to update that section of the status
|
||||||
sections by creating a request file for each section to update, and can send
|
bar. It can send requests immediately, after some delay, or repeatedly at
|
||||||
the signal immediately, after some delay, or repeatedly at some interval.
|
some interval.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
@ -38,7 +38,7 @@ Usage
|
|||||||
The following examples can be executed manually or by putting them in, e.g.,
|
The following examples can be executed manually or by putting them in, e.g.,
|
||||||
your `.xinitrc` file. Note the `&` after long-running commands to make them
|
your `.xinitrc` file. Note the `&` after long-running commands to make them
|
||||||
run in the background. If the directory that you cloned the appliction into
|
run in the background. If the directory that you cloned the appliction into
|
||||||
is not in your path, be sure to include the path when calling `avdd` or `avds`.
|
is not in your path, be sure to specify the path when calling `avdd` or `avds`.
|
||||||
|
|
||||||
Start the daemon to create a status bar with the default sections, prefix,
|
Start the daemon to create a status bar with the default sections, prefix,
|
||||||
separators, and suffix.
|
separators, and suffix.
|
||||||
|
62
avdd
62
avdd
@ -44,8 +44,7 @@ DEFAULT_SEP_L='| '
|
|||||||
DEFAULT_SEP_R=' '
|
DEFAULT_SEP_R=' '
|
||||||
DEFAULT_SUF=' '
|
DEFAULT_SUF=' '
|
||||||
MOD_DIR="$(dirname "$0")"/mod
|
MOD_DIR="$(dirname "$0")"/mod
|
||||||
ACTION_DIR=/tmp/avdd
|
FIFO=/tmp/avdd-fifo
|
||||||
ACTION_DIR_LEN=${#ACTION_DIR}
|
|
||||||
|
|
||||||
mod_list="${1-${DEFAULT_MOD_LIST}}"
|
mod_list="${1-${DEFAULT_MOD_LIST}}"
|
||||||
pre="${2-${DEFAULT_PRE}}"
|
pre="${2-${DEFAULT_PRE}}"
|
||||||
@ -96,43 +95,38 @@ draw_status() {
|
|||||||
# Draw the initial status
|
# Draw the initial status
|
||||||
draw_status
|
draw_status
|
||||||
|
|
||||||
# For each file in the action directory, remove the file, and if a module
|
# If the module value is in the cache, indicating that the module controls
|
||||||
# for the action is cached, call the module function and update the cache. If
|
# part of the status bar, execute the module function and redraw the status
|
||||||
# any cache entries were updated, redraw the status.
|
# bar if that part of the status bar has changed
|
||||||
process_signal () {
|
process_cmd () {
|
||||||
local -a action_paths
|
local -r mod="$1"
|
||||||
local action_path mod is_changed
|
|
||||||
readarray -d '' action_paths< \
|
|
||||||
<(find "${ACTION_DIR}" -maxdepth 1 -type f -exec rm -f {} + -print0)
|
|
||||||
for action_path in "${action_paths[@]}"; do
|
|
||||||
mod="${action_path:$((ACTION_DIR_LEN + 1))}"
|
|
||||||
if [[ -v stat_cache[${mod}] ]]; then
|
if [[ -v stat_cache[${mod}] ]]; then
|
||||||
stat_cache["${mod}"]="$(eval "$(mod_to_fn "${mod}")")"
|
local -r new_val="$(eval "$(mod_to_fn "${mod}")")"
|
||||||
is_changed=1
|
if [[ "${new_val}" != stat_cache["${mod}"] ]]; then
|
||||||
|
stat_cache["${mod}"]="${new_val}"
|
||||||
|
draw_status
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
|
||||||
if [[ -v is_changed ]]; then draw_status; fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Begin trapping signals
|
# Setup the named pipe to receive commands
|
||||||
mkdir -p "${ACTION_DIR}"
|
if [[ ! -p "${FIFO}" ]]; then mkfifo "${FIFO}"; fi
|
||||||
trap process_signal SIGUSR1
|
trap "rm -f ${FIFO}" EXIT
|
||||||
|
|
||||||
# Wait for signals efficiently. In a loop begin a long-running sleep command
|
# Each time the pipe is emptied out, the inner while loop will finish, so
|
||||||
# in the background, then wait on it. If we trap a signal before the wait is
|
# wrap it in an infinte loop to keep blocking until there is data on the pipe
|
||||||
# over and sleep is still running, trap will call process_signal, then code
|
|
||||||
# execution will resume at the line after the wait statement. So on that line
|
|
||||||
# we kill the (probably) still running sleep command so they don't pile up,
|
|
||||||
# and loop to sleep and wait for the next signal. If we don't trap a signal
|
|
||||||
# during the long running sleep, then the wait ends, we try to kill the
|
|
||||||
# sleep command that has already exited, so it doesn't matter, and loop to
|
|
||||||
# sleep and wait again. Note that we don't make the sleep too long because
|
|
||||||
# if the daemon is killed, the sleep will become an orphaned process until
|
|
||||||
# the sleep period elapses.
|
|
||||||
while :; do
|
while :; do
|
||||||
sleep 30m &
|
while read -r cmd; do
|
||||||
sleep_pid="$!"
|
case "${cmd}" in
|
||||||
wait "${sleep_pid}"
|
res_quit)
|
||||||
kill "${sleep_pid}" 2>/dev/null
|
exit 0
|
||||||
|
;;
|
||||||
|
res_*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
process_cmd "${cmd}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done < "${FIFO}"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
53
avds
53
avds
@ -1,43 +1,44 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
USAGE="
|
USAGE="
|
||||||
USAGE: avds <action> [<when>] [<repeat>]
|
USAGE: avds <mod_list> [<when>] [<repeat>]
|
||||||
|
|
||||||
action A comma or space separated list of actions to associate with the
|
mod_list
|
||||||
update signal.
|
A comma or space separated list of modules to request that
|
||||||
|
the daemon execute.
|
||||||
|
|
||||||
when The integer number of milliseconds to wait before sending the
|
when The integer number of milliseconds to wait before sending the
|
||||||
update signal, or one of the following values:
|
request, or one of the following values:
|
||||||
- m to send the update signal at the top of the next minute
|
- m to send the update request at the top of the next minute
|
||||||
- h to send the update signal at the top of the next hour
|
- h to send the update request at the top of the next hour
|
||||||
- d to send the update signal at the top of the next day
|
- d to send the update request at the top of the next day
|
||||||
If not present, the update signal will be sent immediately.
|
If not present, the request will be sent immediately.
|
||||||
|
|
||||||
repeat If present, the update signal will be sent repeatedly according
|
repeat If present, the request will be sent repeatedly according
|
||||||
to <when>.
|
to <when>.
|
||||||
|
|
||||||
EXAMPLES:
|
EXAMPLES:
|
||||||
|
|
||||||
If the daemon interprets the actions 'vol' and 'bl' to mean update the
|
If there are volume and backlight modules named 'vol' and 'bl' that
|
||||||
volume and backlight statuses, respectively, send a signal to
|
update the volume and backlight statuses, send a requst to update
|
||||||
immediately update both of those statuses.
|
both of those statuses immediately.
|
||||||
|
|
||||||
avds 'vol,bl'
|
avds 'vol,bl'
|
||||||
|
|
||||||
If the daemon interprets the actions 'cpu' and 'mem' to mean update the
|
If there are cpu and memory usage modules named 'cpu' and 'mem'
|
||||||
cpu and memory usage statuses, respectively, send a signal to update
|
that update the cpu and memory usage statuses, send a requst to
|
||||||
both of those statuses every 5 seconds.
|
update both of those statuses every 5 seconds.
|
||||||
|
|
||||||
avds 'cpu,mem' 5000 1
|
avds 'cpu,mem' 5000 1
|
||||||
|
|
||||||
If the daemon interprets the actions 'bat' and 'dt' to mean update the
|
If there are battery and date/time modules named 'bat' and 'dt'
|
||||||
battery and date/time statuses, respectively, send a signal to update
|
that update the battery and date/time statuses, send a requst to
|
||||||
both of those statuses at the top of every minute.
|
update both of those statuses at the top of every minute.
|
||||||
|
|
||||||
avds 'bat,dt' m true
|
avds 'bat,dt' m true
|
||||||
"
|
"
|
||||||
DAEMON=avdd
|
DAEMON=avdd
|
||||||
ACTION_DIR=/tmp/"${DAEMON}"
|
FIFO=/tmp/"${DAEMON}"-fifo
|
||||||
|
|
||||||
# Convert integer milliseconds to floating point seconds
|
# Convert integer milliseconds to floating point seconds
|
||||||
ms_to_s () {
|
ms_to_s () {
|
||||||
@ -50,7 +51,7 @@ if [[ "$#" -lt 1 || "$#" -gt 3 ]]; then
|
|||||||
exit 128
|
exit 128
|
||||||
fi
|
fi
|
||||||
|
|
||||||
IFS=', ' read -r -a actions <<< "$1"
|
IFS=', ' read -r -a mods <<< "$1"
|
||||||
when="${2:-0}"
|
when="${2:-0}"
|
||||||
repeat="$3"
|
repeat="$3"
|
||||||
|
|
||||||
@ -59,12 +60,12 @@ if [[ ! "${when}" =~ ^[0-9]+|[mhd]$ ]]; then
|
|||||||
exit 128
|
exit 128
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Send the signal if this is the first run or if repeat is on
|
# Write to the pipe if this is the first run or if repeat is on
|
||||||
first_run=1
|
first_run=1
|
||||||
while [[ "${first_run}" -eq 1 || -n "${repeat}" ]]; do
|
while [[ "${first_run}" -eq 1 || -n "${repeat}" ]]; do
|
||||||
first_run=0
|
first_run=0
|
||||||
|
|
||||||
# Sleep until it's time to send the signal
|
# Sleep until it's time to write to the pipe
|
||||||
if [[ "${when}" != '0' ]]; then
|
if [[ "${when}" != '0' ]]; then
|
||||||
if [[ "${when}" =~ ^[0-9]+$ ]]; then
|
if [[ "${when}" =~ ^[0-9]+$ ]]; then
|
||||||
sleep "$(ms_to_s "${when}")"
|
sleep "$(ms_to_s "${when}")"
|
||||||
@ -87,13 +88,11 @@ while [[ "${first_run}" -eq 1 || -n "${repeat}" ]]; do
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create the signal data and send the signal to the daemon
|
# Write each command to the pipe
|
||||||
daemon_pid="$(pgrep --newest --exact "${DAEMON}")"
|
if [[ ! -p "${FIFO}" ]]; then
|
||||||
if [[ -z "${daemon_pid}" ]]; then
|
|
||||||
printf 'The daemon %s is not running\n' "${DAEMON}" 1>&2
|
printf 'The daemon %s is not running\n' "${DAEMON}" 1>&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
for action in "${actions[@]}"; do touch "${ACTION_DIR}/${action}"; done
|
for mod in "${mods[@]}"; do printf '%s\n' "${mod}" >> "${FIFO}"; done
|
||||||
kill -USR1 "${daemon_pid}"
|
|
||||||
done
|
done
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user