@@ -236,6 +236,7 @@ def __init__(self, frequency, options, sdk_info, capture_func):
236236 self .pid = None # type: Optional[int]
237237
238238 self .running = False
239+ self .soft_shutdown = False
239240
240241 self .new_profiles = deque (maxlen = 128 ) # type: Deque[ContinuousProfile]
241242 self .active_profiles = set () # type: Set[ContinuousProfile]
@@ -317,24 +318,23 @@ def profiler_id(self):
317318 return self .buffer .profiler_id
318319
319320 def make_sampler (self ):
320- # type: () -> Callable[..., None ]
321+ # type: () -> Callable[..., bool ]
321322 cwd = os .getcwd ()
322323
323324 cache = LRUCache (max_size = 256 )
324325
325326 if self .lifecycle == "trace" :
326327
327328 def _sample_stack (* args , ** kwargs ):
328- # type: (*Any, **Any) -> None
329+ # type: (*Any, **Any) -> bool
329330 """
330331 Take a sample of the stack on all the threads in the process.
331332 This should be called at a regular interval to collect samples.
332333 """
333334
334335 # no profiles taking place, so we can stop early
335336 if not self .new_profiles and not self .active_profiles :
336- self .running = False
337- return
337+ return True
338338
339339 # This is the number of profiles we want to pop off.
340340 # It's possible another thread adds a new profile to
@@ -357,7 +357,7 @@ def _sample_stack(*args, **kwargs):
357357 # For some reason, the frame we get doesn't have certain attributes.
358358 # When this happens, we abandon the current sample as it's bad.
359359 capture_internal_exception (sys .exc_info ())
360- return
360+ return False
361361
362362 # Move the new profiles into the active_profiles set.
363363 #
@@ -374,9 +374,7 @@ def _sample_stack(*args, **kwargs):
374374 inactive_profiles = []
375375
376376 for profile in self .active_profiles :
377- if profile .active :
378- pass
379- else :
377+ if not profile .active :
380378 # If a profile is marked inactive, we buffer it
381379 # to `inactive_profiles` so it can be removed.
382380 # We cannot remove it here as it would result
@@ -389,10 +387,12 @@ def _sample_stack(*args, **kwargs):
389387 if self .buffer is not None :
390388 self .buffer .write (ts , sample )
391389
390+ return False
391+
392392 else :
393393
394394 def _sample_stack (* args , ** kwargs ):
395- # type: (*Any, **Any) -> None
395+ # type: (*Any, **Any) -> bool
396396 """
397397 Take a sample of the stack on all the threads in the process.
398398 This should be called at a regular interval to collect samples.
@@ -409,19 +409,21 @@ def _sample_stack(*args, **kwargs):
409409 # For some reason, the frame we get doesn't have certain attributes.
410410 # When this happens, we abandon the current sample as it's bad.
411411 capture_internal_exception (sys .exc_info ())
412- return
412+ return False
413413
414414 if self .buffer is not None :
415415 self .buffer .write (ts , sample )
416416
417+ return False
418+
417419 return _sample_stack
418420
419421 def run (self ):
420422 # type: () -> None
421423 last = time .perf_counter ()
422424
423425 while self .running :
424- self .sampler ()
426+ self .soft_shutdown = self . sampler ()
425427
426428 # some time may have elapsed since the last time
427429 # we sampled, so we need to account for that and
@@ -430,6 +432,15 @@ def run(self):
430432 if elapsed < self .interval :
431433 thread_sleep (self .interval - elapsed )
432434
435+ # the soft shutdown happens here to give it a chance
436+ # for the profiler to be reused
437+ if self .soft_shutdown :
438+ self .running = False
439+
440+ # make sure to explicitly exit the profiler here or there might
441+ # be multiple profilers at once
442+ break
443+
433444 # after sleeping, make sure to take the current
434445 # timestamp so we can use it next iteration
435446 last = time .perf_counter ()
@@ -458,6 +469,8 @@ def __init__(self, frequency, options, sdk_info, capture_func):
458469 def ensure_running (self ):
459470 # type: () -> None
460471
472+ self .soft_shutdown = False
473+
461474 pid = os .getpid ()
462475
463476 # is running on the right process
@@ -532,6 +545,9 @@ def __init__(self, frequency, options, sdk_info, capture_func):
532545
533546 def ensure_running (self ):
534547 # type: () -> None
548+
549+ self .soft_shutdown = False
550+
535551 pid = os .getpid ()
536552
537553 # is running on the right process
0 commit comments