@@ -72,6 +72,19 @@ static void init_thread_tls() {
7272 ProfiledThread::initCurrentThread ();
7373}
7474
75+ // Arm the CPU timer with profiling signals blocked and open the init window
76+ // (PROF-13072). Kept noinline for the same stack-protector reason as
77+ // delete_routine_info: SignalBlocker's sigset_t must not appear in
78+ // start_routine_wrapper_spec's own stack frame on musl/aarch64.
79+ __attribute__ ((noinline))
80+ static void start_window_and_register() {
81+ SignalBlocker blocker;
82+ if (ProfiledThread *pt = ProfiledThread::currentSignalSafe ()) {
83+ pt->startInitWindow ();
84+ }
85+ Profiler::registerThread (ProfiledThread::currentTid ());
86+ }
87+
7588// Wrapper around the real start routine.
7689// The wrapper:
7790// 1. Register the newly created thread to profiler
@@ -86,10 +99,9 @@ static void* start_routine_wrapper_spec(void* args) {
8699 void * params = thr->args ();
87100 delete_routine_info (thr);
88101 init_thread_tls ();
89- int tid = ProfiledThread::currentTid ();
90- Profiler::registerThread (tid);
102+ start_window_and_register ();
91103 void * result = routine (params);
92- Profiler::unregisterThread (tid );
104+ Profiler::unregisterThread (ProfiledThread::currentTid () );
93105 ProfiledThread::release ();
94106 return result;
95107}
@@ -126,21 +138,28 @@ static void* start_routine_wrapper(void* args) {
126138 RoutineInfo* thr = (RoutineInfo*)args;
127139 func_start_routine routine;
128140 void * params;
141+ int tid;
129142 {
130143 // Block profiling signals while accessing and freeing RoutineInfo
131144 // and during TLS initialization. Under ASAN, new/delete/
132145 // pthread_setspecific are intercepted and acquire ASAN's internal
133146 // allocator lock. A profiling signal during any of these calls
134147 // runs ASAN-instrumented code that tries to acquire the same
135148 // lock, causing deadlock.
149+ // registerThread is also kept inside the blocker so that the CPU
150+ // timer is armed while SIGPROF/SIGVTALRM are masked. Any pending
151+ // signal fires only after signals are re-enabled (when the blocker
152+ // scope exits), at which point JVMThread::current() is still null
153+ // and the guard in CTimer::signalHandler discards the sample safely.
136154 SignalBlocker blocker;
137155 routine = thr->routine ();
138156 params = thr->args ();
139157 delete thr;
140158 ProfiledThread::initCurrentThread ();
159+ tid = ProfiledThread::currentTid ();
160+ ProfiledThread::currentSignalSafe ()->startInitWindow ();
161+ Profiler::registerThread (tid);
141162 }
142- int tid = ProfiledThread::currentTid ();
143- Profiler::registerThread (tid);
144163 void * result = nullptr ;
145164 // Handle pthread_exit() bypass - the thread calls pthread_exit()
146165 // instead of normal termination
0 commit comments