1717import signal
1818import subprocess
1919import sys
20+ import tempfile
2021import time
2122from dataclasses import dataclass
2223
@@ -105,6 +106,31 @@ def append_log(path: pathlib.Path, message: str) -> None:
105106 stream .write ("\n " )
106107
107108
109+ def publish_barrier_file (path : pathlib .Path , text : str ) -> None :
110+ """Publish a barrier file so a poller sees either no file or its content.
111+
112+ Path.write_text creates and truncates before it writes, so a reader that
113+ polls for existence and then parses the content can observe the zero-byte
114+ window in between. Write next to the destination and rename into place.
115+ """
116+ with tempfile .NamedTemporaryFile (
117+ mode = "w" ,
118+ encoding = "utf-8" ,
119+ newline = "\n " ,
120+ dir = path .parent ,
121+ prefix = f".{ path .name } ." ,
122+ delete = False ,
123+ ) as temporary :
124+ temporary .write (text )
125+ temporary .flush ()
126+ temporary_path = pathlib .Path (temporary .name )
127+ try :
128+ os .replace (temporary_path , path )
129+ except BaseException :
130+ temporary_path .unlink (missing_ok = True )
131+ raise
132+
133+
108134def start_suite (
109135 suite : str ,
110136 runner_command : list [str ],
@@ -288,12 +314,12 @@ def wait_for_test_pre_terminate_barrier(
288314 ready = barrier_dir / f"{ active .name } .ready"
289315 leader_exited = barrier_dir / f"{ active .name } .leader-exited"
290316 release = barrier_dir / f"{ active .name } .release"
291- ready . write_text ( f"{ active .process .pid } \n " , encoding = "utf-8 " )
317+ publish_barrier_file ( ready , f"{ active .process .pid } \n " )
292318 deadline = time .monotonic () + 10
293319 while not release .exists ():
294320 returncode = active .process .poll ()
295321 if returncode is not None and not leader_exited .exists ():
296- leader_exited . write_text ( f"{ returncode } \n " , encoding = "utf-8 " )
322+ publish_barrier_file ( leader_exited , f"{ returncode } \n " )
297323 if time .monotonic () >= deadline :
298324 raise RuntimeError (
299325 f"test pre-terminate barrier for { active .name !r} was not released"
@@ -312,7 +338,7 @@ def wait_for_test_post_exit_barrier(
312338 return
313339 ready = barrier_dir / f"{ suite } .ready"
314340 release = barrier_dir / f"{ suite } .release"
315- ready . write_text ( "child exited; result intentionally not recorded\n " , encoding = "utf-8 " )
341+ publish_barrier_file ( ready , "child exited; result intentionally not recorded\n " )
316342 deadline = time .monotonic () + 10
317343 while not release .exists ():
318344 if time .monotonic () >= deadline :
0 commit comments