User:Justin545/mtbv


 * try to use 'bg' instead of 'kill -cont' in ash
 * if 'bg' doesn't work on non-child/non-job processes, 'trap' 'SIGSTOP' to run 'wait ' and 'trap' 'SIGCONT' to 'kill -kill ' in ash
 * test if we can run multiple processes and make them echo on the screen concurrently but in different region
 * Inter-process interactions: IPCs, shared resources
 * On machines with multiple processors/cores, several processes/threads may run concurrently!
 * Lock in the process being stopped/scheduled and unlock in the other processes? (using condition variables)
 * Send SIGSTOP to all other processes accessing the message queue instead of locking them to avoid deadlock issues? (use the 3rd field of /proc/ /stat to make sure a process is really stopped)
 * Use message queue of size 1 byte to simulate inter-process condition variable is that possible?
 * Understand the meaning of 'export' (such as 'export PATH') shell built-in: may it be used to exchange data between processes instead of files?


 * 1) !/bin/ash


 * 1)  Inter-process interactions:


 * 1)  Subdivide each statement/function call until each division becomes an atomic
 * 2)  operation.


 * 1)  Adding Sleep between each instruction can outstand race condtion issues?

NewTmpDir {   local Node
 * 1)  !! There is interval between @a1@ and @a2@ such that other process would
 * 2)  interfere the execution within the interval.

while :; do	Node=$RANDOM if [ ! -e /tmp/${Node} ]; then # @a1@ mkdir /tmp/${Node} # @a2@ eval "${1}=/tmp/${Node}" return fi done }

DeRef {   DeRefRes=\$$1 DeRefRes=`eval "echo $DeRefRes"` }
 * 1)  s=a
 * 2)  s=\$$s
 * 3)  s=`eval "echo $s"`
 * 4)  s=\$$s
 * 5)  s=`eval "echo $s"`

SpinAtomicXchg {   local Temp
 * 1)  Atomically exchange contents of variables indicated by $1 and the spinlock.

flock -x 8

DeRef $1 Temp="$DeRefRes" SpinLock_GetVar $1 SpinLock_SetVar $Temp

flock -u 8 }

GetPid {   local Stat Path
 * 1)  Set the PID of the calling process to the variable named in the first argument.

Path=`pwd` cd /proc/self Stat=`cat stat` cd "$Path" eval "${1}=${Stat%% *}" }

ContinueNoLock {   kill -CONT $1 }

StopNoLock {   kill -STOP $1 }

Continue {   SpinLock_Lock ContinueNoLock $1 SpinLock_Unlock }

Stop {   SpinLock_Lock StopNoLock $1 SpinLock_Unlock }

IsStopped {   local Stat

Stat=`cat /proc/${1}/stat` Stat=${Stat#* * } Stat=${Stat%% *} test "$Stat" = 'T' }

TempUnlockProc {   while :; do        if IsStopped $1; then break; fi   done SpinLock_Unlock }

GetMessage {   SpinLock_Lock if MsgQu_IsEmpty ...; then TempUnlockProc $Pid & StopNoLock $Pid # Self stopping. fi   ##  ...retrive one message and set to var indicated by $1... }

SendMessage {   local Wake
 * 1)  $1:Pointer to MsgQu $2:Message $3:Target PID

SpinLock_Lock

if MsgQu_IsFull "$1"; then TempUnlockProc ... &       ##  Add self to wait queue? StopNoLock ... # Self stopping. fi

MsgQu_IsEmpty "$1" Wake=$? echo "$2" > "${1}/`cat \"${1}/End\"`" echo $((`cat "${1}/End"` + 1)) > "${1}/End" [ $Wake -eq 0 ] && ContinueNoLock $3

SpinLock_Unlock }


 * 1)   SpinLock


 * 1)   Proc


 * 1)   MsgQu


 * 1)   Sys

NewTmpDir Root Sys_Init "$Root"

GlobalLock="${Root}/Global.lock" SpinLockVar="${Root}/SpinLock.var" # Locked:1 unlocked:0 This="${Root}/${Pid}" MessageQueue="${This}/MessageQueue"

SpinLock_Init Proc_Init MsgQu_Init




 * 1) !/bin/ash


 * 1)  Inter-process interactions:


 * 1)  Subdivide each statement/function call until each division becomes an atomic operation


 * 1)  Adding Sleep between each instruction can outstand race condtion issues?

