1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/compiler_specific.h" 6 #include "base/logging.h" 7 #include "base/memory/shared_memory.h" 8 #include "base/process/kill.h" 9 #include "base/stl_util.h" 10 #include "base/test/multiprocess_test.h" 11 #include "base/threading/platform_thread.h" 12 #include "media/audio/cross_process_notification.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 #include "testing/multiprocess_func_list.h" 15 16 #include <utility> // NOLINT 17 18 namespace { 19 20 // Initializes (ctor) and deletes (dtor) two vectors of pairs of 21 // CrossProcessNotification instances. 22 class NotificationsOwner { 23 public: 24 // Attempts to create up to |number_of_pairs| number of pairs. Call size() 25 // after construction to find out how many pairs were actually created. 26 explicit NotificationsOwner(size_t number_of_pairs) { 27 CreateMultiplePairs(number_of_pairs); 28 } 29 ~NotificationsOwner() { 30 STLDeleteElements(&a_); 31 STLDeleteElements(&b_); 32 } 33 34 size_t size() const { 35 DCHECK_EQ(a_.size(), b_.size()); 36 return a_.size(); 37 } 38 39 const CrossProcessNotification::Notifications& a() { return a_; } 40 const CrossProcessNotification::Notifications& b() { return b_; } 41 42 private: 43 void CreateMultiplePairs(size_t count) { 44 a_.resize(count); 45 b_.resize(count); 46 size_t i = 0; 47 for (; i < count; ++i) { 48 a_[i] = new CrossProcessNotification(); 49 b_[i] = new CrossProcessNotification(); 50 if (!CrossProcessNotification::InitializePair(a_[i], b_[i])) { 51 LOG(WARNING) << "InitializePair failed at " << i; 52 delete a_[i]; 53 delete b_[i]; 54 break; 55 } 56 } 57 a_.resize(i); 58 b_.resize(i); 59 } 60 61 CrossProcessNotification::Notifications a_; 62 CrossProcessNotification::Notifications b_; 63 }; 64 65 // A simple thread that we'll run two instances of. Both threads get a pointer 66 // to the same |shared_data| and use a CrossProcessNotification to control when 67 // each thread can read/write. 68 class SingleNotifierWorker : public base::PlatformThread::Delegate { 69 public: 70 SingleNotifierWorker(size_t* shared_data, size_t repeats, 71 CrossProcessNotification* notifier) 72 : shared_data_(shared_data), repeats_(repeats), 73 notifier_(notifier) { 74 } 75 virtual ~SingleNotifierWorker() {} 76 77 // base::PlatformThread::Delegate: 78 virtual void ThreadMain() OVERRIDE { 79 for (size_t i = 0; i < repeats_; ++i) { 80 notifier_->Wait(); 81 ++(*shared_data_); 82 notifier_->Signal(); 83 } 84 } 85 86 private: 87 size_t* shared_data_; 88 size_t repeats_; 89 CrossProcessNotification* notifier_; 90 DISALLOW_COPY_AND_ASSIGN(SingleNotifierWorker); 91 }; 92 93 // Similar to SingleNotifierWorker, except each instance of this class will 94 // have >1 instances of CrossProcessNotification to Wait/Signal and an equal 95 // amount of |shared_data| that the notifiers control access to. 96 class MultiNotifierWorker : public base::PlatformThread::Delegate { 97 public: 98 MultiNotifierWorker(size_t* shared_data, size_t repeats, 99 const CrossProcessNotification::Notifications* notifiers) 100 : shared_data_(shared_data), repeats_(repeats), 101 notifiers_(notifiers) { 102 } 103 virtual ~MultiNotifierWorker() {} 104 105 // base::PlatformThread::Delegate: 106 virtual void ThreadMain() OVERRIDE { 107 CrossProcessNotification::WaitForMultiple waiter(notifiers_); 108 for (size_t i = 0; i < repeats_; ++i) { 109 int signaled = waiter.Wait(); 110 ++shared_data_[signaled]; 111 (*notifiers_)[signaled]->Signal(); 112 } 113 } 114 115 private: 116 size_t* shared_data_; 117 size_t repeats_; 118 const CrossProcessNotification::Notifications* notifiers_; 119 DISALLOW_COPY_AND_ASSIGN(MultiNotifierWorker); 120 }; 121 122 // A fixed array of bool flags. Each flag uses 1 bit. Use sizeof(FlagArray) 123 // to determine how much memory you need. The number of flags will therefore 124 // be sizeof(FlagArray) * 8. 125 // We use 'struct' to signify that this structures represents compiler 126 // independent structured data. I.e. you must be able to map this class 127 // to a piece of shared memory of size sizeof(FlagArray) and be able to 128 // use the class. No vtables etc. 129 // TODO(tommi): Move this to its own header when we start using it for signaling 130 // audio devices. As is, it's just here for perf comparison against the 131 // "multiple notifiers" approach. 132 struct FlagArray { 133 public: 134 FlagArray() : flags_() {} 135 136 bool is_set(size_t index) const { 137 return (flags_[index >> 5] & (1 << (index & 31))); 138 } 139 140 void set(size_t index) { 141 flags_[index >> 5] |= (1U << (static_cast<uint32>(index) & 31)); 142 } 143 144 void clear(size_t index) { 145 flags_[index >> 5] &= ~(1U << (static_cast<uint32>(index) & 31)); 146 } 147 148 // Returns the number of flags that can be set/checked. 149 size_t size() const { return sizeof(flags_) * 8; } 150 151 private: 152 // 256 * 32 = 8192 flags in 1KB. 153 uint32 flags_[256]; 154 DISALLOW_COPY_AND_ASSIGN(FlagArray); 155 }; 156 157 class MultiNotifierWorkerFlagArray : public base::PlatformThread::Delegate { 158 public: 159 MultiNotifierWorkerFlagArray(size_t count, FlagArray* signals, 160 size_t* shared_data, size_t repeats, 161 CrossProcessNotification* notifier) 162 : count_(count), signals_(signals), shared_data_(shared_data), 163 repeats_(repeats), notifier_(notifier) { 164 } 165 virtual ~MultiNotifierWorkerFlagArray() {} 166 167 // base::PlatformThread::Delegate: 168 virtual void ThreadMain() OVERRIDE { 169 for (size_t i = 0; i < repeats_; ++i) { 170 notifier_->Wait(); 171 for (size_t s = 0; s < count_; ++s) { 172 if (signals_->is_set(s)) { 173 ++shared_data_[s]; 174 // We don't clear the flag here but simply leave it signaled because 175 // we want the other thread to also increment this variable. 176 } 177 } 178 notifier_->Signal(); 179 } 180 } 181 182 private: 183 size_t count_; 184 FlagArray* signals_; 185 size_t* shared_data_; 186 size_t repeats_; 187 CrossProcessNotification* notifier_; 188 DISALLOW_COPY_AND_ASSIGN(MultiNotifierWorkerFlagArray); 189 }; 190 191 } // end namespace 192 193 TEST(CrossProcessNotification, FlagArray) { 194 FlagArray flags; 195 EXPECT_GT(flags.size(), 1000U); 196 for (size_t i = 0; i < flags.size(); ++i) { 197 EXPECT_FALSE(flags.is_set(i)); 198 flags.set(i); 199 EXPECT_TRUE(flags.is_set(i)); 200 flags.clear(i); 201 EXPECT_FALSE(flags.is_set(i)); 202 } 203 } 204 205 // Initializes two notifiers, signals the each one and make sure the others 206 // wait is satisfied. 207 TEST(CrossProcessNotification, Basic) { 208 CrossProcessNotification a, b; 209 ASSERT_TRUE(CrossProcessNotification::InitializePair(&a, &b)); 210 EXPECT_TRUE(a.IsValid()); 211 EXPECT_TRUE(b.IsValid()); 212 213 a.Signal(); 214 b.Wait(); 215 216 b.Signal(); 217 a.Wait(); 218 } 219 220 // Spins two worker threads, each with their own CrossProcessNotification 221 // that they use to read and write from a shared memory buffer. 222 // Disabled as it trips of the TSAN bot (false positive since TSAN doesn't 223 // recognize sockets as being a synchronization primitive). 224 TEST(CrossProcessNotification, DISABLED_TwoThreads) { 225 CrossProcessNotification a, b; 226 ASSERT_TRUE(CrossProcessNotification::InitializePair(&a, &b)); 227 228 size_t data = 0; 229 const size_t kRepeats = 10000; 230 SingleNotifierWorker worker1(&data, kRepeats, &a); 231 SingleNotifierWorker worker2(&data, kRepeats, &b); 232 base::PlatformThreadHandle thread1, thread2; 233 base::PlatformThread::Create(0, &worker1, &thread1); 234 base::PlatformThread::Create(0, &worker2, &thread2); 235 236 // Start the first thread. They should ping pong a few times and take turns 237 // incrementing the shared variable and never step on each other's toes. 238 a.Signal(); 239 240 base::PlatformThread::Join(thread1); 241 base::PlatformThread::Join(thread2); 242 243 EXPECT_EQ(kRepeats * 2, data); 244 } 245 246 // Uses a pair of threads to access up to 1000 pieces of synchronized shared 247 // data. On regular dev machines, the number of notifiers should be 1000, but on 248 // mac and linux bots, the number will be smaller due to the RLIMIT_NOFILE 249 // limit. Specifically, linux will have this limit at 1024 which means for this 250 // test that the max number of notifiers will be in the range 500-512. On Mac 251 // the limit is 256, so |count| will be ~120. Oh, and raising the limit via 252 // setrlimit() won't work. 253 // DISABLED since the distribution won't be accurate when run on valgrind. 254 TEST(CrossProcessNotification, DISABLED_ThousandNotifiersTwoThreads) { 255 const size_t kCount = 1000; 256 NotificationsOwner pairs(kCount); 257 size_t data[kCount] = {0}; 258 // We use a multiple of the count so that the division in the check below 259 // will be nice and round. 260 size_t repeats = pairs.size() * 1; 261 262 MultiNotifierWorker worker_1(&data[0], repeats, &pairs.a()); 263 MultiNotifierWorker worker_2(&data[0], repeats, &pairs.b()); 264 base::PlatformThreadHandle thread_1, thread_2; 265 base::PlatformThread::Create(0, &worker_1, &thread_1); 266 base::PlatformThread::Create(0, &worker_2, &thread_2); 267 268 for (size_t i = 0; i < pairs.size(); ++i) 269 pairs.a()[i]->Signal(); 270 271 base::PlatformThread::Join(thread_1); 272 base::PlatformThread::Join(thread_2); 273 274 size_t expected_total = pairs.size() * 2; 275 size_t total = 0; 276 for (size_t i = 0; i < pairs.size(); ++i) { 277 // The CrossProcessNotification::WaitForMultiple class should have ensured 278 // that all notifiers had the same quality of service. 279 EXPECT_EQ(expected_total / pairs.size(), data[i]); 280 total += data[i]; 281 } 282 EXPECT_EQ(expected_total, total); 283 } 284 285 // Functionally equivalent (as far as the shared data goes) to the 286 // ThousandNotifiersTwoThreads test but uses a single pair of notifiers + 287 // FlagArray for the 1000 signals. This approach is significantly faster. 288 // Disabled as it trips of the TSAN bot - "Possible data race during write of 289 // size 4" (the flag array). 290 TEST(CrossProcessNotification, DISABLED_TwoNotifiersTwoThreads1000Signals) { 291 CrossProcessNotification a, b; 292 ASSERT_TRUE(CrossProcessNotification::InitializePair(&a, &b)); 293 294 const size_t kCount = 1000; 295 FlagArray signals; 296 ASSERT_GE(signals.size(), kCount); 297 size_t data[kCount] = {0}; 298 299 // Since this algorithm checks all events each time the notifier is 300 // signaled, |repeat| doesn't mean the same thing here as it does in 301 // ThousandNotifiersTwoThreads. 1 repeat here is the same as kCount 302 // repeats in ThousandNotifiersTwoThreads. 303 size_t repeats = 1; 304 MultiNotifierWorkerFlagArray worker1(kCount, &signals, &data[0], repeats, &a); 305 MultiNotifierWorkerFlagArray worker2(kCount, &signals, &data[0], repeats, &b); 306 base::PlatformThreadHandle thread1, thread2; 307 base::PlatformThread::Create(0, &worker1, &thread1); 308 base::PlatformThread::Create(0, &worker2, &thread2); 309 310 for (size_t i = 0; i < kCount; ++i) 311 signals.set(i); 312 a.Signal(); 313 314 base::PlatformThread::Join(thread1); 315 base::PlatformThread::Join(thread2); 316 317 size_t expected_total = kCount * 2; 318 size_t total = 0; 319 for (size_t i = 0; i < kCount; ++i) { 320 // Since for each signal, we process all signaled events, the shared data 321 // variables should all be equal. 322 EXPECT_EQ(expected_total / kCount, data[i]); 323 total += data[i]; 324 } 325 EXPECT_EQ(expected_total, total); 326 } 327 328 // Test the maximum number of notifiers without spinning further wait 329 // threads on Windows. This test assumes we can always create 64 pairs and 330 // bails if we can't. 331 TEST(CrossProcessNotification, MultipleWaits64) { 332 const size_t kCount = 64; 333 NotificationsOwner pairs(kCount); 334 ASSERT_TRUE(pairs.size() == kCount); 335 336 CrossProcessNotification::WaitForMultiple waiter(&pairs.b()); 337 for (size_t i = 0; i < kCount; ++i) { 338 pairs.a()[i]->Signal(); 339 int index = waiter.Wait(); 340 EXPECT_EQ(i, static_cast<size_t>(index)); 341 } 342 } 343 344 // Tests waiting for more notifiers than the OS supports on one thread. 345 // The test will create at most 1000 pairs, but on mac/linux bots the actual 346 // number will be lower. See comment about the RLIMIT_NOFILE limit above for 347 // more details. 348 // DISABLED since the distribution won't be accurate when run on valgrind. 349 TEST(CrossProcessNotification, DISABLED_MultipleWaits1000) { 350 // A 1000 notifiers requires 16 threads on Windows, including the current 351 // one, to perform the wait operation. 352 const size_t kCount = 1000; 353 NotificationsOwner pairs(kCount); 354 355 for (size_t i = 0; i < pairs.size(); ++i) { 356 pairs.a()[i]->Signal(); 357 // To disable the load distribution algorithm and force the extra worker 358 // thread(s) to catch the signaled event, we define the |waiter| inside 359 // the loop. 360 CrossProcessNotification::WaitForMultiple waiter(&pairs.b()); 361 int index = waiter.Wait(); 362 EXPECT_EQ(i, static_cast<size_t>(index)); 363 } 364 } 365 366 class CrossProcessNotificationMultiProcessTest : public base::MultiProcessTest { 367 }; 368 369 namespace { 370 371 // A very crude IPC mechanism that we use to set up the spawned child process 372 // and the parent process. 373 struct CrudeIpc { 374 uint8 ready; 375 CrossProcessNotification::IPCHandle handle_1; 376 CrossProcessNotification::IPCHandle handle_2; 377 }; 378 379 #if defined(OS_POSIX) 380 const int kPosixChildSharedMem = 30; 381 #else 382 const char kSharedMemName[] = "CrossProcessNotificationMultiProcessTest"; 383 #endif 384 385 const size_t kSharedMemSize = 1024; 386 387 } // namespace 388 389 // The main routine of the child process. Waits for the parent process 390 // to copy handles over to the child and then uses a CrossProcessNotification to 391 // wait and signal to the parent process. 392 MULTIPROCESS_TEST_MAIN(CrossProcessNotificationChildMain) { 393 #if defined(OS_POSIX) 394 base::SharedMemory mem( 395 base::SharedMemoryHandle(kPosixChildSharedMem, true /* auto close */), 396 false); 397 #else 398 base::SharedMemory mem; 399 CHECK(mem.CreateNamed(kSharedMemName, true, kSharedMemSize)); 400 #endif 401 402 CHECK(mem.Map(kSharedMemSize)); 403 CrudeIpc* ipc = reinterpret_cast<CrudeIpc*>(mem.memory()); 404 405 while (!ipc->ready) 406 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); 407 408 CrossProcessNotification notifier(ipc->handle_1, ipc->handle_2); 409 notifier.Wait(); 410 notifier.Signal(); 411 412 return 0; 413 } 414 415 // Spawns a new process and hands a CrossProcessNotification instance to the 416 // new process. Once that's done, it waits for the child process to signal 417 // it's end and quits. 418 TEST_F(CrossProcessNotificationMultiProcessTest, Basic) { 419 CrossProcessNotification a, b; 420 ASSERT_TRUE(CrossProcessNotification::InitializePair(&a, &b)); 421 EXPECT_TRUE(a.IsValid()); 422 EXPECT_TRUE(b.IsValid()); 423 424 base::SharedMemory mem; 425 426 #if defined(OS_POSIX) 427 ASSERT_TRUE(mem.CreateAndMapAnonymous(kSharedMemSize)); 428 #else 429 mem.Delete(kSharedMemName); // In case a previous run was unsuccessful. 430 ASSERT_TRUE(mem.CreateNamed(kSharedMemName, false, kSharedMemSize)); 431 ASSERT_TRUE(mem.Map(kSharedMemSize)); 432 #endif 433 434 CrudeIpc* ipc = reinterpret_cast<CrudeIpc*>(mem.memory()); 435 ipc->ready = false; 436 437 #if defined(OS_POSIX) 438 const int kPosixChildSocket = 20; 439 EXPECT_TRUE(b.ShareToProcess( 440 base::kNullProcessHandle, &ipc->handle_1, &ipc->handle_2)); 441 base::FileHandleMappingVector fd_mapping_vec; 442 fd_mapping_vec.push_back(std::make_pair(ipc->handle_1.fd, kPosixChildSocket)); 443 fd_mapping_vec.push_back( 444 std::make_pair(mem.handle().fd, kPosixChildSharedMem)); 445 ipc->handle_1.fd = kPosixChildSocket; 446 base::ProcessHandle process = SpawnChild("CrossProcessNotificationChildMain", 447 fd_mapping_vec, false); 448 #else 449 base::ProcessHandle process = SpawnChild("CrossProcessNotificationChildMain", 450 false); 451 EXPECT_TRUE(b.ShareToProcess(process, &ipc->handle_1, &ipc->handle_2)); 452 #endif 453 454 ipc->ready = true; 455 456 a.Signal(); 457 a.Wait(); 458 459 int exit_code = -1; 460 base::WaitForExitCode(process, &exit_code); 461 EXPECT_EQ(0, exit_code); 462 } 463