TestLibPthreadSpinLocks.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. * Copyright (c) 2021, Brian Gianforcaro <bgianf@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibPthread/pthread.h>
  7. #include <LibTest/TestCase.h>
  8. #include <errno.h>
  9. #include <unistd.h>
  10. TEST_CASE(spin_init_process_scope)
  11. {
  12. {
  13. pthread_spinlock_t lock {};
  14. auto result = pthread_spin_init(&lock, PTHREAD_SCOPE_PROCESS);
  15. EXPECT_EQ(0, result);
  16. result = pthread_spin_destroy(&lock);
  17. EXPECT_EQ(0, result);
  18. }
  19. {
  20. pthread_spinlock_t garbage_lock { 0x1337 };
  21. auto result = pthread_spin_init(&garbage_lock, PTHREAD_SCOPE_PROCESS);
  22. EXPECT_EQ(0, result);
  23. result = pthread_spin_destroy(&garbage_lock);
  24. EXPECT_EQ(0, result);
  25. }
  26. }
  27. TEST_CASE(spin_init_system_scope)
  28. {
  29. pthread_spinlock_t lock {};
  30. auto result = pthread_spin_init(&lock, PTHREAD_SCOPE_SYSTEM);
  31. EXPECT_EQ(0, result);
  32. pthread_spinlock_t garbage_lock { 0x99999 };
  33. result = pthread_spin_init(&garbage_lock, PTHREAD_SCOPE_PROCESS);
  34. EXPECT_EQ(0, result);
  35. }
  36. TEST_CASE(spin_lock)
  37. {
  38. pthread_spinlock_t lock {};
  39. auto result = pthread_spin_lock(&lock);
  40. EXPECT_EQ(0, result);
  41. // We should detect that this thread already holds this lock.
  42. result = pthread_spin_lock(&lock);
  43. EXPECT_EQ(EDEADLK, result);
  44. }
  45. TEST_CASE(spin_try_lock)
  46. {
  47. {
  48. pthread_spinlock_t lock {};
  49. auto result = pthread_spin_trylock(&lock);
  50. EXPECT_EQ(0, result);
  51. result = pthread_spin_unlock(&lock);
  52. EXPECT_EQ(0, result);
  53. }
  54. {
  55. pthread_spinlock_t lock {};
  56. auto result = pthread_spin_trylock(&lock);
  57. EXPECT_EQ(0, result);
  58. // We should detect that this thread already holds the lock.
  59. result = pthread_spin_trylock(&lock);
  60. EXPECT_EQ(EBUSY, result);
  61. }
  62. }
  63. static void lock_from_different_thread(pthread_spinlock_t* lock)
  64. {
  65. pthread_t thread_id {};
  66. auto result = pthread_create(
  67. &thread_id, nullptr, [](void* param) -> void* {
  68. auto lock = (pthread_spinlock_t*)param;
  69. pthread_spin_lock(lock);
  70. return nullptr;
  71. },
  72. lock);
  73. EXPECT_EQ(0, result);
  74. result = pthread_join(thread_id, nullptr);
  75. EXPECT_EQ(0, result);
  76. }
  77. TEST_CASE(spin_unlock)
  78. {
  79. {
  80. pthread_spinlock_t lock {};
  81. auto result = pthread_spin_lock(&lock);
  82. EXPECT_EQ(0, result);
  83. result = pthread_spin_unlock(&lock);
  84. EXPECT_EQ(0, result);
  85. }
  86. {
  87. pthread_spinlock_t lock {};
  88. lock_from_different_thread(&lock);
  89. auto result = pthread_spin_unlock(&lock);
  90. EXPECT_EQ(EPERM, result);
  91. }
  92. }
  93. TEST_CASE(spin_destroy)
  94. {
  95. {
  96. pthread_spinlock_t lock {};
  97. auto result = pthread_spin_lock(&lock);
  98. EXPECT_EQ(0, result);
  99. result = pthread_spin_destroy(&lock);
  100. EXPECT_EQ(EBUSY, result);
  101. result = pthread_spin_unlock(&lock);
  102. EXPECT_EQ(0, result);
  103. }
  104. {
  105. pthread_spinlock_t lock {};
  106. lock_from_different_thread(&lock);
  107. auto result = pthread_spin_destroy(&lock);
  108. EXPECT_EQ(EBUSY, result);
  109. }
  110. }