DeRef {   DeRefRes=\$$1 DeRefRes=`eval "echo $DeRefRes"` }
 * 1)  s=a
 * 2)  s=\$$s
 * 3)  s=`eval "echo $s"`
 * 4)  s=\$$s
 * 5)  s=`eval "echo $s"`

SpinSetLockVar {   echo "$1" > "$SpinLockVar" }

SpinGetLockVar {   eval $1=`cat "$SpinLockVar"` }

SpinInit {   if [ ! -e "$SpinLockVar" ]; then SpinSetLockVar 0 fi   exec 8> "$GlobalLock" }

SpinAtomicXchg {   local Temp
 * 1)  Atomically exchange contents of variables indicated by $1 and the spinlock.

flock -x 8

DeRef $1 Temp="$DeRefRes" SpinGetLockVar $1 SpinSetLockVar $Temp

flock -u 8 }

SpinLock {   local Lock
 * 1)  We should shorten the lock time as we can, becasue processes waiting on a spin lock are essentially doing busy waiting which consume CPU resource.

Lock=1 while :; do       SpinAtomicXchg Lock if [ $Lock = 0 ]; then break; fi   done }

SpinUnlock {   local Lock

Lock=0 SpinAtomicXchg Lock # Atomic operation in case lock variable value alternation is not atomic. Unlike mutex, a spin lock may be locked in a process and unlocked in the other process. }

GetPid {   local Stat Path
 * 1)  Set the PID of the calling process to the variable named in the first argument.

Path=`pwd` cd /proc/self Stat=`cat stat` cd "$Path" eval "$1=${Stat%% *}" }

ContinueNoLock {   kill -CONT $1 }

StopNoLock {   kill -STOP $1 }

Continue {   SpinLock ContinueNoLock $1 SpinUnlock }

Stop {   SpinLock StopNoLock $1 SpinUnlock }

IsStopped {   local Stat

Stat=`cat /proc/${1}/stat` Stat=${Stat#* * } Stat=${Stat%% *} test "$Stat" = 'T' }

TempUnlockProcess {   while :; do        if IsStopped $1; then break; fi   done SpinUnlock }

GetMessage {   SpinLock if IsDirEmpty "$MessageDir"; then TempUnlockProcess $Pid & StopNoLock $Pid # Self stopping. fi   ##  ...retrive one message and set to var indicated by $1... }


 * 1) SendMessage
 * }
 * }

TaskInit {   local Pid

GetPid Pid mkdir "$This" > /dev/null 2>&1 }

MessageQueueInit {   mkdir "$MessageQueue" > /dev/null 2>&1 echo 0 > "${MessageQueue}/Begin.var" echo 0 > "${MessageQueue}/End.var" }

TaskXxx {   local Pid MessageDir Message

GetPid Pid MessageDir="${Root}/${Pid}"

## ...

while GetMessage Message; do       ProcessMessage $Message done

## ... }

local Root GlobalLock SpinLockVar

Root=/tmp/mtbv GlobalLock="${Root}/Global.lock" SpinLockVar="${Root}/SpinLock.var" # Locked:1 unlocked:0 This="${Root}/${Pid}" MessageQueue="${This}/MessageQueue"

SpinInit TaskInit MessageQueueInit



exec 8> /tmp/mtbv/aaa # In shell 1 flock -x 8 # In shell 1 (flock -x 8;) 8> /tmp/mtbv/aaa # In shell 2, and shell 2 is blocked flock -u 8 # In shell 1, and shell 2 is unblocked
 * 1) !/bin/ash

exec 8> /tmp/mtbv/aaa # In shell 1 flock -x 8 # In shell 1 (flock -x 8;) 8> /tmp/mtbv/aaa # In shell 2, and shell 2 is blocked exec 8> /dev/null # In shell 1, and shell 2 is unblocked
 * 1) !/bin/ash


 * 1) !/bin/ash


 * 1)  Adding Sleep between each instruction can outstand race condtion issues?

DeRef {   DeRefRes=\$$1 DeRefRes=`eval "echo $DeRefRes"` }
 * 1)  s=a
 * 2)  s=\$$s
 * 3)  s=`eval "echo $s"`
 * 4)  s=\$$s
 * 5)  s=`eval "echo $s"`

InitAtomicXchg {   exec 8> "$GlobalLock" }

AtomicXchg {   flock -x 8
 * 1)  Atomically exchange contents of variables indicated by $1 and $2.

DeRef $1 Temp="$DeRefRes" DeRef $2 eval "$1=$DeRefRes" eval "$2=$Temp"

