in cpp/profiler/SamplingProfiler.cpp [137:240]
void SamplingProfiler::UnwindStackHandler(
SignalHandler::HandlerScope scope,
int signum,
siginfo_t* siginfo,
void* ucontext) {
SamplingProfiler& profiler = *(SamplingProfiler*)scope.GetData();
ProfileState& state = profiler.state_;
uint64_t tid = threadID();
uint64_t busyState = (tid << 16) | StackSlotState::BUSY_WITH_METADATA;
for (const auto& tracerEntry : state.tracersMap) {
auto tracerType = tracerEntry.first;
if (!(tracerType & state.currentTracers)) {
continue;
}
// The external tracer is frequently disabled, so fail fast here
// if that is the case
if (ExternalTracer::isExternalTracer(tracerType)) {
if (!static_cast<ExternalTracer*>(tracerEntry.second.get())
->isEnabled()) {
continue;
}
}
uint32_t slotIndex;
bool slot_found = getSlotIndex(state, tid, slotIndex);
if (!slot_found) {
// We're out of slots, no tracer is likely to succeed.
break;
}
auto& slot = state.stacks[slotIndex];
// Can finally occupy the slot
if (sigsetjmp(slot.sig_jmp_buf, 1) == 0) {
memset(slot.method_names, 0, sizeof(slot.method_names));
memset(slot.class_descriptors, 0, sizeof(slot.class_descriptors));
uint8_t ret{StackSlotState::FREE};
if (JavaBaseTracer::isJavaTracer(tracerType)) {
ret = reinterpret_cast<JavaBaseTracer*>(tracerEntry.second.get())
->collectJavaStack(
(ucontext_t*)ucontext,
slot.frames,
slot.method_names,
slot.class_descriptors,
slot.depth,
MAX_STACK_DEPTH);
} else {
ret = tracerEntry.second->collectStack(
(ucontext_t*)ucontext, slot.frames, slot.depth, MAX_STACK_DEPTH);
}
slot.profilerType = tracerType;
if (StackCollectionRetcode::STACK_OVERFLOW == ret) {
state.errStackOverflows.fetch_add(1);
}
slot.timerType = ThreadTimer::decodeType(siginfo->si_value.sival_int);
// Ignore TRACER_DISABLED errors for now and free the slot.
// TODO T42938550
if (StackCollectionRetcode::TRACER_DISABLED == ret) {
if (!slot.state.compare_exchange_strong(
busyState, StackSlotState::FREE)) {
abortWithReason(
"Invariant violation - BUSY_WITH_METADATA to FREE failed");
}
continue;
}
auto nextSlotState = (tid << 16) | ret;
// In case if a Tracer class handles collection on it's own the slot is
// freed after the signal is processed.
if (ret == StackCollectionRetcode::IGNORE) {
nextSlotState = StackSlotState::FREE;
}
if (!slot.state.compare_exchange_strong(busyState, nextSlotState)) {
// Slot was overwritten by another thread.
// This is an ordering violation, so abort.
abortWithReason(
"Invariant violation - BUSY_WITH_METADATA to return code failed");
}
if (nextSlotState != StackSlotState::FREE) {
profiler.maybeSignalReader();
}
} else {
// We came from the longjmp in sigcatch_handler.
// Something must have crashed.
// Log the error information and bail out
slot.time = monotonicTime();
slot.profilerType = tracerType;
if (!slot.state.compare_exchange_strong(
busyState,
(tid << 16) | StackCollectionRetcode::SIGNAL_INTERRUPT)) {
abortWithReason(
"Invariant violation - BUSY_WITH_METADATA to SIGNAL_INTERRUPT failed");
}
profiler.maybeSignalReader();
}
}
}