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
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()
|
|
|