void SamplingProfiler::UnwindStackHandler()

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();
    }
  }
}