13614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//===-- sanitizer_stoptheworld_test.cc ------------------------------------===// 23614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// 33614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// The LLVM Compiler Infrastructure 43614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// 53614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// This file is distributed under the University of Illinois Open Source 63614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// License. See LICENSE.TXT for details. 73614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// 83614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//===----------------------------------------------------------------------===// 93614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// 103614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// Tests for sanitizer_stoptheworld.h 113614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// 123614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko//===----------------------------------------------------------------------===// 133614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 14a615b26e3e3c2da0b2f950f506f6c2c220430c19Sergey Matveev#include "sanitizer_common/sanitizer_platform.h" 15cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev#if SANITIZER_LINUX && defined(__x86_64__) 163614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 173614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include "sanitizer_common/sanitizer_stoptheworld.h" 183614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include "gtest/gtest.h" 193614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 203614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include "sanitizer_common/sanitizer_libc.h" 213614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include "sanitizer_common/sanitizer_common.h" 223614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 233614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include <pthread.h> 243614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko#include <sched.h> 253614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 263614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkonamespace __sanitizer { 273614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 283614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostatic pthread_mutex_t incrementer_thread_exit_mutex; 293614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 303614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostruct CallbackArgument { 313614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko volatile int counter; 323614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko volatile bool threads_stopped; 333614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko volatile bool callback_executed; 343614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko CallbackArgument() 353614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko : counter(0), 363614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko threads_stopped(false), 373614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko callback_executed(false) {} 383614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko}; 393614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 403614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkovoid *IncrementerThread(void *argument) { 413614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko CallbackArgument *callback_argument = (CallbackArgument *)argument; 423614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko while (true) { 433614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko __sync_fetch_and_add(&callback_argument->counter, 1); 443614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko if (pthread_mutex_trylock(&incrementer_thread_exit_mutex) == 0) { 453614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_mutex_unlock(&incrementer_thread_exit_mutex); 463614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko return NULL; 473614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } else { 483614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko sched_yield(); 493614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } 503614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } 513614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko} 523614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 533614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// This callback checks that IncrementerThread is suspended at the time of its 543614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// execution. 553614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkovoid Callback(const SuspendedThreadsList &suspended_threads_list, 563614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko void *argument) { 573614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko CallbackArgument *callback_argument = (CallbackArgument *)argument; 583614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko callback_argument->callback_executed = true; 593614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko int counter_at_init = __sync_fetch_and_add(&callback_argument->counter, 0); 603614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko for (uptr i = 0; i < 1000; i++) { 613614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko sched_yield(); 623614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko if (__sync_fetch_and_add(&callback_argument->counter, 0) != 633614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko counter_at_init) { 643614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko callback_argument->threads_stopped = false; 653614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko return; 663614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } 673614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } 683614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko callback_argument->threads_stopped = true; 693614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko} 703614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 713614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander PotapenkoTEST(StopTheWorld, SuspendThreadsSimple) { 723614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_mutex_init(&incrementer_thread_exit_mutex, NULL); 733614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko CallbackArgument argument; 743614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_t thread_id; 753614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko int pthread_create_result; 763614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_mutex_lock(&incrementer_thread_exit_mutex); 773614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_create_result = pthread_create(&thread_id, NULL, IncrementerThread, 783614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko &argument); 793614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko ASSERT_EQ(0, pthread_create_result); 803614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko StopTheWorld(&Callback, &argument); 813614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_mutex_unlock(&incrementer_thread_exit_mutex); 823614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko EXPECT_TRUE(argument.callback_executed); 833614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko EXPECT_TRUE(argument.threads_stopped); 843614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko // argument is on stack, so we have to wait for the incrementer thread to 853614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko // terminate before we can return from this function. 863614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko ASSERT_EQ(0, pthread_join(thread_id, NULL)); 873614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_mutex_destroy(&incrementer_thread_exit_mutex); 883614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko} 893614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 903614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// A more comprehensive test where we spawn a bunch of threads while executing 913614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko// StopTheWorld in parallel. 923614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostatic const uptr kThreadCount = 50; 933614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostatic const uptr kStopWorldAfter = 10; // let this many threads spawn first 943614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 953614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostatic pthread_mutex_t advanced_incrementer_thread_exit_mutex; 963614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 973614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkostruct AdvancedCallbackArgument { 983614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko volatile uptr thread_index; 993614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko volatile int counters[kThreadCount]; 1003614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_t thread_ids[kThreadCount]; 1013614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko volatile bool threads_stopped; 1023614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko volatile bool callback_executed; 1033614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko volatile bool fatal_error; 1043614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko AdvancedCallbackArgument() 1053614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko : thread_index(0), 1063614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko threads_stopped(false), 1073614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko callback_executed(false), 1083614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko fatal_error(false) {} 1093614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko}; 1103614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 1113614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkovoid *AdvancedIncrementerThread(void *argument) { 1123614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko AdvancedCallbackArgument *callback_argument = 1133614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko (AdvancedCallbackArgument *)argument; 1145efb53ed40eeab7bc6c361c0825608fc97322e1dDmitry Vyukov uptr this_thread_index = __sync_fetch_and_add( 1155efb53ed40eeab7bc6c361c0825608fc97322e1dDmitry Vyukov &callback_argument->thread_index, 1); 1163614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko // Spawn the next thread. 1173614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko int pthread_create_result; 1183614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko if (this_thread_index + 1 < kThreadCount) { 1193614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_create_result = 1203614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_create(&callback_argument->thread_ids[this_thread_index + 1], 1213614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko NULL, AdvancedIncrementerThread, argument); 1223614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko // Cannot use ASSERT_EQ in non-void-returning functions. If there's a 1233614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko // problem, defer failing to the main thread. 1243614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko if (pthread_create_result != 0) { 1253614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko callback_argument->fatal_error = true; 1263614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko __sync_fetch_and_add(&callback_argument->thread_index, 1273614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko kThreadCount - callback_argument->thread_index); 1283614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } 1293614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } 1303614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko // Do the actual work. 1313614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko while (true) { 1323614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko __sync_fetch_and_add(&callback_argument->counters[this_thread_index], 1); 1333614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko if (pthread_mutex_trylock(&advanced_incrementer_thread_exit_mutex) == 0) { 1343614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_mutex_unlock(&advanced_incrementer_thread_exit_mutex); 1353614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko return NULL; 1363614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } else { 1373614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko sched_yield(); 1383614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } 1393614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } 1403614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko} 1413614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 1423614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenkovoid AdvancedCallback(const SuspendedThreadsList &suspended_threads_list, 1433614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko void *argument) { 1443614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko AdvancedCallbackArgument *callback_argument = 1453614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko (AdvancedCallbackArgument *)argument; 1463614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko callback_argument->callback_executed = true; 1473614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 1483614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko int counters_at_init[kThreadCount]; 1493614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko for (uptr j = 0; j < kThreadCount; j++) 1503614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko counters_at_init[j] = __sync_fetch_and_add(&callback_argument->counters[j], 1513614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 0); 1523614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko for (uptr i = 0; i < 10; i++) { 1533614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko sched_yield(); 1543614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko for (uptr j = 0; j < kThreadCount; j++) 1553614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko if (__sync_fetch_and_add(&callback_argument->counters[j], 0) != 1563614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko counters_at_init[j]) { 1573614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko callback_argument->threads_stopped = false; 1583614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko return; 1593614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } 1603614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko } 1613614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko callback_argument->threads_stopped = true; 1623614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko} 1633614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 1643614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander PotapenkoTEST(StopTheWorld, SuspendThreadsAdvanced) { 1653614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_mutex_init(&advanced_incrementer_thread_exit_mutex, NULL); 1663614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko AdvancedCallbackArgument argument; 1673614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 1683614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_mutex_lock(&advanced_incrementer_thread_exit_mutex); 1693614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko int pthread_create_result; 1703614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_create_result = pthread_create(&argument.thread_ids[0], NULL, 1713614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko AdvancedIncrementerThread, 1723614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko &argument); 1733614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko ASSERT_EQ(0, pthread_create_result); 1743614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko // Wait for several threads to spawn before proceeding. 1753614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko while (__sync_fetch_and_add(&argument.thread_index, 0) < kStopWorldAfter) 1763614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko sched_yield(); 1773614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko StopTheWorld(&AdvancedCallback, &argument); 1783614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko EXPECT_TRUE(argument.callback_executed); 1793614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko EXPECT_TRUE(argument.threads_stopped); 1803614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 1813614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko // Wait for all threads to spawn before we start terminating them. 1823614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko while (__sync_fetch_and_add(&argument.thread_index, 0) < kThreadCount) 1833614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko sched_yield(); 1845efb53ed40eeab7bc6c361c0825608fc97322e1dDmitry Vyukov ASSERT_FALSE(argument.fatal_error); // a pthread_create has failed 1853614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko // Signal the threads to terminate. 1863614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_mutex_unlock(&advanced_incrementer_thread_exit_mutex); 1873614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko for (uptr i = 0; i < kThreadCount; i++) 1883614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko ASSERT_EQ(0, pthread_join(argument.thread_ids[i], NULL)); 1893614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko pthread_mutex_destroy(&advanced_incrementer_thread_exit_mutex); 1903614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko} 1913614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 1923614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko} // namespace __sanitizer 1933614c16084e8a0dc8ae3418402a2d0c6f8107e39Alexander Potapenko 194cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev#endif // SANITIZER_LINUX && defined(__x86_64__) 195