@@ -68,6 +68,13 @@ def __init__(self):
6868 self ._exitcode = None
6969 self ._reentrant_messages = deque ()
7070
71+ # True to use colon-separated lines, rather than JSON lines,
72+ # for internal communication. (Mainly for testing).
73+ # Filenames not supported by the simple format will always be sent
74+ # using JSON.
75+ # The reader should understand all formats.
76+ self ._use_simple_format = False
77+
7178 def _reentrant_call_error (self ):
7279 # gh-109629: this happens if an explicit call to the ResourceTracker
7380 # gets interrupted by a garbage collection, invoking a finalizer (*)
@@ -200,7 +207,9 @@ def _launch(self):
200207 os .close (r )
201208
202209 def _make_probe_message (self ):
203- """Return a JSON-encoded probe message."""
210+ """Return a probe message."""
211+ if self ._use_simple_format :
212+ return b'PROBE:0:noop\n '
204213 return (
205214 json .dumps (
206215 {"cmd" : "PROBE" , "rtype" : "noop" },
@@ -267,6 +276,15 @@ def _write(self, msg):
267276 assert nbytes == len (msg ), f"{ nbytes = } != { len (msg )= } "
268277
269278 def _send (self , cmd , name , rtype ):
279+ if self ._use_simple_format and '\n ' not in name :
280+ msg = f"{ cmd } :{ name } :{ rtype } \n " .encode ("ascii" )
281+ if len (msg ) > 512 :
282+ # posix guarantees that writes to a pipe of less than PIPE_BUF
283+ # bytes are atomic, and that PIPE_BUF >= 512
284+ raise ValueError ('msg too long' )
285+ self ._ensure_running_and_write (msg )
286+ return
287+
270288 # POSIX guarantees that writes to a pipe of less than PIPE_BUF (512 on Linux)
271289 # bytes are atomic. Therefore, we want the message to be shorter than 512 bytes.
272290 # POSIX shm_open() and sem_open() require the name, including its leading slash,
@@ -286,6 +304,7 @@ def _send(self, cmd, name, rtype):
286304
287305 # The entire JSON message is guaranteed < PIPE_BUF (512 bytes) by construction.
288306 assert len (msg ) <= 512 , f"internal error: message too long ({ len (msg )} bytes)"
307+ assert msg .startswith (b'{' )
289308
290309 self ._ensure_running_and_write (msg )
291310
@@ -296,6 +315,30 @@ def _send(self, cmd, name, rtype):
296315getfd = _resource_tracker .getfd
297316
298317
318+ def _decode_message (line ):
319+ if line .startswith (b'{' ):
320+ try :
321+ obj = json .loads (line .decode ('ascii' ))
322+ except Exception as e :
323+ raise ValueError ("malformed resource_tracker message: %r" % (line ,)) from e
324+
325+ cmd = obj ["cmd" ]
326+ rtype = obj ["rtype" ]
327+ b64 = obj .get ("base64_name" , "" )
328+
329+ if not isinstance (cmd , str ) or not isinstance (rtype , str ) or not isinstance (b64 , str ):
330+ raise ValueError ("malformed resource_tracker fields: %r" % (obj ,))
331+
332+ try :
333+ name = base64 .urlsafe_b64decode (b64 ).decode ('utf-8' , 'surrogateescape' )
334+ except ValueError as e :
335+ raise ValueError ("malformed resource_tracker base64_name: %r" % (b64 ,)) from e
336+ else :
337+ cmd , rest = line .strip ().decode ('ascii' ).split (':' , maxsplit = 1 )
338+ name , rtype = rest .rsplit (':' , maxsplit = 1 )
339+ return cmd , rtype , name
340+
341+
299342def main (fd ):
300343 '''Run resource tracker.'''
301344 # protect the process from ^C and "killall python" etc
@@ -318,23 +361,7 @@ def main(fd):
318361 with open (fd , 'rb' ) as f :
319362 for line in f :
320363 try :
321- try :
322- obj = json .loads (line .decode ('ascii' ))
323- except Exception as e :
324- raise ValueError ("malformed resource_tracker message: %r" % (line ,)) from e
325-
326- cmd = obj ["cmd" ]
327- rtype = obj ["rtype" ]
328- b64 = obj .get ("base64_name" , "" )
329-
330- if not isinstance (cmd , str ) or not isinstance (rtype , str ) or not isinstance (b64 , str ):
331- raise ValueError ("malformed resource_tracker fields: %r" % (obj ,))
332-
333- try :
334- name = base64 .urlsafe_b64decode (b64 ).decode ('utf-8' , 'surrogateescape' )
335- except ValueError as e :
336- raise ValueError ("malformed resource_tracker base64_name: %r" % (b64 ,)) from e
337-
364+ cmd , rtype , name = _decode_message (line )
338365 cleanup_func = _CLEANUP_FUNCS .get (rtype , None )
339366 if cleanup_func is None :
340367 raise ValueError (
0 commit comments