You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

125 lines
3.3 KiB

import sys
import time
import asyncio
from subprocess import Popen, PIPE
RESET = "\033[0m"
C = "\033[32m" # Child color green
P = "\033[33m" # Parent color yellow
def usage():
print("Usage:")
print(" stdin_race.py pump <persecond> <maxcount>")
print(" stdin_race.py parent")
print(" stdin_race.py child <delay_ms>")
print("\nExample:")
print(" python stdin_race.py pump 35 50 | python stdin_race.py parent")
sys.exit(1)
async def pump(persecond, maxcount):
if persecond > 1000:
print("WARNING: (>1000) sub-millisecond scheduling not available - will go full speed", file=sys.stderr)
await asyncio.sleep(0.5)
counter = -1
ms = 1000 / persecond
async def pump_emit():
nonlocal counter
try:
counter += 1
print(f".{counter}", end="", flush=True)
except BrokenPipeError:
return False
return True
async def pump_schedule():
nonlocal counter
while maxcount <= 0 or counter < maxcount - 1:
if not await pump_emit():
break
await asyncio.sleep(ms / 1000)
print("pump-done", file=sys.stderr, flush=True)
await pump_schedule()
async def parent():
print(f"{P}parent{RESET}", file=sys.stderr, flush=True)
await asyncio.sleep(0.25)
# Read the first chunk from stdin
parent_chunk1 = sys.stdin.read(8)
print(f"{P}{parent_chunk1}{RESET}", file=sys.stderr, flush=True)
# Launch the child process
child_proc = Popen(
[sys.executable, __file__, "child", "150"],
stdin=sys.stdin, stdout=PIPE, stderr=sys.stderr, text=True
)
# Forward stdin to the child process
#while True:
# chunk = sys.stdin.read(1)
# if not chunk:
# break
# try:
# child_proc.stdin.write(chunk)
# #child_proc.stdin.flush()
# except BrokenPipeError:
# print("Broken pipe error, child process may have exited.", file=sys.stderr)
# break
child_proc.wait()
#child_proc.wait()
print("parent-tail-read", file=sys.stderr, flush=True)
while True:
chunk = sys.stdin.read(1)
if not chunk:
break
print(chunk, end="", file=sys.stderr, flush=True)
print(f"\n{P}parent-done{RESET}", flush=True)
async def child(delay_ms):
print(f"\n{C}child{RESET}", file=sys.stderr, flush=True)
await asyncio.sleep(delay_ms / 1000)
# Read exactly 16 characters from stdin
chunk = sys.stdin.read(16)
print(f"{C}{chunk}{RESET}", file=sys.stderr, flush=True)
print("child-done", file=sys.stderr, flush=True)
sys.exit(0)
def main():
if len(sys.argv) < 2:
usage()
role = sys.argv[1]
if role == "pump":
if len(sys.argv) != 4:
usage()
persecond = int(sys.argv[2])
maxcount = int(sys.argv[3])
asyncio.run(pump(persecond, maxcount))
elif role == "parent":
if len(sys.argv) != 2:
usage()
asyncio.run(parent())
elif role == "child":
if len(sys.argv) != 3:
usage()
delay_ms = int(sys.argv[2])
asyncio.run(child(delay_ms))
else:
usage()
if __name__ == "__main__":
main()