sistema_progs

Programas para customizar o meu entorno de traballo nos meus equipos persoais
Log | Files | Refs

util.bgproc.sh (20271B)


      1 # -*- mode: sh; mode: sh-bash -*-
      2 
      3 ## @fn ble/util/bgproc#open prefix command [opts]
      4 ##   Start a session for a background process.  The session can be closed by
      5 ##   calling "ble/util/bgproc#close PREFIX".  The background process is usually
      6 ##   started on the start of the session and terminated on closing the session.
      7 ##   In addition, if requested, the background process can be stopped and
      8 ##   started any time in the session.  If the background process is stopped, it
      9 ##   is automatically restarted when it becomes needed.  If "timeout=TIMEOUT"
     10 ##   is specified in OPTS, the background process is automatically stopped
     11 ##   where there is no access for the time duration specified by TIMEOUT.
     12 ##
     13 ##   @param[in] prefix
     14 ##     This names the identifier of the bgproc.  This is actually used as the
     15 ##     prefix of the array names used to store the information of the created
     16 ##     bgproc, so the value needs to be a valid variable name.
     17 ##
     18 ##     When the bgproc is successfully created, the following array elements
     19 ##     are set, (where PREFIX in the variable name is replaced by the value of
     20 ##     prefix).
     21 ##
     22 ##     @var PREFIX_bgproc[0]       ... fd_response
     23 ##     @var PREFIX_bgproc[1]       ... fd_request
     24 ##     @var PREFIX_bgproc[2]       ... command
     25 ##     @var PREFIX_bgproc[3]       ... opts
     26 ##     @var PREFIX_bgproc[4]       ... bgpid
     27 ##     @var PREFIX_bgproc_fname[0] ... fname_response
     28 ##     @var PREFIX_bgproc_fname[1] ... fname_request
     29 ##     @var PREFIX_bgproc_fname[2] ... fname_run_pid
     30 ##
     31 ##     To send strings to stdin of the background process, one can write to the
     32 ##     file descriptor ${PREFIX_bgproc[1]}.  To read strings coming from stdout
     33 ##     of the background process, one can read from the file descriptor
     34 ##     ${PREFIX_bgproc[0]}.
     35 ##
     36 ##     When any of "timeout=TIMEOUT", "deferred", and "restart" are specified
     37 ##     to OPTS, one should call "ble/util/bgproc#use PREFIX" just before
     38 ##     directly accesssing the file descriptors ${PREFIX_bgproc[0]} and
     39 ##     ${PREFIX_bgproc[1]} to ensure that the background process is running.
     40 ##     Or, one can use a shorthand "ble/util/bgproc#post PREFIX STRING" to
     41 ##     ensure the background process and write STRING to it.  Immediately after
     42 ##     "ble/util/bgproc#post PREFIX STRING", one do not need to call
     43 ##     "ble/util/bgproc#use PREFIX" to read from ${PREFIX_bgproc[0]}.
     44 ##
     45 ##   @param[in] command
     46 ##     The command to execute.
     47 ##
     48 ##     @remarks Use `exec'--The command is started in a subshell.  When an
     49 ##     external command is started (as the last command of the subshell),
     50 ##     please start the command by `exec'.  This will replace the current
     51 ##     process with the external process.  If the external command is not
     52 ##     started with `exec', the external command is created as a child process
     53 ##     of the subshell, and the file descriptors are kept by also the subshell.
     54 ##     This may cause a deadlock in closing the file descriptors because the
     55 ##     file descriptors in the external process are still alive even after the
     56 ##     main Bash subshell closes them because the subshell still keeps the file
     57 ##     descriptor.
     58 ##
     59 ##     @remarks Reserved variables `bgproc' and `bgproc_fname'--If the command
     60 ##     wants to access the variable names "bgproc" and "bgproc_fname" defined
     61 ##     outside the command, please save the values in other names of variables
     62 ##     before calling "ble/util/bgproc#open" and access those alternative
     63 ##     variables from inside the command.  The variable names "bgproc" and
     64 ##     "bgproc_fname" are hidden by the local variables used by ble/util/bgproc
     65 ##     itself.
     66 ##
     67 ##   @param[in,opt] opts
     68 ##     A colon-separated list of options.  The following options can be
     69 ##     specified.
     70 ##
     71 ##     deferred
     72 ##       When this option is specified, the background process is initially not
     73 ##       started.  It will be started when it is first required.
     74 ##
     75 ##     restart
     76 ##       When this option is specified, if the background process died
     77 ##       unexpectedly, the background process will be restarted when it becomes
     78 ##       necessary.
     79 ##
     80 ##       Note: Even if this option is unspecified, the background process that
     81 ##       was intensiontally stopped will be always restarted when it becomes
     82 ##       necessary.  This option only affects the case that the background
     83 ##       process exited or died outside the management of bgproc.
     84 ##
     85 ##     timeout=TIMEOUT
     86 ##       When this option is specified, the background process is stopped when
     87 ##       there are no access to the background process for the time duration
     88 ##       specified by TIMEOUT.  The unit of TIMEOUT is millisecond.
     89 ##
     90 ##     owner-close-on-unload
     91 ##       This option suppresses the automatic call of "ble/util/bgproc#close"
     92 ##       from the "unload" blehook.  This option is useful when another
     93 ##       "unload" blehook needs to access to this bgproc.  When this option is
     94 ##       specified, another "unload" blehook needs to manually call
     95 ##       "ble/util/bgproc#close" for this bgproc.  If "ble/util/bgproc#close"
     96 ##       is not called, the background process may be forcibly terminated by
     97 ##       the final cleaup stage of ble.sh session.
     98 ##
     99 ##     no-close-on-unload
    100 ##       This option suppresses the automatic call of "ble/util/bgproc#close"
    101 ##       and any cleanups of the background process, so that the background
    102 ##       process survives after Bash terminates or ble.sh has been unloaded.
    103 ##
    104 ##       Note: Nevertheless, file descriptors at the side of the parent shell
    105 ##       will be closed on the termination of the parent shell, which can cause
    106 ##       SIGPIPE write error or EOF read error in the background process.
    107 ##
    108 ##     kill-timeout=TIMEOUT
    109 ##       This option specifies the timeout after the attempt of stopping the
    110 ##       background process in unit of millisecond.  The default is 10000 (10
    111 ##       seconds).  If the background process does not terminate within the
    112 ##       timeout after closing the file descriptors at the side of the parent
    113 ##       shell, the background process will receive SIGTERM.  If it does not
    114 ##       terminate even after sending SIGTERM, it will then receive SIGKILL
    115 ##       after additional timeout specified by "kill9-timeout".
    116 ##
    117 ##     kill9-timeout=TIMEOUT
    118 ##       This option specifies the additional timeout after sending SIGTERM
    119 ##       after "kill-timeout".  The default is 10000 (10 seconds).  If the
    120 ##       background process does not terminate within the timeout after sending
    121 ##       SIGTERM, the background process will receive SIGKILL.
    122 ##
    123 ##   @exit 0 if the background process is successfully started or "deferred" is
    124 ##   specified to OPTS.  2 if an invalid prefix value is specified.  3 if the
    125 ##   system does not support named pipes.  1 if the background process failed
    126 ##   to be started.
    127 ##
    128 ##   @remarks No FD_CLOEXEC for bgproc file descriptors--Unlike "coproc", the
    129 ##   file descriptors opened by bgproc are not closed in subshells.  This means
    130 ##   that if there are other background processes holding the file descriptors,
    131 ##   even when the main Bash process closes the file descriptors by
    132 ##   `ble/util/bgproc#stop' or `ble/util/bgproc#close', the file descriptors in
    133 ##   the bgproc process can still alive.  If one wants to make it sure that the
    134 ##   file descriptors are closed in the other subshells, one needs to close the
    135 ##   file descriptors
    136 ##
    137 ##   1) by calling eval "exec ${PREFIX_bgproc[0]}>&- ${PREFIX_bgproc[1]}>&-"
    138 ##
    139 ##   2) Or by calling `ble/fd#finalize' (Note that `ble/fd#finalize' closes all
    140 ##     the file descriptors opened by ble.sh including the ones used by
    141 ##     ble/util/msleep)..
    142 ##
    143 ##   3) Or another way is to use the loadable builtin "fdflags" to set
    144 ##     FD_CLOEXEC in `ble/util/bgproc/onstart:PREFIX'.  bgproc[]
    145 ##
    146 ##     # The loadable builtin needs to be loaded in advance.  Please replace
    147 ##     # the path /usr/lib/bash/fdflags based on your installation.
    148 ##     enable -f /usr/lib/bash/fdflags fdflags
    149 ##
    150 ##     function ble/util/bgproc/onstart:PREFIX {
    151 ##       fdflags -s +cloexec "${PREFIX_bgproc[0]}"
    152 ##       fdflags -s +cloexec "${PREFIX_bgproc[1]}"
    153 ##     }
    154 ##
    155 ## @fn ble/util/bgproc/onstart:PREFIX
    156 ##   When this function is defined, this function is called after the new
    157 ##   background process is created.
    158 ##
    159 ## @fn ble/util/bgproc/onstop:PREFIX
    160 ##   When this function is defined, this function is called before the
    161 ##   background process is stopped.
    162 ##
    163 ##   The application can send an intruction to terminate the background process
    164 ##   in this hook (in case that the background process does not automatically
    165 ##   end on the close of the file descriptors, or the file descriptors can be
    166 ##   shared with other background subshells).  Note that the background process
    167 ##   will receive SIGTERM if it does not terminate within the timeout specified
    168 ##   by "kill-timeout=TIMEOUT" and then will receive SIGKILL if it does not
    169 ##   even terminate within the additional timeout specified by
    170 ##   "kill9-timeout=TIMEOUT".
    171 ##
    172 ## @fn ble/util/bgproc/onclose:PREFIX
    173 ##   When this function is defined, this function is called before the bgproc
    174 ##   session is closed.
    175 ##
    176 ## @fn ble/util/bgproc/ontimeout:PREFIX
    177 ##   When this function is defined, this function is called before the timeout
    178 ##   specified by "timeout=TIMEOUT" in OPTS.  If this function exits with
    179 ##   non-zero status, the timeout is canceled.
    180 ##
    181 function ble/util/bgproc#open {
    182   if ! ble/string#match "$1" '^[_a-zA-Z][_a-zA-Z0-9]*$'; then
    183     ble/util/print "$FUNCNAME: $1: invalid prefix value." >&2
    184     return 2
    185   fi
    186 
    187   # If there is an existing bgproc on the same prefix, close it first.
    188   ble/util/bgproc#close "$1"
    189 
    190   local -a bgproc=()
    191   bgproc[0]=
    192   bgproc[1]=
    193   bgproc[2]=$2
    194   bgproc[3]=${3-}
    195 
    196   local -a bgproc_fname=()
    197   bgproc_fname[0]=$_ble_base_run/$$.util.bgproc.$1.response.pipe
    198   bgproc_fname[1]=$_ble_base_run/$$.util.bgproc.$1.request.pipe
    199   bgproc_fname[2]=$_ble_base_run/$$.util.bgproc.$1.pid
    200 
    201   ble/util/save-vars "${1}_" bgproc bgproc_fname
    202 
    203   [[ :${bgproc[3]}: == *:deferred:* ]] || ble/util/bgproc#start "$1"; local ext=$?
    204   if ((ext!=0)); then
    205     builtin eval -- "${1}_bgproc=() ${1}_bgproc_fname=()"
    206   fi
    207   return "$ext"
    208 }
    209 
    210 ## @fn ble/util/bgproc#alive prefix
    211 ##   Test if the bgproc session is active.
    212 ##
    213 ##   @param[in] prefix
    214 ##     The name to identify the bgproc.
    215 ##
    216 function ble/util/bgproc#opened {
    217   local bgpid_ref=${1}_bgproc[0]
    218   [[ ${!bgpid_ref+set} ]] || return 2
    219 }
    220 
    221 ## @fn ble/util/bgproc/.alive
    222 ##   @var[in] bgproc
    223 function ble/util/bgproc/.alive {
    224   [[ ${bgproc[4]-} ]] && kill -0 "${bgproc[4]}" 2>/dev/null
    225 }
    226 
    227 ## @fn ble/util/bgproc/.exec
    228 ##   @var[in] bgproc
    229 function ble/util/bgproc/.exec {
    230   # Note: We need to specify the redirections for ${bgproc[0]} and ${bgproc[1]}
    231   # on "builtin eval" because of a bash-3.0 bug.  In Bash 3.0, the redirections
    232   # are not properly set up if one uses a function definition of the form
    233   # "function fname { } redirections".
    234   builtin eval -- "${bgproc[2]}" <&"${bgproc[1]}" >&"${bgproc[0]}"
    235 }
    236 
    237 ## @fn ble/util/bgproc/.mkfifo
    238 ##   @var[in] bgproc_fname
    239 function ble/util/bgproc/.mkfifo {
    240   local -a pipe_remove=() pipe_create=()
    241   local i
    242   for i in 0 1; do
    243     [[ -p ${bgproc_fname[i]} ]] && continue
    244     ble/array#push pipe_create "${bgproc_fname[i]}"
    245     if [[ -e ${bgproc_fname[i]} || -h ${bgproc_fname[i]} ]]; then
    246       ble/array#push pipe_remove "${bgproc_fname[i]}"
    247     fi
    248   done
    249   ((${#pipe_remove[@]}==0)) || ble/bin/rm -f "${pipe_remove[@]}" 2>/dev/null
    250   ((${#pipe_create[@]}==0)) || ble/bin/mkfifo "${pipe_create[@]}" 2>/dev/null
    251 }
    252 
    253 ## @fn ble/util/bgproc#start prefix
    254 ##   Start the background process.  This runs the command specified to
    255 ##   "ble/util/bgproc#open".
    256 ##
    257 ##   @param[in] prefix
    258 ##     The name to identify the bgproc.
    259 ##
    260 ##   @exit 0 if the background process is successfully started or was already
    261 ##   running.  2 if the PREFIX does not corresponds to an existing bgproc.  3
    262 ##   if the system does not support the named pipes.  1 if the background
    263 ##   process failed to be started.
    264 ##
    265 function ble/util/bgproc#start {
    266   local bgproc bgproc_fname
    267   ble/util/restore-vars "${1}_" bgproc bgproc_fname
    268   if ((!${#bgproc[@]})); then
    269     ble/util/print "$FUNCNAME: $1: not an existing bgproc name." >&2
    270     return 2
    271   fi
    272 
    273   if ble/util/bgproc/.alive; then
    274     # The background process is already running
    275     return 0
    276   fi
    277   [[ ! ${bgproc[0]-} ]] || ble/fd#close 'bgproc[0]'
    278   [[ ! ${bgproc[1]-} ]] || ble/fd#close 'bgproc[1]'
    279 
    280   # Note: mkfifo may fail in MSYS-1
    281   local _ble_local_ext=0 _ble_local_bgproc0= _ble_local_bgproc1=
    282   if ble/util/bgproc/.mkfifo &&
    283     ble/fd#alloc _ble_local_bgproc0 '<> "${bgproc_fname[0]}"' &&
    284     ble/fd#alloc _ble_local_bgproc1 '<> "${bgproc_fname[1]}"'
    285   then
    286     bgproc[0]=$_ble_local_bgproc0
    287     bgproc[1]=$_ble_local_bgproc1
    288     # Note: We want to assign a new process group to the background process
    289     #   without affecting the job table of the main shell so use the subshell
    290     #   `(...)'.  The process group is later used to kill the process tree in
    291     #   stopping the background process.  Note that the command substitutions
    292     #   $(...) do not create a new process group even if we specify `set -m' so
    293     #   cannot be used for the present purpose.
    294     ble/util/assign 'bgproc[4]' '(set -m; ble/util/bgproc/.exec __ble_suppress_joblist__ >/dev/null & bgpid=$!; ble/util/print "$bgpid")'
    295 
    296     if ble/util/bgproc/.alive; then
    297       [[ :${bgproc[3]}: == *:no-close-on-unload:* ]] ||
    298         ble/util/print "-${bgproc[4]}" >| "${bgproc_fname[2]}"
    299       [[ :${bgproc[3]}: == *:no-close-on-unload:* || :${bgproc[3]}: == *:owner-close-on-unload:* ]] ||
    300         blehook unload!="ble/util/bgproc#close $1"
    301       ble/util/bgproc#keepalive "$1"
    302     else
    303       builtin unset -v 'bgproc[4]'
    304       _ble_local_ext=1
    305     fi
    306   else
    307     _ble_local_ext=3
    308   fi
    309 
    310   if ((_ble_local_ext!=0)); then
    311     [[ ! ${bgproc[0]-} ]] || ble/fd#close 'bgproc[0]'
    312     [[ ! ${bgproc[1]-} ]] || ble/fd#close 'bgproc[1]'
    313     bgproc[0]=
    314     bgproc[1]=
    315     builtin unset -v 'bgproc[4]'
    316   fi
    317 
    318   ble/util/save-vars "${1}_" bgproc bgproc_fname
    319 
    320   if ((_ble_local_ext==0)); then
    321     ble/function#try ble/util/bgproc/onstart:"$1"
    322   fi
    323   return "$_ble_local_ext"
    324 }
    325 
    326 function ble/util/bgproc#stop/.kill {
    327   local pid=$1 opts=$2 ret
    328 
    329   # kill --
    330   local timeout=10000
    331   if ble/opts#extract-last-optarg "$opts" kill-timeout; then
    332     timeout=$ret
    333   fi
    334   ble/util/conditional-sync '' '((1))' 1000 progressive-weight:pid="$pid":no-wait-pid:timeout="$timeout"
    335   kill -0 "$pid" || return 0
    336 
    337   # kill -9
    338   local timeout=10000
    339   if ble/opts#extract-last-optarg "$opts" kill9-timeout; then
    340     timeout=$ret
    341   fi
    342   ble/util/conditional-sync '' '((1))' 1000 progressive-weight:pid="$pid":no-wait-pid:timeout="$timeout":SIGKILL
    343 }
    344 
    345 ## @fn ble/util/bgproc#stop prefix
    346 ##   Stop the background process.
    347 ##
    348 ##   @param[in] prefix
    349 ##     The name to identify the bgproc.
    350 ##
    351 function ble/util/bgproc#stop {
    352   local prefix=$1
    353   ble/util/bgproc#keepalive/.cancel-timeout "$prefix"
    354 
    355   local bgproc bgproc_fname
    356   ble/util/restore-vars "${prefix}_" bgproc bgproc_fname
    357   if ((!${#bgproc[@]})); then
    358     ble/util/print "$FUNCNAME: $prefix: not an existing bgproc name." >&2
    359     return 2
    360   fi
    361 
    362   [[ ${bgproc[4]-} ]] || return 1
    363 
    364   if ble/is-function ble/util/bgproc/onstop:"$prefix" && ble/util/bgproc/.alive; then
    365     ble/util/bgproc/onstop:"$prefix"
    366   fi
    367 
    368   ble/fd#close 'bgproc[0]'
    369   ble/fd#close 'bgproc[1]'
    370   >| "${bgproc_fname[2]}"
    371 
    372   # When the background process is active, kill the process after waiting for
    373   # the time specified by kill-timeout.
    374   if ble/util/bgproc/.alive; then
    375     (ble/util/nohup 'ble/util/bgproc#stop/.kill "-${bgproc[4]}" "${bgproc[3]}"')
    376   fi
    377 
    378   builtin eval -- "${prefix}_bgproc[0]="
    379   builtin eval -- "${prefix}_bgproc[1]="
    380   builtin unset -v "${prefix}_bgproc[4]"
    381   return 0
    382 }
    383 
    384 ## @fn ble/util/bgproc#alive prefix
    385 ##   Test if the background process is currently running.
    386 ##
    387 ##   @param[in] prefix
    388 ##     The name to identify the bgproc.
    389 ##
    390 ##   @exit 2 if the prefix does not define a bgproc.  1 if the bgproc
    391 ##     process is temporarily stopped.  3 if the bgproc process has
    392 ##     crashed.  0 if the process is running.
    393 function ble/util/bgproc#alive {
    394   local prefix=$1 bgproc
    395   ble/util/restore-vars "${prefix}_" bgproc
    396   ((${#bgproc[@]})) || return 2
    397   [[ ${bgproc[4]-} ]] || return 1
    398   kill -0 "${bgproc[4]}" 2>/dev/null || return 3
    399   return 0
    400 }
    401 
    402 function ble/util/bgproc#keepalive/.timeout {
    403   local prefix=$1
    404 
    405   # Call ble/util/bgproc/ontimeout:PREFIX if any
    406   if ble/is-function ble/util/bgproc/ontimeout:"$prefix"; then
    407     if ! ble/util/bgproc/ontimeout:"$prefix"; then
    408       ble/util/bgproc#keepalive "$prefix"
    409       return 0
    410     fi
    411   fi
    412 
    413   ble/util/bgproc#stop "$prefix"
    414 }
    415 
    416 function ble/util/bgproc#keepalive/.cancel-timeout {
    417   local prefix=$1
    418   ble/function#try ble/util/idle.cancel "ble/util/bgproc#keepalive/.timeout $prefix"
    419 }
    420 
    421 ## @fn ble/util/bgproc#keepalive prefix
    422 ##   Rest the timeout to stop the background process.
    423 ##
    424 ##   @param[in] prefix
    425 ##     The name to identify the bgproc.
    426 ##
    427 function ble/util/bgproc#keepalive {
    428   local prefix=$1 bgproc
    429   ble/util/restore-vars "${prefix}_" bgproc
    430   ((${#bgproc[@]})) || return 2
    431   ble/util/bgproc/.alive || return 1
    432 
    433   ble/util/bgproc#keepalive/.cancel-timeout "$prefix"
    434   local ret
    435   ble/opts#extract-last-optarg "${bgproc[3]}" timeout || return 0; local bgproc_timeout=$ret
    436   if ((bgproc_timeout>0)); then
    437     local timeout_proc="ble/util/bgproc#keepalive/.timeout $1"
    438     ble/function#try ble/util/idle.push --sleep="$bgproc_timeout" "$timeout_proc"
    439   fi
    440   return 0
    441 }
    442 
    443 _ble_util_bgproc_onclose_processing=
    444 ## @fn ble/util/bgproc#close prefix
    445 ##   Close the bgproc session.
    446 ##
    447 ##   @param[in] prefix
    448 ##     The name to identify the bgproc.
    449 ##
    450 function ble/util/bgproc#close {
    451   # If the bgproc does not exist, do nothing.
    452   ble/util/bgproc#opened "$1" || return 2
    453 
    454   local prefix=${1}
    455   blehook unload-="ble/util/bgproc#close $prefix"
    456   ble/util/bgproc#keepalive/.cancel-timeout "$prefix"
    457 
    458   # When the callback function "ble/util/bgproc/onclose:PREFIX" is defined, we
    459   # call the function before starting the closing process.  However, we skip
    460   # this if the present call of "ble/util/bgproc#close" is already from inside
    461   # the callback, we skip it to avoid the infinite recursion.
    462   if ble/is-function ble/util/bgproc/onclose:"$prefix"; then
    463     if [[ :${_ble_util_bgproc_onclose_processing-}: != *:"$prefix":* ]]; then
    464       local _ble_util_bgproc_onclose_processing=${_ble_util_bgproc_onclose_processing-}:$prefix
    465       ble/util/bgproc/onclose:"$prefix"
    466     fi
    467   fi
    468 
    469   ble/util/bgproc#stop "$prefix"
    470   builtin eval -- "${prefix}_bgproc=() ${prefix}_bgproc_fname=()"
    471 }
    472 
    473 ## @fn ble/util/bgproc#use prefix
    474 ##   Ensure the file descriptors to be ready for uses.  When the background
    475 ##   process is temporarily stopped, this will restart the background process.
    476 ##   When the background process was terminated unexpectedly and "restart" is
    477 ##   specified to the bgproc's OPTS, this will also restart the background
    478 ##   process.
    479 ##
    480 ##   @param[in] prefix
    481 ##     The name to identify the bgproc.
    482 ##
    483 ##   @exit 0 if the background process is ready.  2 if the specified PREFIX
    484 ##   does not correspond to an existing bgproc.  3 if the system does not seem
    485 ##   to support named pipes.  1 if the background process was stopped and
    486 ##   failed to restart it.
    487 ##
    488 function ble/util/bgproc#use {
    489   local bgproc
    490   ble/util/restore-vars "${1}_" bgproc
    491   if ((!${#bgproc[@]})); then
    492     ble/util/print "$FUNCNAME: $1: not an existing bgproc name." >&2
    493     return 2
    494   fi
    495 
    496   if [[ ! ${bgproc[4]-} ]]; then
    497     # The background process has been stopped intenstionally.  We automatically
    498     # restart the background process in this case.
    499     ble/util/bgproc#start "$1" || return "$?"
    500   elif ! kill -0 "${bgproc[4]-}"; then
    501     # The background process died unexpectedly
    502     if [[ :${bgproc[3]-}: == *:restart:* ]]; then
    503       ble/util/bgproc#start "$1" || return "$?"
    504     else
    505       return 1
    506     fi
    507   else
    508     ble/util/bgproc#keepalive "$1"
    509     return 0
    510   fi
    511 }
    512 
    513 function ble/util/bgproc#post {
    514   ble/util/bgproc#use "$1" || return "$?"
    515   local fd1_ref=${1}_bgproc[1]
    516   ble/util/print "$2" >&"${!fd1_ref}"
    517 }