IPC.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/IPC/SharedMemory.h>
  9. #include <AzCore/UnitTest/TestTypes.h>
  10. #include <AzCore/std/parallel/thread.h>
  11. #include <AzCore/std/functional.h>
  12. using namespace AZ;
  13. #if AZ_TRAIT_SUPPORT_IPC
  14. namespace UnitTest
  15. {
  16. /**
  17. * Test InterProcessCommunication utils.
  18. */
  19. class IPC
  20. : public LeakDetectionFixture
  21. {
  22. };
  23. TEST_F(IPC, SharedMemoryThrash)
  24. {
  25. AZ::SharedMemory sharedMem;
  26. AZ::SharedMemory::CreateResult result = sharedMem.Create("SharedMemoryUnitTest", sizeof(AZStd::thread_id), true);
  27. EXPECT_EQ(AZ::SharedMemory::CreatedNew, result);
  28. bool mapped = sharedMem.Map();
  29. EXPECT_TRUE(mapped);
  30. auto threadFunc = [&sharedMem]()
  31. {
  32. AZStd::thread_id* lastThreadId = static_cast<AZStd::thread_id*>(sharedMem.Data());
  33. for (int i = 0; i < 100000; ++i)
  34. {
  35. AZStd::lock_guard<decltype(sharedMem)> lock(sharedMem);
  36. *lastThreadId = AZStd::this_thread::get_id();
  37. }
  38. };
  39. AZStd::thread threads[8];
  40. for (size_t t = 0; t < AZ_ARRAY_SIZE(threads); ++t)
  41. {
  42. threads[t] = AZStd::thread(threadFunc);
  43. }
  44. for (auto& thread : threads)
  45. {
  46. thread.join();
  47. }
  48. bool unmapped = sharedMem.UnMap();
  49. EXPECT_TRUE(unmapped);
  50. }
  51. TEST_F(IPC, SharedMemoryMutexAbandonment)
  52. {
  53. const char* sharedMemKey = "SharedMemoryUnitTest";
  54. auto threadFunc = [sharedMemKey]()
  55. {
  56. void* memBuffer = azmalloc(sizeof(AZ::SharedMemory));
  57. AZ::SharedMemory* sharedMem = new (memBuffer) AZ::SharedMemory();
  58. AZ::SharedMemory::CreateResult result = sharedMem->Create(sharedMemKey, sizeof(AZStd::thread_id), true);
  59. EXPECT_TRUE(result == AZ::SharedMemory::CreatedNew || result == AZ::SharedMemory::CreatedExisting);
  60. bool mapped = sharedMem->Map();
  61. EXPECT_TRUE(mapped);
  62. AZStd::thread_id* lastThreadId = static_cast<AZStd::thread_id*>(sharedMem->Data());
  63. for (int i = 0; i < 100000; ++i)
  64. {
  65. sharedMem->lock();
  66. *lastThreadId = AZStd::this_thread::get_id();
  67. if (i == (int)(*lastThreadId).m_id || sharedMem->IsLockAbandoned())
  68. {
  69. // Simulate a crash/dead process by cleaning up the handles but not unlocking
  70. HANDLE* mmapHandle = (HANDLE*)(reinterpret_cast<char*>(sharedMem) + sizeof(SharedMemory_Common));
  71. HANDLE* mutexHandle = mmapHandle + 1;
  72. bool closedMap = CloseHandle(*mmapHandle) != 0;
  73. EXPECT_TRUE(closedMap);
  74. bool closedMutex = CloseHandle(*mutexHandle) != 0;
  75. EXPECT_TRUE(closedMutex);
  76. azfree(sharedMem); // avoid calling dtor
  77. return;
  78. }
  79. sharedMem->unlock();
  80. }
  81. bool unmapped = sharedMem->UnMap();
  82. EXPECT_TRUE(unmapped);
  83. sharedMem->~SharedMemory();
  84. azfree(memBuffer);
  85. };
  86. AZStd::thread threads[8];
  87. for (size_t t = 0; t < AZ_ARRAY_SIZE(threads); ++t)
  88. {
  89. threads[t] = AZStd::thread(threadFunc);
  90. }
  91. for (auto& thread : threads)
  92. {
  93. thread.join();
  94. }
  95. }
  96. }
  97. #endif // AZ_TRAIT_SUPPORT_IPC