Index: test/functionalities/expr-doesnt-deadlock/Makefile =================================================================== --- test/functionalities/expr-doesnt-deadlock/Makefile +++ test/functionalities/expr-doesnt-deadlock/Makefile @@ -1,6 +1,6 @@ LEVEL = ../../make -C_SOURCES := locking.c +CXX_SOURCES := locking.cpp ENABLE_THREADS := YES include $(LEVEL)/Makefile.rules Index: test/functionalities/expr-doesnt-deadlock/TestExprDoesntBlock.py =================================================================== --- test/functionalities/expr-doesnt-deadlock/TestExprDoesntBlock.py +++ test/functionalities/expr-doesnt-deadlock/TestExprDoesntBlock.py @@ -44,7 +44,7 @@ # Now create a breakpoint at source line before call_me_to_get_lock gets called. - main_file_spec = lldb.SBFileSpec ("locking.c") + main_file_spec = lldb.SBFileSpec ("locking.cpp") breakpoint = target.BreakpointCreateBySourceRegex('Break here', main_file_spec) if self.TraceOn(): print "breakpoint:", breakpoint Index: test/functionalities/expr-doesnt-deadlock/locking.c =================================================================== --- test/functionalities/expr-doesnt-deadlock/locking.c +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include -#include -#include - -pthread_mutex_t contended_mutex = PTHREAD_MUTEX_INITIALIZER; - -pthread_mutex_t control_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t control_condition; - -pthread_mutex_t thread_started_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t thread_started_condition; - -// This function runs in a thread. The locking dance is to make sure that -// by the time the main thread reaches the pthread_join below, this thread -// has for sure acquired the contended_mutex. So then the call_me_to_get_lock -// function will block trying to get the mutex, and only succeed once it -// signals this thread, then lets it run to wake up from the cond_wait and -// release the mutex. - -void * -lock_acquirer_1 (void *input) -{ - pthread_mutex_lock (&contended_mutex); - - // Grab this mutex, that will ensure that the main thread - // is in its cond_wait for it (since that's when it drops the mutex. - - pthread_mutex_lock (&thread_started_mutex); - pthread_mutex_unlock(&thread_started_mutex); - - // Now signal the main thread that it can continue, we have the contended lock - // so the call to call_me_to_get_lock won't make any progress till this - // thread gets a chance to run. - - pthread_mutex_lock (&control_mutex); - - pthread_cond_signal (&thread_started_condition); - - pthread_cond_wait (&control_condition, &control_mutex); - - pthread_mutex_unlock (&contended_mutex); - return NULL; -} - -int -call_me_to_get_lock () -{ - pthread_cond_signal (&control_condition); - pthread_mutex_lock (&contended_mutex); - return 567; -} - -int main () -{ - pthread_t thread_1; - - pthread_cond_init (&control_condition, NULL); - pthread_cond_init (&thread_started_condition, NULL); - - pthread_mutex_lock (&thread_started_mutex); - - pthread_create (&thread_1, NULL, lock_acquirer_1, NULL); - - pthread_cond_wait (&thread_started_condition, &thread_started_mutex); - - pthread_mutex_lock (&control_mutex); - pthread_mutex_unlock (&control_mutex); - - // Break here. At this point the other thread will have the contended_mutex, - // and be sitting in its cond_wait for the control condition. So there is - // no way that our by-hand calling of call_me_to_get_lock will proceed - // without running the first thread at least somewhat. - - call_me_to_get_lock(); - pthread_join (thread_1, NULL); - - return 0; - -} Index: test/functionalities/expr-doesnt-deadlock/locking.cpp =================================================================== --- /dev/null +++ test/functionalities/expr-doesnt-deadlock/locking.cpp @@ -0,0 +1,80 @@ +#include +#include + +#include +#include +#include + +std::mutex contended_mutex; +std::mutex control_mutex; +std::mutex thread_started_mutex; + +std::unique_lock *contended_lock = nullptr; +std::unique_lock *control_lock = nullptr; +std::unique_lock *thread_started_lock = nullptr; + +std::condition_variable control_condition; +std::condition_variable thread_started_condition; + +// This function runs in a thread. The locking dance is to make sure that +// by the time the main thread reaches the pthread_join below, this thread +// has for sure acquired the contended_mutex. So then the call_me_to_get_lock +// function will block trying to get the mutex, and only succeed once it +// signals this thread, then lets it run to wake up from the cond_wait and +// release the mutex. + +void * +lock_acquirer_1 () +{ + contended_lock->lock(); + + // Grab this mutex, that will ensure that the main thread + // is in its cond_wait for it (since that's when it drops the mutex. + thread_started_lock->lock(); + thread_started_lock->unlock(); + + // Now signal the main thread that it can continue, we have the contended lock + // so the call to call_me_to_get_lock won't make any progress till this + // thread gets a chance to run. + control_lock->lock(); + + thread_started_condition.notify_all(); + control_condition.wait(*control_lock); + + return NULL; +} + +int +call_me_to_get_lock () +{ + control_condition.notify_all(); + contended_lock->lock(); + return 567; +} + +int main () +{ + contended_lock = new std::unique_lock(contended_mutex, std::defer_lock); + control_lock = new std::unique_lock(control_mutex, std::defer_lock); + thread_started_lock = new std::unique_lock(thread_started_mutex, std::defer_lock); + + thread_started_lock->lock(); + + std::thread thread_1(lock_acquirer_1); + + thread_started_condition.wait(*thread_started_lock); + + control_lock->lock(); + control_lock->unlock(); + + // Break here. At this point the other thread will have the contended_mutex, + // and be sitting in its cond_wait for the control condition. So there is + // no way that our by-hand calling of call_me_to_get_lock will proceed + // without running the first thread at least somewhat. + + call_me_to_get_lock(); + thread_1.join(); + + return 0; + +} Index: test/functionalities/thread/create_during_step/main.cpp =================================================================== --- test/functionalities/thread/create_during_step/main.cpp +++ test/functionalities/thread/create_during_step/main.cpp @@ -10,8 +10,8 @@ // This test is intended to create a situation in which one thread will be // created while the debugger is stepping in another thread. -#include #include +#include // Note that although hogging the CPU while waiting for a variable to change // would be terrible in production code, it's great for testing since it @@ -31,7 +31,7 @@ volatile int g_test = 0; void * -step_thread_func (void *input) +step_thread_func () { g_test = 0; // Set breakpoint here @@ -48,13 +48,13 @@ void * create_thread_func (void *input) { - pthread_t *step_thread = (pthread_t*)input; + std::thread *step_thread = (std::thread*)input; // Wait until the main thread knows this thread is started. pseudo_barrier_wait(g_barrier); // Wait until the other thread is done. - pthread_join(*step_thread, NULL); + step_thread->join(); // Return return NULL; @@ -62,21 +62,18 @@ int main () { - pthread_t thread_1; - pthread_t thread_2; - // Use a simple count to simulate a barrier. pseudo_barrier_init(g_barrier, 2); // Create a thread to hit the breakpoint. - pthread_create (&thread_1, NULL, step_thread_func, NULL); + std::thread thread_1(step_thread_func); // Wait until the step thread is stepping while (g_test < 1) do_nothing(); // Create a thread to exit while we're stepping. - pthread_create (&thread_2, NULL, create_thread_func, &thread_1); + std::thread thread_2(create_thread_func, &thread_1); // Wait until that thread is started pseudo_barrier_wait(g_barrier); @@ -85,8 +82,8 @@ g_thread_created = 1; // Wait for the threads to finish. - pthread_join(thread_2, NULL); - pthread_join(thread_1, NULL); + thread_2.join(); + thread_1.join(); return 0; } Index: test/functionalities/thread/exit_during_break/main.cpp =================================================================== --- test/functionalities/thread/exit_during_break/main.cpp +++ test/functionalities/thread/exit_during_break/main.cpp @@ -13,9 +13,9 @@ // breakpoint is hit. The test case should be flexible enough to treat that // as success. -#include #include #include +#include volatile int g_test = 0; @@ -42,7 +42,7 @@ std::atomic_int g_barrier3; void * -break_thread_func (void *input) +break_thread_func () { // Wait until the entire first group of threads is running pseudo_barrier_wait(g_barrier1); @@ -61,7 +61,7 @@ } void * -wait_thread_func (void *input) +wait_thread_func () { // Wait until the entire first group of threads is running pseudo_barrier_wait(g_barrier1); @@ -77,7 +77,7 @@ } void * -exit_thread_func (void *input) +exit_thread_func () { // Sync up with the rest of the threads. pseudo_barrier_wait(g_barrier2); @@ -91,11 +91,6 @@ int main () { - pthread_t thread_1; - pthread_t thread_2; - pthread_t thread_3; - pthread_t thread_4; - pthread_t thread_5; // The first barrier waits for the non-exiting threads to start. // This thread will also participate in that barrier. @@ -111,25 +106,25 @@ pseudo_barrier_init(g_barrier3, 4); // Create a thread to hit the breakpoint - pthread_create (&thread_1, NULL, break_thread_func, NULL); + std::thread thread_1(break_thread_func); // Create more threads to slow the debugger down during processing. - pthread_create (&thread_2, NULL, wait_thread_func, NULL); - pthread_create (&thread_3, NULL, wait_thread_func, NULL); - pthread_create (&thread_4, NULL, wait_thread_func, NULL); + std::thread thread_2(wait_thread_func); + std::thread thread_3(wait_thread_func); + std::thread thread_4(wait_thread_func); // Wait for all these threads to get started. pseudo_barrier_wait(g_barrier1); // Create a thread to exit during the breakpoint - pthread_create (&thread_5, NULL, exit_thread_func, NULL); + std::thread thread_5(exit_thread_func); // Wait for the threads to finish - pthread_join(thread_5, NULL); - pthread_join(thread_4, NULL); - pthread_join(thread_3, NULL); - pthread_join(thread_2, NULL); - pthread_join(thread_1, NULL); + thread_5.join(); + thread_4.join(); + thread_3.join(); + thread_2.join(); + thread_1.join(); return 0; } Index: test/functionalities/thread/exit_during_step/main.cpp =================================================================== --- test/functionalities/thread/exit_during_step/main.cpp +++ test/functionalities/thread/exit_during_step/main.cpp @@ -10,9 +10,10 @@ // This test is intended to create a situation in which one thread will exit // while the debugger is stepping in another thread. -#include #include +#include + // Note that although hogging the CPU while waiting for a variable to change // would be terrible in production code, it's great for testing since it // avoids a lot of messy context switching to get multiple threads synchronized. @@ -33,7 +34,7 @@ volatile int g_test = 0; void * -step_thread_func (void *input) +step_thread_func () { // Wait until both threads are started. pseudo_barrier_wait(g_barrier); @@ -51,7 +52,7 @@ } void * -exit_thread_func (void *input) +exit_thread_func () { // Wait until both threads are started. pseudo_barrier_wait(g_barrier); @@ -66,26 +67,23 @@ int main () { - pthread_t thread_1; - pthread_t thread_2; - // Synchronize thread start so that doesn't happen during stepping. pseudo_barrier_init(g_barrier, 2); // Create a thread to hit the breakpoint. - pthread_create (&thread_1, NULL, step_thread_func, NULL); + std::thread thread_1(step_thread_func); // Create a thread to exit while we're stepping. - pthread_create (&thread_2, NULL, exit_thread_func, NULL); + std::thread thread_2(exit_thread_func); // Wait for the exit thread to finish. - pthread_join(thread_2, NULL); + thread_2.join(); // Let the stepping thread know the other thread is gone. g_thread_exited = 1; // Wait for the stepping thread to finish. - pthread_join(thread_1, NULL); + thread_1.join(); return 0; } Index: test/functionalities/thread/multi_break/main.cpp =================================================================== --- test/functionalities/thread/multi_break/main.cpp +++ test/functionalities/thread/multi_break/main.cpp @@ -12,8 +12,8 @@ // the breakpoint in the second thread will be hit while the breakpoint handler // in the first thread is trying to stop all threads. -#include #include +#include // Note that although hogging the CPU while waiting for a variable to change // would be terrible in production code, it's great for testing since it @@ -32,7 +32,7 @@ volatile int g_test = 0; void * -thread_func (void *input) +thread_func () { // Wait until both threads are running pseudo_barrier_wait(g_barrier); @@ -46,19 +46,16 @@ int main () { - pthread_t thread_1; - pthread_t thread_2; - // Don't let either thread do anything until they're both ready. pseudo_barrier_init(g_barrier, 2); // Create two threads - pthread_create (&thread_1, NULL, thread_func, NULL); - pthread_create (&thread_2, NULL, thread_func, NULL); + std::thread thread_1(thread_func); + std::thread thread_2(thread_func); // Wait for the threads to finish - pthread_join(thread_1, NULL); - pthread_join(thread_2, NULL); + thread_1.join(); + thread_2.join(); return 0; } Index: test/functionalities/thread/step_out/main.cpp =================================================================== --- test/functionalities/thread/step_out/main.cpp +++ test/functionalities/thread/step_out/main.cpp @@ -10,8 +10,8 @@ // This test is intended to create a situation in which two threads are stopped // at a breakpoint and the debugger issues a step-out command. -#include #include +#include // Note that although hogging the CPU while waiting for a variable to change // would be terrible in production code, it's great for testing since it @@ -34,7 +34,7 @@ } void * -thread_func (void *input) +thread_func () { // Wait until both threads are running pseudo_barrier_wait(g_barrier); @@ -48,19 +48,16 @@ int main () { - pthread_t thread_1; - pthread_t thread_2; - // Don't let either thread do anything until they're both ready. pseudo_barrier_init(g_barrier, 2); // Create two threads - pthread_create (&thread_1, NULL, thread_func, NULL); - pthread_create (&thread_2, NULL, thread_func, NULL); + std::thread thread_1(thread_func); + std::thread thread_2(thread_func); // Wait for the threads to finish - pthread_join(thread_1, NULL); - pthread_join(thread_2, NULL); + thread_1.join(); + thread_2.join(); return 0; } Index: test/functionalities/thread/thread_exit/main.cpp =================================================================== --- test/functionalities/thread/thread_exit/main.cpp +++ test/functionalities/thread/thread_exit/main.cpp @@ -9,8 +9,8 @@ // This test verifies the correct handling of child thread exits. -#include #include +#include // Note that although hogging the CPU while waiting for a variable to change // would be terrible in production code, it's great for testing since it @@ -29,7 +29,7 @@ std::atomic_int g_barrier3; void * -thread1 (void *input) +thread1 () { // Synchronize with the main thread. pseudo_barrier_wait(g_barrier1); @@ -42,7 +42,7 @@ } void * -thread2 (void *input) +thread2 () { // Synchronize with thread1 and the main thread. pseudo_barrier_wait(g_barrier2); @@ -56,34 +56,30 @@ int main () { - pthread_t thread_1; - pthread_t thread_2; - pthread_t thread_3; - pseudo_barrier_init(g_barrier1, 2); pseudo_barrier_init(g_barrier2, 3); pseudo_barrier_init(g_barrier3, 2); // Create a thread. - pthread_create (&thread_1, NULL, thread1, NULL); + std::thread thread_1(thread1); // Wait for thread1 to start. pseudo_barrier_wait(g_barrier1); // Create another thread. - pthread_create (&thread_2, NULL, thread2, NULL); // Set first breakpoint here + std::thread thread_2(thread2); // Set first breakpoint here // Wait for thread2 to start. pseudo_barrier_wait(g_barrier2); // Wait for the first thread to finish - pthread_join(thread_1, NULL); + thread_1.join(); // Synchronize with the remaining thread pseudo_barrier_wait(g_barrier3); // Set third breakpoint here // Wait for the second thread to finish - pthread_join(thread_2, NULL); + thread_2.join(); return 0; // Set fourth breakpoint here } Index: test/functionalities/thread/thread_specific_break/Makefile =================================================================== --- test/functionalities/thread/thread_specific_break/Makefile +++ test/functionalities/thread/thread_specific_break/Makefile @@ -1,6 +1,6 @@ LEVEL = ../../../make -C_SOURCES := main.c +CXX_SOURCES := main.cpp ENABLE_THREADS := YES include $(LEVEL)/Makefile.rules Index: test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py =================================================================== --- test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py +++ test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py @@ -37,7 +37,7 @@ target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) - main_source_spec = lldb.SBFileSpec ("main.c") + main_source_spec = lldb.SBFileSpec ("main.cpp") # Set a breakpoint in the thread body, and make it active for only the first thread. break_thread_body = target.BreakpointCreateBySourceRegex ("Break here in thread body.", main_source_spec) Index: test/functionalities/thread/thread_specific_break/main.c =================================================================== --- test/functionalities/thread/thread_specific_break/main.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -void * -thread_function (void *thread_marker) -{ - int keep_going = 1; - int my_value = *((int *)thread_marker); - int counter = 0; - - while (counter < 20) - { - counter++; // Break here in thread body. - usleep (10); - } - return NULL; -} - - -int -main () -{ - - pthread_t threads[10]; - - int thread_value = 0; - int i; - - for (i = 0; i < 10; i++) - { - thread_value += 1; - pthread_create (&threads[i], NULL, &thread_function, &thread_value); - } - - for (i = 0; i < 10; i++) - pthread_join (threads[i], NULL); - - return 0; -} Index: test/functionalities/thread/thread_specific_break/main.cpp =================================================================== --- /dev/null +++ test/functionalities/thread/thread_specific_break/main.cpp @@ -0,0 +1,39 @@ +#include +#include +#include + +void * +thread_function (void *thread_marker) +{ + int keep_going = 1; + int my_value = *((int *)thread_marker); + int counter = 0; + + while (counter < 20) + { + counter++; // Break here in thread body. + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + return NULL; +} + + +int +main () +{ + std::vector threads; + + int thread_value = 0; + int i; + + for (i = 0; i < 10; i++) + { + thread_value += 1; + threads.push_back(std::thread(thread_function, &thread_value)); + } + + for (i = 0; i < 10; i++) + threads[i].join(); + + return 0; +}