◐ Shell
clean mode source ↗

`sys._setprofileallthreads` race condition

There's a race on tstate->c_profilefunc if profiling is disable concurrently via sys._setprofileallthreads or threading.setprofile_all_threads or PyEval_SetProfileAllThreads.

import sys
import threading

done = threading.Event()

def foo():
    pass

def my_profile(frame, event, arg):
    return None

def bg_thread():
    while not done.is_set():
        foo()
        foo()
        foo()
        foo()
        foo()
        foo()
        foo()
        foo()
        foo()
        foo()
    

def main():
    bg_threads = []
    for i in range(10):
        t = threading.Thread(target=bg_thread)
        t.start()
        bg_threads.append(t)

    for i in range(100):
        print(f"Iteration {i}")
        sys._setprofileallthreads(my_profile)
        sys._setprofileallthreads(None)

    done.set()
    for t in bg_threads:
        t.join()

    
if __name__ == "__main__":
    main()