xref: /llvm-project/lldb/test/API/commands/expression/no-deadlock/locking.cpp (revision 99451b4453688a94c6014cac233d371ab4cc342d)
1*99451b44SJordan Rupprecht #include <stdio.h>
2*99451b44SJordan Rupprecht #include <thread>
3*99451b44SJordan Rupprecht #include <mutex>
4*99451b44SJordan Rupprecht #include <condition_variable>
5*99451b44SJordan Rupprecht 
6*99451b44SJordan Rupprecht std::mutex contended_mutex;
7*99451b44SJordan Rupprecht 
8*99451b44SJordan Rupprecht std::mutex control_mutex;
9*99451b44SJordan Rupprecht std::condition_variable  control_condition;
10*99451b44SJordan Rupprecht 
11*99451b44SJordan Rupprecht std::mutex thread_started_mutex;
12*99451b44SJordan Rupprecht std::condition_variable  thread_started_condition;
13*99451b44SJordan Rupprecht 
14*99451b44SJordan Rupprecht // This function runs in a thread.  The locking dance is to make sure that
15*99451b44SJordan Rupprecht // by the time the main thread reaches the pthread_join below, this thread
16*99451b44SJordan Rupprecht // has for sure acquired the contended_mutex.  So then the call_me_to_get_lock
17*99451b44SJordan Rupprecht // function will block trying to get the mutex, and only succeed once it
18*99451b44SJordan Rupprecht // signals this thread, then lets it run to wake up from the cond_wait and
19*99451b44SJordan Rupprecht // release the mutex.
20*99451b44SJordan Rupprecht 
21*99451b44SJordan Rupprecht void
lock_acquirer_1(void)22*99451b44SJordan Rupprecht lock_acquirer_1 (void)
23*99451b44SJordan Rupprecht {
24*99451b44SJordan Rupprecht   std::unique_lock<std::mutex> contended_lock(contended_mutex);
25*99451b44SJordan Rupprecht 
26*99451b44SJordan Rupprecht   // Grab this mutex, that will ensure that the main thread
27*99451b44SJordan Rupprecht   // is in its cond_wait for it (since that's when it drops the mutex.
28*99451b44SJordan Rupprecht 
29*99451b44SJordan Rupprecht   thread_started_mutex.lock();
30*99451b44SJordan Rupprecht   thread_started_mutex.unlock();
31*99451b44SJordan Rupprecht 
32*99451b44SJordan Rupprecht   // Now signal the main thread that it can continue, we have the contended lock
33*99451b44SJordan Rupprecht   // so the call to call_me_to_get_lock won't make any progress till  this
34*99451b44SJordan Rupprecht   // thread gets a chance to run.
35*99451b44SJordan Rupprecht 
36*99451b44SJordan Rupprecht   std::unique_lock<std::mutex> control_lock(control_mutex);
37*99451b44SJordan Rupprecht 
38*99451b44SJordan Rupprecht   thread_started_condition.notify_all();
39*99451b44SJordan Rupprecht 
40*99451b44SJordan Rupprecht   control_condition.wait(control_lock);
41*99451b44SJordan Rupprecht 
42*99451b44SJordan Rupprecht }
43*99451b44SJordan Rupprecht 
44*99451b44SJordan Rupprecht int
call_me_to_get_lock(int ret_val)45*99451b44SJordan Rupprecht call_me_to_get_lock (int ret_val)
46*99451b44SJordan Rupprecht {
47*99451b44SJordan Rupprecht   control_condition.notify_all();
48*99451b44SJordan Rupprecht   contended_mutex.lock();
49*99451b44SJordan Rupprecht   return ret_val;
50*99451b44SJordan Rupprecht }
51*99451b44SJordan Rupprecht 
52*99451b44SJordan Rupprecht int
get_int()53*99451b44SJordan Rupprecht get_int() {
54*99451b44SJordan Rupprecht   return 567;
55*99451b44SJordan Rupprecht }
56*99451b44SJordan Rupprecht 
main()57*99451b44SJordan Rupprecht int main ()
58*99451b44SJordan Rupprecht {
59*99451b44SJordan Rupprecht   std::unique_lock<std::mutex> thread_started_lock(thread_started_mutex);
60*99451b44SJordan Rupprecht 
61*99451b44SJordan Rupprecht   std::thread thread_1(lock_acquirer_1);
62*99451b44SJordan Rupprecht 
63*99451b44SJordan Rupprecht   thread_started_condition.wait(thread_started_lock);
64*99451b44SJordan Rupprecht 
65*99451b44SJordan Rupprecht   control_mutex.lock();
66*99451b44SJordan Rupprecht   control_mutex.unlock();
67*99451b44SJordan Rupprecht 
68*99451b44SJordan Rupprecht   // Break here.  At this point the other thread will have the contended_mutex,
69*99451b44SJordan Rupprecht   // and be sitting in its cond_wait for the control condition.  So there is
70*99451b44SJordan Rupprecht   // no way that our by-hand calling of call_me_to_get_lock will proceed
71*99451b44SJordan Rupprecht   // without running the first thread at least somewhat.
72*99451b44SJordan Rupprecht 
73*99451b44SJordan Rupprecht   int result = call_me_to_get_lock(get_int());
74*99451b44SJordan Rupprecht   thread_1.join();
75*99451b44SJordan Rupprecht 
76*99451b44SJordan Rupprecht   return 0;
77*99451b44SJordan Rupprecht 
78*99451b44SJordan Rupprecht }
79