1 /* Test of glthread_rwlock_rdlock function.
2 Copyright (C) 2017-2019 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2005.
19 https://github.com/linux-test-project/ltp/blob/master/testcases/open_posix_testsuite/conformance/interfaces/pthread_rwlock_rdlock/2-2.c
20 by Intel Corporation. */
24 #include "glthread/lock.h"
31 #include "glthread/thread.h"
32 #include "glthread/yield.h"
34 /* Verify that in a situation where
35 - an rwlock is taken by a reader and has a writer waiting,
36 - an additional reader requests the lock,
37 - the waiting writer and the requesting reader threads have the same
39 the requesting reader thread gets blocked, so that at some point the
40 waiting writer can acquire the lock.
41 Without such a guarantee, when there a N readers and each of the readers
42 spends more than 1/Nth of the time with the lock held, there is a high
43 probability that the waiting writer will not get the lock in a given finite
44 time, a phenomenon called "writer starvation".
45 Without such a guarantee, applications have a hard time avoiding writer
48 POSIX:2008 makes this requirement only for implementations that support TPS
49 (Thread Priority Scheduling) and only for the scheduling policies SCHED_FIFO
51 http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html
52 but test verifies the guarantee regardless of TPS and regardless of
55 #define SUCCEED() exit (0)
56 #define FAILURE() exit (1)
57 #define UNEXPECTED(n) (fprintf (stderr, "Unexpected outcome %d\n", n), abort ())
59 /* The main thread creates the waiting writer and the requesting reader threads
60 in the default way; this guarantees that they have the same priority.
61 We can reuse the main thread as first reader thread. */
63 static gl_rwlock_t lock
;
64 static gl_thread_t reader1
;
65 static gl_thread_t writer
;
66 static gl_thread_t reader2
;
67 static gl_thread_t timer
;
68 /* Used to pass control from writer to reader2 and from reader2 to timer,
70 Passing control from one running thread to another running thread
71 is most likely faster than to create the second thread. */
72 static gl_lock_t baton
;
75 timer_func (void *ignored
)
77 /* Step 13 (can be before or after step 12):
78 The timer thread takes the baton, then waits a moment to make sure
79 it can tell whether the second reader thread is blocked at step 12. */
80 if (glthread_lock_lock (&baton
))
83 /* By the time we get here, it's clear that the second reader thread is
84 blocked at step 12. This is the desired behaviour. */
89 reader2_func (void *ignored
)
93 /* Step 8 (can be before or after step 7):
94 The second reader thread takes the baton, then waits a moment to make sure
95 the writer thread has reached step 7. */
96 if (glthread_lock_lock (&baton
))
100 /* Step 10: Launch a timer, to test whether the next call blocks. */
101 if (glthread_create (&timer
, timer_func
, NULL
))
103 /* Step 11: Release the baton. */
104 if (glthread_lock_unlock (&baton
))
106 /* Step 12: The second reader thread requests the lock. */
107 err
= glthread_rwlock_rdlock (&lock
);
115 writer_func (void *ignored
)
117 /* Step 4: Take the baton, so that the second reader thread does not go ahead
119 if (glthread_lock_lock (&baton
))
121 /* Step 5: Create the second reader thread. */
122 if (glthread_create (&reader2
, reader2_func
, NULL
))
124 /* Step 6: Release the baton. */
125 if (glthread_lock_unlock (&baton
))
127 /* Step 7: The writer thread requests the lock. */
128 if (glthread_rwlock_wrlock (&lock
))
136 reader1
= gl_thread_self ();
138 /* Step 1: The main thread initializes the lock and the baton. */
139 if (glthread_rwlock_init (&lock
))
141 if (glthread_lock_init (&baton
))
143 /* Step 2: The main thread acquires the lock as a reader. */
144 if (glthread_rwlock_rdlock (&lock
))
146 /* Step 3: Create the writer thread. */
147 if (glthread_create (&writer
, writer_func
, NULL
))
149 /* Job done. Go to sleep. */
152 /* In cooperative threads implementations (Pth), give other threads