diff options
Diffstat (limited to 'internal/worker.zsh')
-rw-r--r-- | internal/worker.zsh | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/internal/worker.zsh b/internal/worker.zsh new file mode 100644 index 00000000..99948c46 --- /dev/null +++ b/internal/worker.zsh @@ -0,0 +1,258 @@ +# invoked in worker: _p9k_worker_main <pgid> +function _p9k_worker_main() { + mkfifo $_p9k__worker_file_prefix.fifo || return + echo -nE - s$_p9k_worker_pgid$'\x1e' || return + exec 0<$_p9k__worker_file_prefix.fifo || return + zf_rm $_p9k__worker_file_prefix.fifo || return + + typeset -g IFS=$' \t\n\0' + + local -i reset + local req fd + local -a ready + local _p9k_worker_request_id + local -A _p9k_worker_fds # fd => id$'\x1f'callback + local -A _p9k_worker_inflight # id => inflight count + + function _p9k_worker_reply() { + print -nr -- e${(pj:\n:)@}$'\x1e' || kill -- -$_p9k_worker_pgid + } + + # usage: _p9k_worker_async <work> <callback> + function _p9k_worker_async() { + local fd async=$1 + sysopen -r -o cloexec -u fd <( + () { eval $async; } && print -n '\x1e') || return + (( ++_p9k_worker_inflight[$_p9k_worker_request_id] )) + _p9k_worker_fds[$fd]=$_p9k_worker_request_id$'\x1f'$2 + } + + trap '' PIPE + + { + while zselect -a ready 0 ${(k)_p9k_worker_fds}; do + [[ $ready[1] == -r ]] || return + for fd in ${ready:1}; do + if [[ $fd == 0 ]]; then + local buf= + while true; do + sysread -t 0 'buf[$#buf+1]' && continue + (( $? == 4 )) || return + [[ $buf[-1] == (|$'\x1e') ]] && break + sysread 'buf[$#buf+1]' || return + done + for req in ${(ps:\x1e:)buf}; do + _p9k_worker_request_id=${req%%$'\x1f'*} + () { eval $req[$#_p9k_worker_request_id+2,-1] } + (( $+_p9k_worker_inflight[$_p9k_worker_request_id] )) && continue + print -rn -- d$_p9k_worker_request_id$'\x1e' || return + done + else + local REPLY= + while true; do + sysread -i $fd 'REPLY[$#REPLY+1]' && continue + (( $? == 5 )) || return + break + done + local cb=$_p9k_worker_fds[$fd] + _p9k_worker_request_id=${cb%%$'\x1f'*} + unset "_p9k_worker_fds[$fd]" + exec {fd}>&- + if [[ $REPLY == *$'\x1e' ]]; then + REPLY[-1]="" + () { eval $cb[$#_p9k_worker_request_id+2,-1] } + fi + if (( --_p9k_worker_inflight[$_p9k_worker_request_id] == 0 )); then + unset "_p9k_worker_inflight[$_p9k_worker_request_id]" + print -rn -- d$_p9k_worker_request_id$'\x1e' || return + fi + fi + done + done + } always { + kill -- -$_p9k_worker_pgid + } +} + +typeset -g _p9k__worker_pid +typeset -g _p9k__worker_req_fd +typeset -g _p9k__worker_resp_fd +typeset -g _p9k__worker_shell_pid +typeset -g _p9k__worker_file_prefix +typeset -gA _p9k__worker_request_map + +# invoked in master: _p9k_worker_invoke <request-id> <list> +function _p9k_worker_invoke() { + [[ -n $_p9k__worker_resp_fd ]] || return + local req=$1$'\x1f'$2$'\x1e' + if [[ -n $_p9k__worker_req_fd && $+_p9k__worker_request_map[$1] == 0 ]]; then + _p9k__worker_request_map[$1]= + print -rnu $_p9k__worker_req_fd -- $req + else + _p9k__worker_request_map[$1]=$req + fi +} + +function _p9k_worker_cleanup() { + emulate -L zsh + setopt no_hist_expand extended_glob no_prompt_bang prompt_{percent,subst} no_aliases + [[ $_p9k__worker_shell_pid == $sysparams[pid] ]] && _p9k_worker_stop + return 0 +} + +function _p9k_worker_stop() { + emulate -L zsh + setopt no_hist_expand extended_glob no_prompt_bang prompt_{percent,subst} no_aliases + add-zsh-hook -D zshexit _p9k_worker_cleanup + [[ -n $_p9k__worker_resp_fd ]] && zle -F $_p9k__worker_resp_fd + [[ -n $_p9k__worker_resp_fd ]] && exec {_p9k__worker_resp_fd}>&- + [[ -n $_p9k__worker_req_fd ]] && exec {_p9k__worker_req_fd}>&- + [[ -n $_p9k__worker_pid ]] && kill -- -$_p9k__worker_pid 2>/dev/null + [[ -n $_p9k__worker_file_prefix ]] && zf_rm -f $_p9k__worker_file_prefix.fifo + _p9k__worker_pid= + _p9k__worker_req_fd= + _p9k__worker_resp_fd= + _p9k__worker_shell_pid= + _p9k__worker_request_map=() + return 0 +} + +function _p9k_worker_receive() { + emulate -L zsh + setopt no_hist_expand extended_glob no_prompt_bang prompt_{percent,subst} no_aliases + + [[ -z $_p9k__worker_resp_fd ]] && return + + { + (( $# <= 1 )) || return + + local buf resp + while true; do + sysread -t 0 -i $_p9k__worker_resp_fd 'buf[$#buf+1]' && continue + (( $? == 4 )) || return + [[ $buf == (|*$'\x1e')$'\x05'# ]] && break + sysread -i $_p9k__worker_resp_fd 'buf[$#buf+1]' || return + done + + local -i reset + for resp in ${(ps:\x1e:)${buf//$'\x05'}}; do + local arg=$resp[2,-1] + case $resp[1] in + d) + local req=$_p9k__worker_request_map[$arg] + if [[ -n $req ]]; then + _p9k__worker_request_map[$arg]= + print -rnu $_p9k__worker_req_fd -- $req || return + else + unset "_p9k__worker_request_map[$arg]" + fi + ;; + e) + if (( start_time )); then + local -F end_time=EPOCHREALTIME + local -F3 latency=$((1000*(end_time-start_time))) + echo "latency: $latency ms" >>/tmp/log + start_time=0 + fi + () { eval $arg } + ;; + s) + [[ -z $_p9k__worker_pid ]] || return + [[ $arg == <1-> ]] || return + _p9k__worker_pid=$arg + sysopen -w -o cloexec -u _p9k__worker_req_fd $_p9k__worker_file_prefix.fifo || return + local req= + for req in $_p9k__worker_request_map; do + print -rnu $_p9k__worker_req_fd -- $req || return + done + _p9k__worker_request_map=({${(k)^_p9k__worker_request_map},''}) + ;; + *) + return 1 + ;; + esac + done + + if (( reset == 2 )); then + _p9k_refresh_reason=worker + _p9k_set_prompt + _p9k_refresh_reason='' + fi + (( reset )) && _p9k_reset_prompt + return 0 + } always { + (( $? )) && _p9k_worker_stop + } +} + +function _p9k_worker_start() { + setopt no_bgnice monitor + { + [[ -n $_p9k__worker_resp_fd ]] && return + _p9k__worker_file_prefix=${TMPDIR:-/tmp}/p10k.worker.$EUID.$$.$EPOCHSECONDS + + sysopen -r -o cloexec -u _p9k__worker_resp_fd <( + if [[ -n $_POWERLEVEL9K_WORKER_LOG_LEVEL ]]; then + exec 2>$_p9k__worker_file_prefix.log + setopt xtrace + else + exec 2>/dev/null + fi + # todo: remove + exec 2>>/tmp/log + setopt xtrace + zmodload zsh/zselect || return + ! { zselect -t0 || (( $? != 1 )) } || return + local _p9k_worker_pgid=$sysparams[pid] + _p9k_worker_main & + { + trap '' PIPE + while syswrite $'\x05'; do zselect -t 1000; done + zf_rm -f $_p9k__worker_file_prefix.fifo + kill -- -$_p9k_worker_pgid + } & + exec =true) || return + zle -F $_p9k__worker_resp_fd _p9k_worker_receive + _p9k__worker_shell_pid=$sysparams[pid] + add-zsh-hook zshexit _p9k_worker_cleanup + } always { + (( $? )) && _p9k_worker_stop + } +} + +# todo: remove + +return + +function _p9k_reset_prompt() { + zle && zle reset-prompt && zle -R +} + +emulate -L zsh -o prompt_subst -o interactive_comments # -o xtrace + +# POWERLEVEL9K_WORKER_LOG_LEVEL=DEBUG + +zmodload zsh/datetime +zmodload zsh/system +zmodload -F zsh/files b:zf_mv b:zf_rm + +autoload -Uz add-zsh-hook + +function foo_compute() { + _p9k_worker_reply 'echo sync latency: $((1000*(EPOCHREALTIME-'$1'))) >>/tmp/log' + # _p9k_worker_async foo_async "foo_sync $1" +} + +function foo_async() { +} + +function foo_sync() { + _p9k_worker_reply 'echo async latency: $((1000*(EPOCHREALTIME-'$1'))) >>/tmp/log' +} + +typeset -F start_time=EPOCHREALTIME +_p9k_worker_start +_p9k_worker_invoke first '_p9k_worker_reply ""' +echo -E - $((1000*(EPOCHREALTIME-start_time))) + +bm() { _p9k_worker_invoke foo$1 "foo_compute $EPOCHREALTIME" } |