flock -u 8 }

SpinLock {   local Lock
 * 1)  We should shorten the lock time as we can, becasue processes waiting on a spin lock are essentially doing busy waiting which consume CPU resource.

Lock=1 while :; do       AtomicXchg Lock $1 if [ $Lock = 0 ]; then break; fi   done }

SpinUnlock {   local Lock

Lock=0 AtomicXchg Lock $1 # Atomic operation in case lock variable value alternation is not atomic. Unlike mutex, a spin lock may be locked in a process and unlocked in the other process. }

GetPid {   local Stat Path
 * 1)  Set the PID of the calling process to the variable named in the first argument.

Path=`pwd` cd /proc/self Stat=`cat stat` cd "$Path" eval "$1=${Stat%% *}" }

ContinueNoLock {   kill -CONT $1 }

StopNoLock {   kill -STOP $1 }

Continue {   SpinLock SpinLockVar ContinueNoLock $1 SpinUnlock SpinLockVar }

Stop {   SpinLock SpinLockVar StopNoLock $1 SpinUnlock SpinLockVar }

IsStopped {   local Stat

Stat=`cat /proc/${1}/stat` Stat=${Stat#* * } Stat=${Stat%% *} test "$Stat" = 'T' }

TempUnlockProcess {   while :; do        if IsStopped $1; then break; fi   done SpinUnlock SpinLockVar }

GetMessage {   SpinLock SpinLockVar if IsDirEmpty "$MessageDir"; then TempUnlockProcess $Pid & StopNoLock $Pid # Self stopping. fi   ##  ...retrive one message and set to var indicated by $1... }

TaskXxx {   local Pid MessageDir Message

GetPid Pid MessageDir="${Root}/${Pid}"

## ...

while GetMessage Message; do       ProcessMessage $Message done

## ... }

local Root GlobalLock SpinLockVar

Root=/tmp/mtbv GlobalLock="${Root}/global.lock" SpinLockVar=0 # Locked:1 unlocked:0

InitAtomicXchg




 * 1) !/bin/ash


 * 1)  Adding Sleep between each instruction can outstand race condtion issues?

GetPid {   local Stat Path
 * 1)  Set the PID of the calling process to the variable named in the first argument.

Path=`pwd` cd /proc/self Stat=`cat stat` cd "$Path" eval "$1=${Stat%% *}" }

ContinueNoLock {   kill -CONT $1 }

StopNoLock {   kill -STOP $1 }

Continue {   (        flock -x 8        ContinueNoLock $1        ) 8> $GlobalLock }

Stop {   (        flock -x 8        StopNoLock $1        ) 8> $GlobalLock }

IsStopped {   local Stat Stat=`cat /proc/${1}/stat` Stat=${Stat#* * } Stat=${Stat%% *} test "$Stat" = 'T' }

PostUnlock {   while :; do	if IsStopped $1; then break; fi done Unlock $GlobalLock }

GetMessage {   Lock $GlobalLock if IsDirEmpty "$MessageDir"; then PostUnlock $Pid & StopNoLock $Pid # Self stopping. fi   ##  ...retrive one message and set to var indicated by $1... }

TaskXxx {   local Pid MessageDir Message

GetPid Pid MessageDir="${Root}/${Pid}"

## ...

while GetMessage Message; do	ProcessMessage $Message done

## ... }

local Root

Root=/tmp/mtbv GlobalLock="${Root}/global.lock"


 * 1) !/bin/ash

m {   local s p    p=`pwd` cd /proc/self s=`cat stat` cd "$p" eval "$1=${s%% *}" }
 * 1)  Set the PID of the calling process to variable named in the first argument.

p {   local i    echo ...beg m i   echo $i kill -stop $i echo ...end }
 * 1)  Self stopping test function.


 * 1) !/bin/bash

w {   echo '...beg w...' while :; do sleep 60; done echo '...end w...' }

c {   echo '...beg c...' echo '...end c...' }

s {   echo '...beg s...' wait $ttt # 'wait' will return (similar to WAIT(2) returns 'EINTR') when interrupted by signal like USR1 or c? echo '...end s...' }

p {   echo '...beg p...'

w & ttt=$!

trap c USR1 # Default handler terminates the program, so we make a dummy handler (do nothing) to avoid the termination trap s USR2

while :; do	echo -n '^' sleep 0.05 done

kill $ttt

echo '...end p...' }

p & echo $!


 * 1)  Use 'kill -USR2 $!' to stop/suspend p and use 'kill -USR1 $!' to continue/resume p


 * 1) !/bin/ash

