pthread_rwlock_rdlock.m4 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. # pthread_rwlock_rdlock.m4 serial 1
  2. dnl Copyright (C) 2017 Free Software Foundation, Inc.
  3. dnl This file is free software; the Free Software Foundation
  4. dnl gives unlimited permission to copy and/or distribute it,
  5. dnl with or without modifications, as long as this notice is preserved.
  6. dnl From Bruno Haible.
  7. dnl Inspired by
  8. dnl https://github.com/linux-test-project/ltp/blob/master/testcases/open_posix_testsuite/conformance/interfaces/pthread_rwlock_rdlock/2-2.c
  9. dnl by Intel Corporation.
  10. dnl Test whether in a situation where
  11. dnl - an rwlock is taken by a reader and has a writer waiting,
  12. dnl - an additional reader requests the lock,
  13. dnl - the waiting writer and the requesting reader threads have the same
  14. dnl priority,
  15. dnl the requesting reader thread gets blocked, so that at some point the
  16. dnl waiting writer can acquire the lock.
  17. dnl Without such a guarantee, when there a N readers and each of the readers
  18. dnl spends more than 1/Nth of the time with the lock held, there is a high
  19. dnl probability that the waiting writer will not get the lock in a given finite
  20. dnl time, a phenomenon called "writer starvation".
  21. dnl Without such a guarantee, applications have a hard time avoiding writer
  22. dnl starvation.
  23. dnl
  24. dnl POSIX:2008 makes this requirement only for implementations that support TPS
  25. dnl (Thread Priority Scheduling) and only for the scheduling policies SCHED_FIFO
  26. dnl and SCHED_RR, see
  27. dnl http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html
  28. dnl but test verifies the guarantee regardless of TPS and regardless of
  29. dnl scheduling policy.
  30. AC_DEFUN([gl_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER],
  31. [
  32. AC_REQUIRE([gl_THREADLIB_EARLY])
  33. AC_CACHE_CHECK([whether pthread_rwlock_rdlock prefers a writer to a reader],
  34. [gl_cv_pthread_rwlock_rdlock_prefer_writer],
  35. [save_LIBS="$LIBS"
  36. LIBS="$LIBS $LIBMULTITHREAD"
  37. AC_RUN_IFELSE(
  38. [AC_LANG_SOURCE([[
  39. #include <errno.h>
  40. #include <pthread.h>
  41. #include <stdlib.h>
  42. #include <unistd.h>
  43. #define SUCCEED() exit (0)
  44. #define FAILURE() exit (1)
  45. #define UNEXPECTED(n) (exit (10 + (n)))
  46. /* The main thread creates the waiting writer and the requesting reader threads
  47. in the default way; this guarantees that they have the same priority.
  48. We can reuse the main thread as first reader thread. */
  49. static pthread_rwlock_t lock;
  50. static pthread_t reader1;
  51. static pthread_t writer;
  52. static pthread_t reader2;
  53. static pthread_t timer;
  54. /* Used to pass control from writer to reader2 and from reader2 to timer,
  55. as in a relay race.
  56. Passing control from one running thread to another running thread
  57. is most likely faster than to create the second thread. */
  58. static pthread_mutex_t baton;
  59. static void *
  60. timer_func (void *ignored)
  61. {
  62. /* Step 13 (can be before or after step 12):
  63. The timer thread takes the baton, then waits a moment to make sure
  64. it can tell whether the second reader thread is blocked at step 12. */
  65. if (pthread_mutex_lock (&baton))
  66. UNEXPECTED (13);
  67. usleep (100000);
  68. /* By the time we get here, it's clear that the second reader thread is
  69. blocked at step 12. This is the desired behaviour. */
  70. SUCCEED ();
  71. }
  72. static void *
  73. reader2_func (void *ignored)
  74. {
  75. int err;
  76. /* Step 8 (can be before or after step 7):
  77. The second reader thread takes the baton, then waits a moment to make sure
  78. the writer thread has reached step 7. */
  79. if (pthread_mutex_lock (&baton))
  80. UNEXPECTED (8);
  81. usleep (100000);
  82. /* Step 9: The second reader thread requests the lock. */
  83. err = pthread_rwlock_tryrdlock (&lock);
  84. if (err == 0)
  85. FAILURE ();
  86. else if (err != EBUSY)
  87. UNEXPECTED (9);
  88. /* Step 10: Launch a timer, to test whether the next call blocks. */
  89. if (pthread_create (&timer, NULL, timer_func, NULL))
  90. UNEXPECTED (10);
  91. /* Step 11: Release the baton. */
  92. if (pthread_mutex_unlock (&baton))
  93. UNEXPECTED (11);
  94. /* Step 12: The second reader thread requests the lock. */
  95. err = pthread_rwlock_rdlock (&lock);
  96. if (err == 0)
  97. FAILURE ();
  98. else
  99. UNEXPECTED (12);
  100. }
  101. static void *
  102. writer_func (void *ignored)
  103. {
  104. /* Step 4: Take the baton, so that the second reader thread does not go ahead
  105. too early. */
  106. if (pthread_mutex_lock (&baton))
  107. UNEXPECTED (4);
  108. /* Step 5: Create the second reader thread. */
  109. if (pthread_create (&reader2, NULL, reader2_func, NULL))
  110. UNEXPECTED (5);
  111. /* Step 6: Release the baton. */
  112. if (pthread_mutex_unlock (&baton))
  113. UNEXPECTED (6);
  114. /* Step 7: The writer thread requests the lock. */
  115. if (pthread_rwlock_wrlock (&lock))
  116. UNEXPECTED (7);
  117. return NULL;
  118. }
  119. int
  120. main ()
  121. {
  122. reader1 = pthread_self ();
  123. /* Step 1: The main thread initializes the lock and the baton. */
  124. if (pthread_rwlock_init (&lock, NULL))
  125. UNEXPECTED (1);
  126. if (pthread_mutex_init (&baton, NULL))
  127. UNEXPECTED (1);
  128. /* Step 2: The main thread acquires the lock as a reader. */
  129. if (pthread_rwlock_rdlock (&lock))
  130. UNEXPECTED (2);
  131. /* Step 3: Create the writer thread. */
  132. if (pthread_create (&writer, NULL, writer_func, NULL))
  133. UNEXPECTED (3);
  134. /* Job done. Go to sleep. */
  135. for (;;)
  136. {
  137. sleep (1);
  138. }
  139. }
  140. ]])],
  141. [gl_cv_pthread_rwlock_rdlock_prefer_writer=yes],
  142. [gl_cv_pthread_rwlock_rdlock_prefer_writer=no],
  143. [gl_cv_pthread_rwlock_rdlock_prefer_writer="guessing yes"])
  144. LIBS="$save_LIBS"
  145. ])
  146. case "$gl_cv_pthread_rwlock_rdlock_prefer_writer" in
  147. *yes)
  148. AC_DEFINE([HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER], [1],
  149. [Define if the 'pthread_rwlock_rdlock' function prefers a writer to a reader.])
  150. ;;
  151. esac
  152. ])