llvm/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/main.cpp

// This test will present lldb with two threads one of which the test will
// overlay with an OSPlugin thread.  Then we'll do a step out on the thread_1,
// but arrange to hit a breakpoint in main before the step out completes. At
// that point we will not report an OS plugin thread for thread_1. Then we'll
// run again and hit the step out breakpoint.  Make sure we haven't deleted
// that, and recognize it.

#include <condition_variable>
#include <mutex>
#include <stdio.h>
#include <thread>

static int g_value = 0; // I don't have access to the real threads in the
                        // OS Plugin, and I don't want to have to count
                        // StopID's. So I'm using this value to tell me which
                        // stop point the program has reached.
std::mutex g_mutex;
std::condition_variable g_cv;
static int g_condition = 0; // Using this as the variable backing g_cv
                            // to prevent spurious wakeups.

void step_out_of_here() {
  std::unique_lock<std::mutex> func_lock(g_mutex);
  // Set a breakpoint:first stop in thread - do a step out.
  g_condition = 1;
  g_cv.notify_one();
  g_cv.wait(func_lock, [&] { return g_condition == 2; });
}

void *thread_func() {
  // Do something
  step_out_of_here();

  // Return
  return NULL;
}

int main() {
  // Lock the mutex so we can block the thread:
  std::unique_lock<std::mutex> main_lock(g_mutex);
  // Create the thread
  std::thread thread_1(thread_func);
  g_cv.wait(main_lock, [&] { return g_condition == 1; });
  g_value = 1;
  g_condition = 2;
  // Stop here and do not make a memory thread for thread_1.
  g_cv.notify_one();
  g_value = 2;
  main_lock.unlock();

  // Wait for the threads to finish
  thread_1.join();

  return 0;
}