echo_at {   local str str="\033[${1}H" if [ "$2" -gt 1 ]; then str="${str}\033[$(($2 - 1))C${3}" else str="${str}${3}" fi   echo -n "$str" }
 * 1)  Make text positioning and text printing done by a single 'echo' call, which
 * 2)  should reduce/eliminate the race condition when this function is called
 * 3)  within multiple processes.
 * 4)  This function doesn't add newline at the end of the output.
 * 5)  Notice that 'echo' don't accept '-e' option in 'sh' and 'ash'.
 * 1)  Notice that 'echo' don't accept '-e' option in 'sh' and 'ash'.
 * 1)  Notice that 'echo' don't accept '-e' option in 'sh' and 'ash'.

(flock -x 8; sleep 200;) 8> /tmp/kkk
 * 1)  In one of terminal window

(flock -x 7; echo ---why---;) 7> /tmp/kkk
 * 1)  In the other terminal window


 * 1) /bin/bash

g {   while :; do	echo -e "\033[${1}H" sleep `echo "0.$RANDOM"` done }

echo_at {   echo -e "\033[${1}H" sleep .1 if [ $2 -gt 1 ]; then echo -e "\033[$(($2 - 1))C${3}" else echo -e "$3" fi }

p {   while :; do	echo_at "$1" "$2" "    <$RANDOM>    " sleep `echo "0.$RANDOM"` done }

p 23 60 & g 1 & g 2 & g 3 & g 4 & g 5 & g 6 & g 7 & g 8 & g 9 & g 10 & g 11 & g 12 &


 * 1) /bin/bash

echo_at {   echo -e "\033[${1}H" if [ $2 -gt 1 ]; then echo -e "\033[$(($2 - 1))C${3}" else echo -e "$3" fi }

p {   while :; do	echo_at "$1" "$2" "    <$RANDOM>    " sleep `echo "0.$RANDOM"` done }

p {   iii=1 while :; do	echo_at "$1" "$2" "   <$iii>    " iii=$(($iii + 1)) sleep `echo "0.$RANDOM"` done }


 * 1)  (progn
 * 2)    (setq i 1)
 * 3)    (while (<= i 21)
 * 4)      (insert (format "p %d 60 & " i))
 * 5)      (setq i (1+ i))

p 1 60 & p 2 60 & p 3 60 & p 4 60 & p 5 60 & p 6 60 & p 7 60 & p 8 60 & p 9 60 & p 10 60 & p 11 60 & p 12 60 & p 13 60 & p 14 60 & p 15 60 & p 16 60 & p 17 60 & p 18 60 & p 19 60 & p 20 60 & p 21 60 &


 * 1) ttt=$(echo '$ttt $!')


 * 1) !/bin/ash

w {   echo '...beg w...' while :; do sleep 60; done echo '...end w...' }

c {   echo '...beg c...' echo $ttt kill $ttt echo '...end c...' }

s {   echo '...beg s...' w & ttt=$! echo $ttt wait $ttt echo '...end s...' }

p {   echo '...beg p...'

trap c USR1 trap s USR2

while :; do	echo '^' sleep 1 done

echo '...end p...' }



w {   echo '...beg w...' while :; do sleep 60; done echo '...end w...' }

c {   echo '...beg c...' echo $ttt kill $ttt echo '...end c...' }

s {   echo '...beg s...' w & ttt=$! echo $ttt wait $ttt echo '...end s...' }

p {   echo '...beg p...'

trap c USR1 trap s USR2

w & while :; do wait $! done

echo '...end p...' }



c {   echo '..beg c...' echo $ttt echo '..end c...' }

w {   echo '..beg w...' while :; do sleep 60; done echo '..end w...' }

p {   echo '..beg p...'

w & ttt=$! echo "ttt=$ttt" trap c CONT

w & while :; do wait $! done

echo '..end p...' }



e {   echo '..beg e...' echo '...trap...' echo '..end e...' }

w {   echo '..beg w...' ping localhost > /dev/null echo '..end w...' }

p {   echo '..beg p...' trap e CONT w & while :; do wait $! done echo '..end p...' }



w {   ping localhost > /dev/null }

p {   trap e CONT w }

p {   trap '-' CONT w }



w {   while :; do	sleep 1 done }

e {   echo '...trap...' }

p {   trap e USR1 w }