@@ -207,6 +207,7 @@ def __init__(self, frequency, options, sdk_info, capture_func):
207207 self .pid = None # type: Optional[int]
208208
209209 self .running = False
210+ self .soft_shutdown = False
210211
211212 self .new_profiles = deque (maxlen = 128 ) # type: Deque[ContinuousProfile]
212213 self .active_profiles = set () # type: Set[ContinuousProfile]
@@ -288,24 +289,23 @@ def profiler_id(self):
288289 return self .buffer .profiler_id
289290
290291 def make_sampler (self ):
291- # type: () -> Callable[..., None ]
292+ # type: () -> Callable[..., bool ]
292293 cwd = os .getcwd ()
293294
294295 cache = LRUCache (max_size = 256 )
295296
296297 if self .lifecycle == "trace" :
297298
298299 def _sample_stack (* args , ** kwargs ):
299- # type: (*Any, **Any) -> None
300+ # type: (*Any, **Any) -> bool
300301 """
301302 Take a sample of the stack on all the threads in the process.
302303 This should be called at a regular interval to collect samples.
303304 """
304305
305306 # no profiles taking place, so we can stop early
306307 if not self .new_profiles and not self .active_profiles :
307- self .running = False
308- return
308+ return True
309309
310310 # This is the number of profiles we want to pop off.
311311 # It's possible another thread adds a new profile to
@@ -328,7 +328,7 @@ def _sample_stack(*args, **kwargs):
328328 # For some reason, the frame we get doesn't have certain attributes.
329329 # When this happens, we abandon the current sample as it's bad.
330330 capture_internal_exception (sys .exc_info ())
331- return
331+ return False
332332
333333 # Move the new profiles into the active_profiles set.
334334 #
@@ -345,9 +345,7 @@ def _sample_stack(*args, **kwargs):
345345 inactive_profiles = []
346346
347347 for profile in self .active_profiles :
348- if profile .active :
349- pass
350- else :
348+ if not profile .active :
351349 # If a profile is marked inactive, we buffer it
352350 # to `inactive_profiles` so it can be removed.
353351 # We cannot remove it here as it would result
@@ -360,10 +358,12 @@ def _sample_stack(*args, **kwargs):
360358 if self .buffer is not None :
361359 self .buffer .write (ts , sample )
362360
361+ return False
362+
363363 else :
364364
365365 def _sample_stack (* args , ** kwargs ):
366- # type: (*Any, **Any) -> None
366+ # type: (*Any, **Any) -> bool
367367 """
368368 Take a sample of the stack on all the threads in the process.
369369 This should be called at a regular interval to collect samples.
@@ -380,19 +380,21 @@ def _sample_stack(*args, **kwargs):
380380 # For some reason, the frame we get doesn't have certain attributes.
381381 # When this happens, we abandon the current sample as it's bad.
382382 capture_internal_exception (sys .exc_info ())
383- return
383+ return False
384384
385385 if self .buffer is not None :
386386 self .buffer .write (ts , sample )
387387
388+ return False
389+
388390 return _sample_stack
389391
390392 def run (self ):
391393 # type: () -> None
392394 last = time .perf_counter ()
393395
394396 while self .running :
395- self .sampler ()
397+ self .soft_shutdown = self . sampler ()
396398
397399 # some time may have elapsed since the last time
398400 # we sampled, so we need to account for that and
@@ -401,6 +403,15 @@ def run(self):
401403 if elapsed < self .interval :
402404 thread_sleep (self .interval - elapsed )
403405
406+ # the soft shutdown happens here to give it a chance
407+ # for the profiler to be reused
408+ if self .soft_shutdown :
409+ self .running = False
410+
411+ # make sure to explicitly exit the profiler here or there might
412+ # be multiple profilers at once
413+ break
414+
404415 # after sleeping, make sure to take the current
405416 # timestamp so we can use it next iteration
406417 last = time .perf_counter ()
@@ -429,6 +440,8 @@ def __init__(self, frequency, options, sdk_info, capture_func):
429440 def ensure_running (self ):
430441 # type: () -> None
431442
443+ self .soft_shutdown = False
444+
432445 pid = os .getpid ()
433446
434447 # is running on the right process
@@ -503,6 +516,9 @@ def __init__(self, frequency, options, sdk_info, capture_func):
503516
504517 def ensure_running (self ):
505518 # type: () -> None
519+
520+ self .soft_shutdown = False
521+
506522 pid = os .getpid ()
507523
508524 # is running on the right process
0 commit comments