1 /* Test of the wait queue handling of read-write locks.
2 Copyright (C) 2024 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published
6 by the Free Software Foundation, either version 3 of the License,
7 or (at your option) any later version.
9 This file 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>, 2024. */
31 /* This program shows the wait queue handling of POSIX read-write locks.
33 The program has a single pthread_rwlock_t.
35 The function do_test takes as argument a string consisting of Rs and Ws,
36 for example RWRRW. It launches a corresponding number of threads:
37 For each R, a thread that attempts to lock the lock for reading;
38 for each W, a thread that attempts to lock the lock for writing.
39 The threads do this lock attempt one after the other.
40 The first thread keeps the lock until after all threads have issued their
41 requests, then releases it. The interesting part is, then, in which order
42 these lock attempts are granted.
44 The function find_wait_queue_handling performs a series of do_test
45 invocations and produces a textual description of the wait queue handling.
47 The main() function invokes find_wait_queue_handling for all available
48 flavours of read-write locks. */
50 /* Some platforms need a longer STEP_INTERVAL, otherwise some of the assertions
51 RRR, RRRR, RRRRR fail.
52 Note: The probability of failing these assertions is higher when the machine
53 is under high load. It can be worked around by increasing the STEP_INTERVAL.
54 However, increasing the STEP_INTERVAL means to increase the total duration
56 STEP_INTERVAL Duration (on glibc/Linux)
62 There is no way to have this test be reasonably fast and 100% reliable at the
63 same time. Therefore the compromise we have chosen is
64 - to pick STEP_INTERVAL so that the test succeeds on developer machines
65 with little load and on continuous integration machines,
66 - to exclude the test from packaging, unless the gnulib-tool option
67 '--with-longrunning-tests' is specified. */
68 #if (defined __APPLE__ && defined __MACH__)
70 # define STEP_INTERVAL 200000000 /* nanoseconds */
71 #elif defined _WIN32 || defined __CYGWIN__
73 # define STEP_INTERVAL 50000000 /* nanoseconds */
74 #elif (defined __FreeBSD__ || defined __DragonFly__) || (defined __linux__ && defined __hppa)
75 /* FreeBSD, Linux/hppa */
76 # define STEP_INTERVAL 20000000 /* nanoseconds */
78 # define STEP_INTERVAL 10000000 /* nanoseconds */
81 static pthread_rwlock_t lock
;
83 /* A lock that serializes the sprintf() calls. */
84 static pthread_rwlock_t sprintf_lock
;
89 unsigned int wait_before
;
90 unsigned int wait_after
;
95 reader_func (void *arg
)
97 struct locals
*l
= arg
;
100 if (l
->wait_before
> 0)
102 struct timespec duration
;
103 duration
.tv_sec
= l
->wait_before
/ 1000000000;
104 duration
.tv_nsec
= l
->wait_before
% 1000000000;
105 nanosleep (&duration
, NULL
);
107 err
= pthread_rwlock_rdlock (&lock
);
110 fprintf (stderr
, "pthread_rwlock_rdlock failed, error = %d\n", err
);
113 ASSERT (pthread_rwlock_wrlock (&sprintf_lock
) == 0);
114 sprintf (l
->result
+ strlen (l
->result
), " %s", l
->name
);
115 ASSERT (pthread_rwlock_unlock (&sprintf_lock
) == 0);
116 if (l
->wait_after
> 0)
118 struct timespec duration
;
119 duration
.tv_sec
= l
->wait_after
/ 1000000000;
120 duration
.tv_nsec
= l
->wait_after
% 1000000000;
121 nanosleep (&duration
, NULL
);
123 err
= pthread_rwlock_unlock (&lock
);
126 fprintf (stderr
, "pthread_rwlock_unlock failed, error = %d\n", err
);
134 writer_func (void *arg
)
136 struct locals
*l
= arg
;
139 if (l
->wait_before
> 0)
141 struct timespec duration
;
142 duration
.tv_sec
= l
->wait_before
/ 1000000000;
143 duration
.tv_nsec
= l
->wait_before
% 1000000000;
144 nanosleep (&duration
, NULL
);
146 err
= pthread_rwlock_wrlock (&lock
);
149 fprintf (stderr
, "pthread_rwlock_rdlock failed, error = %d\n", err
);
152 ASSERT (pthread_rwlock_wrlock (&sprintf_lock
) == 0);
153 sprintf (l
->result
+ strlen (l
->result
), " %s", l
->name
);
154 ASSERT (pthread_rwlock_unlock (&sprintf_lock
) == 0);
155 if (l
->wait_after
> 0)
157 struct timespec duration
;
158 duration
.tv_sec
= l
->wait_after
/ 1000000000;
159 duration
.tv_nsec
= l
->wait_after
% 1000000000;
160 nanosleep (&duration
, NULL
);
162 err
= pthread_rwlock_unlock (&lock
);
165 fprintf (stderr
, "pthread_rwlock_unlock failed, error = %d\n", err
);
173 do_test (const char *rw_string
)
175 size_t n
= strlen (rw_string
);
179 char **names
= (char **) malloc (n
* sizeof (char *));
180 for (size_t i
= 0; i
< n
; i
++)
183 sprintf (name
, "%c%u", rw_string
[i
], (unsigned int) (i
+1));
184 names
[i
] = strdup (name
);
189 /* Create the threads. */
190 struct locals
*locals
= (struct locals
*) malloc (n
* sizeof (struct locals
));
191 pthread_t
*threads
= (pthread_t
*) malloc (n
* sizeof (pthread_t
));
192 for (size_t i
= 0; i
< n
; i
++)
194 locals
[i
].name
= names
[i
];
195 locals
[i
].wait_before
= i
* STEP_INTERVAL
;
196 locals
[i
].wait_after
= (i
== 0 ? n
* STEP_INTERVAL
: 0);
197 locals
[i
].result
= resultbuf
;
198 err
= pthread_create (&threads
[i
], NULL
,
199 rw_string
[i
] == 'R' ? reader_func
:
200 rw_string
[i
] == 'W' ? writer_func
:
201 (abort (), (void * (*) (void *)) NULL
),
205 fprintf (stderr
, "pthread_create failed to create thread %u, error = %d\n",
206 (unsigned int) (i
+1), err
);
211 /* Wait until the threads are done. */
212 for (size_t i
= 0; i
< n
; i
++)
215 err
= pthread_join (threads
[i
], &retcode
);
218 fprintf (stderr
, "pthread_join failed to wait for thread %u, error = %d\n",
219 (unsigned int) (i
+1), err
);
227 for (size_t i
= 0; i
< n
; i
++)
231 return strdup (resultbuf
);
235 startswith (const char *str
, const char *prefix
)
237 return strncmp (str
, prefix
, strlen (prefix
)) == 0;
241 find_wait_queue_handling (void)
243 /* These are mandatory behaviour of rwlocks:
244 R1 R2 ... R(i-1) ... => R1 R2 ... R(i-1) ...
245 because the R2 ... R(i-1) succeed while R1 is still being held. */
246 ASSERT (startswith (do_test ("R"), " R1"));
247 ASSERT (startswith (do_test ("RR"), " R1 R2"));
248 ASSERT (startswith (do_test ("RRR"), " R1 R2 R3"));
249 ASSERT (startswith (do_test ("RRRR"), " R1 R2 R3 R4"));
250 ASSERT (startswith (do_test ("RRRRR"), " R1 R2 R3 R4 R5"));
252 bool final_r_prefers_first
= true;
253 bool final_r_prefers_readers
= true;
254 bool final_r_prefers_readers_first_reader
= true;
255 bool final_r_prefers_readers_last_reader
= true;
256 bool final_r_prefers_readers_first_writer
= true;
257 bool final_r_prefers_readers_last_writer
= true;
258 bool final_r_prefers_writers
= true;
259 bool final_r_prefers_writers_first_writer
= true;
260 bool final_r_prefers_writers_last_writer
= true;
261 bool final_w_prefers_first_a
= true;
262 bool final_w_prefers_first_b
= true;
263 bool final_w_prefers_first
= true;
264 bool final_w_prefers_readers
= true;
265 bool final_w_prefers_readers_first_reader
= true;
266 bool final_w_prefers_readers_last_reader
= true;
267 bool final_w_prefers_readers_first_writer
= true;
268 bool final_w_prefers_readers_last_writer
= true;
269 bool final_w_prefers_writers
= true;
270 bool final_w_prefers_writers_first_writer
= true;
271 bool final_w_prefers_writers_last_writer
= true;
272 bool final_w_prefers_writers_some_reader
= true;
273 bool final_w_prefers_writers_first_reader
= true;
274 bool final_w_prefers_writers_last_reader
= true;
276 /* Perform the test a few times, so that in case of a non-deterministic
277 behaviour that happens to look like deterministic in one round, we get
278 a higher probability of finding that it is non-deterministic. */
279 for (int repeat
= 3; repeat
> 0; repeat
--)
281 bool r_prefers_first
= false;
282 bool r_prefers_readers
= false;
283 bool r_prefers_readers_first_reader
= false;
284 bool r_prefers_readers_last_reader
= false;
285 bool r_prefers_readers_first_writer
= false;
286 bool r_prefers_readers_last_writer
= false;
287 bool r_prefers_writers
= false;
288 bool r_prefers_writers_first_writer
= false;
289 bool r_prefers_writers_last_writer
= false;
290 bool w_prefers_first_a
= false;
291 bool w_prefers_first_b
= false;
292 bool w_prefers_first
= false;
293 bool w_prefers_readers
= false;
294 bool w_prefers_readers_first_reader
= false;
295 bool w_prefers_readers_last_reader
= false;
296 bool w_prefers_readers_first_writer
= false;
297 bool w_prefers_readers_last_writer
= false;
298 bool w_prefers_writers
= false;
299 bool w_prefers_writers_first_writer
= false;
300 bool w_prefers_writers_last_writer
= false;
301 bool w_prefers_writers_some_reader
= false;
302 bool w_prefers_writers_first_reader
= false;
303 bool w_prefers_writers_last_reader
= false;
306 const char * RWR
= do_test ("RWR");
307 const char * RWW
= do_test ("RWW");
308 const char * RWRR
= do_test ("RWRR");
309 const char * RWRW
= do_test ("RWRW");
310 const char * RWWR
= do_test ("RWWR");
311 const char * RWWW
= do_test ("RWWW");
312 const char * RWRRR
= do_test ("RWRRR");
313 const char * RWRRW
= do_test ("RWRRW");
314 const char * RWRWR
= do_test ("RWRWR");
315 const char * RWRWW
= do_test ("RWRWW");
316 const char * RWWRR
= do_test ("RWWRR");
317 const char * RWWRW
= do_test ("RWWRW");
318 const char * RWWWR
= do_test ("RWWWR");
319 const char * RWWWW
= do_test ("RWWWW");
321 if ( startswith (RWR
, " R1 W2")
322 && startswith (RWW
, " R1 W2")
323 && startswith (RWRR
, " R1 W2")
324 && startswith (RWRW
, " R1 W2")
325 && startswith (RWWR
, " R1 W2")
326 && startswith (RWWW
, " R1 W2")
327 && startswith (RWRRR
, " R1 W2")
328 && startswith (RWRRW
, " R1 W2")
329 && startswith (RWRWR
, " R1 W2")
330 && startswith (RWRWW
, " R1 W2")
331 && startswith (RWWRR
, " R1 W2")
332 && startswith (RWWRW
, " R1 W2")
333 && startswith (RWWWR
, " R1 W2")
334 && startswith (RWWWW
, " R1 W2"))
335 r_prefers_first
= true;
336 if ( startswith (RWR
, " R1 R")
337 && startswith (RWRR
, " R1 R")
338 && startswith (RWRW
, " R1 R")
339 && startswith (RWWR
, " R1 R")
340 && startswith (RWRRR
, " R1 R")
341 && startswith (RWRRW
, " R1 R")
342 && startswith (RWRWR
, " R1 R")
343 && startswith (RWRWW
, " R1 R")
344 && startswith (RWWRR
, " R1 R")
345 && startswith (RWWRW
, " R1 R")
346 && startswith (RWWWR
, " R1 R"))
348 r_prefers_readers
= true;
349 if ( startswith (RWR
, " R1 R3")
350 && startswith (RWRR
, " R1 R3")
351 && startswith (RWRW
, " R1 R3")
352 && startswith (RWWR
, " R1 R4")
353 && startswith (RWRRR
, " R1 R3")
354 && startswith (RWRRW
, " R1 R3")
355 && startswith (RWRWR
, " R1 R3")
356 && startswith (RWRWW
, " R1 R3")
357 && startswith (RWWRR
, " R1 R4")
358 && startswith (RWWRW
, " R1 R4")
359 && startswith (RWWWR
, " R1 R5"))
360 r_prefers_readers_first_reader
= true;
361 if ( startswith (RWR
, " R1 R3")
362 && startswith (RWRR
, " R1 R4")
363 && startswith (RWRW
, " R1 R3")
364 && startswith (RWWR
, " R1 R4")
365 && startswith (RWRRR
, " R1 R5")
366 && startswith (RWRRW
, " R1 R4")
367 && startswith (RWRWR
, " R1 R5")
368 && startswith (RWRWW
, " R1 R3")
369 && startswith (RWWRR
, " R1 R5")
370 && startswith (RWWRW
, " R1 R4")
371 && startswith (RWWWR
, " R1 R5"))
372 r_prefers_readers_last_reader
= true;
373 if ( startswith (RWW
, " R1 W2")
374 && startswith (RWWW
, " R1 W2")
375 && startswith (RWWWW
, " R1 W2"))
376 r_prefers_readers_first_writer
= true;
377 if ( startswith (RWW
, " R1 W3")
378 && startswith (RWWW
, " R1 W4")
379 && startswith (RWWWW
, " R1 W5"))
380 r_prefers_readers_last_writer
= true;
381 if (!(r_prefers_readers_first_writer
|| r_prefers_readers_last_writer
))
383 printf (" RWW =>%s\n", RWW
);
384 printf (" RWWW =>%s\n", RWWW
);
385 printf (" RWWWW =>%s\n", RWWWW
);
388 if ( startswith (RWR
, " R1 W")
389 && startswith (RWW
, " R1 W")
390 && startswith (RWRR
, " R1 W")
391 && startswith (RWRW
, " R1 W")
392 && startswith (RWWR
, " R1 W")
393 && startswith (RWWW
, " R1 W")
394 && startswith (RWRRR
, " R1 W")
395 && startswith (RWRRW
, " R1 W")
396 && startswith (RWRWR
, " R1 W")
397 && startswith (RWRWW
, " R1 W")
398 && startswith (RWWRR
, " R1 W")
399 && startswith (RWWRW
, " R1 W")
400 && startswith (RWWWR
, " R1 W")
401 && startswith (RWWWW
, " R1 W"))
403 r_prefers_writers
= true;
404 if ( startswith (RWR
, " R1 W2")
405 && startswith (RWW
, " R1 W2")
406 && startswith (RWRR
, " R1 W2")
407 && startswith (RWRW
, " R1 W2")
408 && startswith (RWWR
, " R1 W2")
409 && startswith (RWWW
, " R1 W2")
410 && startswith (RWRRR
, " R1 W2")
411 && startswith (RWRRW
, " R1 W2")
412 && startswith (RWRWR
, " R1 W2")
413 && startswith (RWRWW
, " R1 W2")
414 && startswith (RWWRR
, " R1 W2")
415 && startswith (RWWRW
, " R1 W2")
416 && startswith (RWWWR
, " R1 W2")
417 && startswith (RWWWW
, " R1 W2"))
418 r_prefers_writers_first_writer
= true;
419 if ( startswith (RWR
, " R1 W2")
420 && startswith (RWW
, " R1 W3")
421 && startswith (RWRR
, " R1 W2")
422 && startswith (RWRW
, " R1 W4")
423 && startswith (RWWR
, " R1 W3")
424 && startswith (RWWW
, " R1 W4")
425 && startswith (RWRRR
, " R1 W2")
426 && startswith (RWRRW
, " R1 W5")
427 && startswith (RWRWR
, " R1 W4")
428 && startswith (RWRWW
, " R1 W5")
429 && startswith (RWWRR
, " R1 W3")
430 && startswith (RWWRW
, " R1 W5")
431 && startswith (RWWWR
, " R1 W4")
432 && startswith (RWWWW
, " R1 W5"))
433 r_prefers_writers_last_writer
= true;
435 if (!(r_prefers_first
|| r_prefers_readers
|| r_prefers_writers
))
437 printf (" RWR =>%s\n", RWR
);
438 printf (" RWW =>%s\n", RWW
);
439 printf (" RWRR =>%s\n", RWRR
);
440 printf (" RWRW =>%s\n", RWRW
);
441 printf (" RWWR =>%s\n", RWWR
);
442 printf (" RWWW =>%s\n", RWWW
);
443 printf (" RWRRR =>%s\n", RWRRR
);
444 printf (" RWRRW =>%s\n", RWRRW
);
445 printf (" RWRWR =>%s\n", RWRWR
);
446 printf (" RWRWW =>%s\n", RWRWW
);
447 printf (" RWWRR =>%s\n", RWWRR
);
448 printf (" RWWRW =>%s\n", RWWRW
);
449 printf (" RWWWR =>%s\n", RWWWR
);
450 printf (" RWWWW =>%s\n", RWWWW
);
455 const char * WRR
= do_test ("WRR");
456 const char * WRW
= do_test ("WRW");
457 const char * WWR
= do_test ("WWR");
458 const char * WWW
= do_test ("WWW");
459 const char * WRRR
= do_test ("WRRR");
460 const char * WRRW
= do_test ("WRRW");
461 const char * WRWR
= do_test ("WRWR");
462 const char * WRWW
= do_test ("WRWW");
463 const char * WWRR
= do_test ("WWRR");
464 const char * WWRW
= do_test ("WWRW");
465 const char * WWWR
= do_test ("WWWR");
466 const char * WWWW
= do_test ("WWWW");
467 const char * WRRRR
= do_test ("WRRRR");
468 const char * WRRRW
= do_test ("WRRRW");
469 const char * WRRWR
= do_test ("WRRWR");
470 const char * WRRWW
= do_test ("WRRWW");
471 const char * WRWRR
= do_test ("WRWRR");
472 const char * WRWRW
= do_test ("WRWRW");
473 const char * WRWWR
= do_test ("WRWWR");
474 const char * WRWWW
= do_test ("WRWWW");
475 const char * WWRRR
= do_test ("WWRRR");
476 const char * WWRRW
= do_test ("WWRRW");
477 const char * WWRWR
= do_test ("WWRWR");
478 const char * WWRWW
= do_test ("WWRWW");
479 const char * WWWRR
= do_test ("WWWRR");
480 const char * WWWRW
= do_test ("WWWRW");
481 const char * WWWWR
= do_test ("WWWWR");
482 const char * WWWWW
= do_test ("WWWWW");
484 if ( startswith (WRR
, " W1 R")
485 && startswith (WRW
, " W1 R")
486 && startswith (WWR
, " W1 W")
487 && startswith (WWW
, " W1 W")
488 && startswith (WRRR
, " W1 R")
489 && startswith (WRRW
, " W1 R")
490 && startswith (WRWR
, " W1 R")
491 && startswith (WRWW
, " W1 R")
492 && startswith (WWRR
, " W1 W")
493 && startswith (WWRW
, " W1 W")
494 && startswith (WWWR
, " W1 W")
495 && startswith (WWWW
, " W1 W")
496 && startswith (WRRRR
, " W1 R")
497 && startswith (WRRRW
, " W1 R")
498 && startswith (WRRWR
, " W1 R")
499 && startswith (WRRWW
, " W1 R")
500 && startswith (WRWRR
, " W1 R")
501 && startswith (WRWRW
, " W1 R")
502 && startswith (WRWWR
, " W1 R")
503 && startswith (WRWWW
, " W1 R")
504 && startswith (WWRRR
, " W1 W")
505 && startswith (WWRRW
, " W1 W")
506 && startswith (WWRWR
, " W1 W")
507 && startswith (WWRWW
, " W1 W")
508 && startswith (WWWRR
, " W1 W")
509 && startswith (WWWRW
, " W1 W")
510 && startswith (WWWWR
, " W1 W")
511 && startswith (WWWWW
, " W1 W"))
513 w_prefers_first_a
= true;
514 if ( startswith (WRR
, " W1 R")
515 && startswith (WRW
, " W1 R")
516 && startswith (WWR
, " W1 W2")
517 && startswith (WWW
, " W1 W2")
518 && startswith (WRRR
, " W1 R")
519 && startswith (WRRW
, " W1 R")
520 && startswith (WRWR
, " W1 R")
521 && startswith (WRWW
, " W1 R")
522 && startswith (WWRR
, " W1 W2")
523 && startswith (WWRW
, " W1 W2")
524 && startswith (WWWR
, " W1 W2")
525 && startswith (WWWW
, " W1 W2")
526 && startswith (WRRRR
, " W1 R")
527 && startswith (WRRRW
, " W1 R")
528 && startswith (WRRWR
, " W1 R")
529 && startswith (WRRWW
, " W1 R")
530 && startswith (WRWRR
, " W1 R")
531 && startswith (WRWRW
, " W1 R")
532 && startswith (WRWWR
, " W1 R")
533 && startswith (WRWWW
, " W1 R")
534 && startswith (WWRRR
, " W1 W2")
535 && startswith (WWRRW
, " W1 W2")
536 && startswith (WWRWR
, " W1 W2")
537 && startswith (WWRWW
, " W1 W2")
538 && startswith (WWWRR
, " W1 W2")
539 && startswith (WWWRW
, " W1 W2")
540 && startswith (WWWWR
, " W1 W2")
541 && startswith (WWWWW
, " W1 W2"))
543 w_prefers_first_b
= true;
544 if ( startswith (WRR
, " W1 R2")
545 && startswith (WRW
, " W1 R2")
546 && startswith (WWR
, " W1 W2")
547 && startswith (WWW
, " W1 W2")
548 && startswith (WRRR
, " W1 R2")
549 && startswith (WRRW
, " W1 R2")
550 && startswith (WRWR
, " W1 R2")
551 && startswith (WRWW
, " W1 R2")
552 && startswith (WWRR
, " W1 W2")
553 && startswith (WWRW
, " W1 W2")
554 && startswith (WWWR
, " W1 W2")
555 && startswith (WWWW
, " W1 W2")
556 && startswith (WRRRR
, " W1 R2")
557 && startswith (WRRRW
, " W1 R2")
558 && startswith (WRRWR
, " W1 R2")
559 && startswith (WRRWW
, " W1 R2")
560 && startswith (WRWRR
, " W1 R2")
561 && startswith (WRWRW
, " W1 R2")
562 && startswith (WRWWR
, " W1 R2")
563 && startswith (WRWWW
, " W1 R2")
564 && startswith (WWRRR
, " W1 W2")
565 && startswith (WWRRW
, " W1 W2")
566 && startswith (WWRWR
, " W1 W2")
567 && startswith (WWRWW
, " W1 W2")
568 && startswith (WWWRR
, " W1 W2")
569 && startswith (WWWRW
, " W1 W2")
570 && startswith (WWWWR
, " W1 W2")
571 && startswith (WWWWW
, " W1 W2"))
572 w_prefers_first
= true;
575 if ( startswith (WRR
, " W1 R")
576 && startswith (WRW
, " W1 R")
577 && startswith (WWR
, " W1 R")
578 && startswith (WRRR
, " W1 R")
579 && startswith (WRRW
, " W1 R")
580 && startswith (WRWR
, " W1 R")
581 && startswith (WRWW
, " W1 R")
582 && startswith (WWRR
, " W1 R")
583 && startswith (WWRW
, " W1 R")
584 && startswith (WWWR
, " W1 R")
585 && startswith (WRRRR
, " W1 R")
586 && startswith (WRRRW
, " W1 R")
587 && startswith (WRRWR
, " W1 R")
588 && startswith (WRRWW
, " W1 R")
589 && startswith (WRWRR
, " W1 R")
590 && startswith (WRWRW
, " W1 R")
591 && startswith (WRWWR
, " W1 R")
592 && startswith (WRWWW
, " W1 R")
593 && startswith (WWRRR
, " W1 R")
594 && startswith (WWRRW
, " W1 R")
595 && startswith (WWRWR
, " W1 R")
596 && startswith (WWRWW
, " W1 R")
597 && startswith (WWWRR
, " W1 R")
598 && startswith (WWWRW
, " W1 R")
599 && startswith (WWWWR
, " W1 R"))
601 w_prefers_readers
= true;
602 if ( startswith (WRR
, " W1 R2")
603 && startswith (WRW
, " W1 R2")
604 && startswith (WWR
, " W1 R3")
605 && startswith (WRRR
, " W1 R2")
606 && startswith (WRRW
, " W1 R2")
607 && startswith (WRWR
, " W1 R2")
608 && startswith (WRWW
, " W1 R2")
609 && startswith (WWRR
, " W1 R3")
610 && startswith (WWRW
, " W1 R3")
611 && startswith (WWWR
, " W1 R4")
612 && startswith (WRRRR
, " W1 R2")
613 && startswith (WRRRW
, " W1 R2")
614 && startswith (WRRWR
, " W1 R2")
615 && startswith (WRRWW
, " W1 R2")
616 && startswith (WRWRR
, " W1 R2")
617 && startswith (WRWRW
, " W1 R2")
618 && startswith (WRWWR
, " W1 R2")
619 && startswith (WRWWW
, " W1 R2")
620 && startswith (WWRRR
, " W1 R3")
621 && startswith (WWRRW
, " W1 R3")
622 && startswith (WWRWR
, " W1 R3")
623 && startswith (WWRWW
, " W1 R3")
624 && startswith (WWWRR
, " W1 R4")
625 && startswith (WWWRW
, " W1 R4")
626 && startswith (WWWWR
, " W1 R5"))
627 w_prefers_readers_first_reader
= true;
628 if ( startswith (WRR
, " W1 R3")
629 && startswith (WRW
, " W1 R2")
630 && startswith (WWR
, " W1 R3")
631 && startswith (WRRR
, " W1 R4")
632 && startswith (WRRW
, " W1 R3")
633 && startswith (WRWR
, " W1 R4")
634 && startswith (WRWW
, " W1 R2")
635 && startswith (WWRR
, " W1 R4")
636 && startswith (WWRW
, " W1 R3")
637 && startswith (WWWR
, " W1 R4")
638 && startswith (WRRRR
, " W1 R5")
639 && startswith (WRRRW
, " W1 R4")
640 && startswith (WRRWR
, " W1 R5")
641 && startswith (WRRWW
, " W1 R3")
642 && startswith (WRWRR
, " W1 R5")
643 && startswith (WRWRW
, " W1 R4")
644 && startswith (WRWWR
, " W1 R5")
645 && startswith (WRWWW
, " W1 R2")
646 && startswith (WWRRR
, " W1 R5")
647 && startswith (WWRRW
, " W1 R4")
648 && startswith (WWRWR
, " W1 R5")
649 && startswith (WWRWW
, " W1 R3")
650 && startswith (WWWRR
, " W1 R5")
651 && startswith (WWWRW
, " W1 R4")
652 && startswith (WWWWR
, " W1 R5"))
653 w_prefers_readers_last_reader
= true;
654 if ( startswith (WWW
, " W1 W2 W3")
655 && startswith (WWWW
, " W1 W2 W3 W4")
656 && startswith (WWWWW
, " W1 W2 W3 W4 W5"))
657 w_prefers_readers_first_writer
= true;
658 if ( startswith (WWW
, " W1 W3")
659 && startswith (WWWW
, " W1 W4")
660 && startswith (WWWWW
, " W1 W5"))
661 w_prefers_readers_last_writer
= true;
662 if (!(w_prefers_readers_first_writer
|| w_prefers_readers_last_writer
))
664 printf (" WWW =>%s\n", WWW
);
665 printf (" WWWW =>%s\n", WWWW
);
666 printf (" WWWWW =>%s\n", WWWWW
);
669 if ( startswith (WRW
, " W1 W")
670 && startswith (WWR
, " W1 W")
671 && startswith (WWW
, " W1 W")
672 && startswith (WRRW
, " W1 W")
673 && startswith (WRWR
, " W1 W")
674 && startswith (WRWW
, " W1 W")
675 && startswith (WWRR
, " W1 W")
676 && startswith (WWRW
, " W1 W")
677 && startswith (WWWR
, " W1 W")
678 && startswith (WWWW
, " W1 W")
679 && startswith (WRRRW
, " W1 W")
680 && startswith (WRRWR
, " W1 W")
681 && startswith (WRRWW
, " W1 W")
682 && startswith (WRWRR
, " W1 W")
683 && startswith (WRWRW
, " W1 W")
684 && startswith (WRWWR
, " W1 W")
685 && startswith (WRWWW
, " W1 W")
686 && startswith (WWRRR
, " W1 W")
687 && startswith (WWRRW
, " W1 W")
688 && startswith (WWRWR
, " W1 W")
689 && startswith (WWRWW
, " W1 W")
690 && startswith (WWWRR
, " W1 W")
691 && startswith (WWWRW
, " W1 W")
692 && startswith (WWWWR
, " W1 W")
693 && startswith (WWWWW
, " W1 W"))
695 w_prefers_writers
= true;
696 if ( startswith (WRW
, " W1 W3")
697 && startswith (WWR
, " W1 W2")
698 && startswith (WWW
, " W1 W2")
699 && startswith (WRRW
, " W1 W4")
700 && startswith (WRWR
, " W1 W3")
701 && startswith (WRWW
, " W1 W3")
702 && startswith (WWRR
, " W1 W2")
703 && startswith (WWRW
, " W1 W2")
704 && startswith (WWWR
, " W1 W2")
705 && startswith (WWWW
, " W1 W2")
706 && startswith (WRRRW
, " W1 W5")
707 && startswith (WRRWR
, " W1 W4")
708 && startswith (WRRWW
, " W1 W4")
709 && startswith (WRWRR
, " W1 W3")
710 && startswith (WRWRW
, " W1 W3")
711 && startswith (WRWWR
, " W1 W3")
712 && startswith (WRWWW
, " W1 W3")
713 && startswith (WWRRR
, " W1 W2")
714 && startswith (WWRRW
, " W1 W2")
715 && startswith (WWRWR
, " W1 W2")
716 && startswith (WWRWW
, " W1 W2")
717 && startswith (WWWRR
, " W1 W2")
718 && startswith (WWWRW
, " W1 W2")
719 && startswith (WWWWR
, " W1 W2")
720 && startswith (WWWWW
, " W1 W2"))
721 w_prefers_writers_first_writer
= true;
722 if ( startswith (WRW
, " W1 W3")
723 && startswith (WWR
, " W1 W2")
724 && startswith (WWW
, " W1 W3")
725 && startswith (WRRW
, " W1 W4")
726 && startswith (WRWR
, " W1 W3")
727 && startswith (WRWW
, " W1 W4")
728 && startswith (WWRR
, " W1 W2")
729 && startswith (WWRW
, " W1 W4")
730 && startswith (WWWR
, " W1 W3")
731 && startswith (WWWW
, " W1 W4")
732 && startswith (WRRRW
, " W1 W5")
733 && startswith (WRRWR
, " W1 W4")
734 && startswith (WRRWW
, " W1 W5")
735 && startswith (WRWRR
, " W1 W3")
736 && startswith (WRWRW
, " W1 W5")
737 && startswith (WRWWR
, " W1 W4")
738 && startswith (WRWWW
, " W1 W5")
739 && startswith (WWRRR
, " W1 W2")
740 && startswith (WWRRW
, " W1 W5")
741 && startswith (WWRWR
, " W1 W4")
742 && startswith (WWRWW
, " W1 W5")
743 && startswith (WWWRR
, " W1 W3")
744 && startswith (WWWRW
, " W1 W5")
745 && startswith (WWWWR
, " W1 W4")
746 && startswith (WWWWW
, " W1 W5"))
747 w_prefers_writers_last_writer
= true;
748 if ( startswith (WRR
, " W1 R")
749 && startswith (WRRR
, " W1 R")
750 && startswith (WRRRR
, " W1 R"))
752 w_prefers_writers_some_reader
= true;
753 if ( startswith (WRR
, " W1 R2 R3")
754 && startswith (WRRR
, " W1 R2 R3 R4")
755 && startswith (WRRRR
, " W1 R2 R3 R4 R5"))
756 w_prefers_writers_first_reader
= true;
757 if ( startswith (WRR
, " W1 R3")
758 && startswith (WRRR
, " W1 R4")
759 && startswith (WRRRR
, " W1 R5"))
760 w_prefers_writers_last_reader
= true;
762 if (!w_prefers_writers_some_reader
)
764 printf (" WRR =>%s\n", WRR
);
765 printf (" WRRR =>%s\n", WRRR
);
766 printf (" WRRRR =>%s\n", WRRRR
);
769 if (!(w_prefers_first_a
|| w_prefers_readers
|| w_prefers_writers
))
771 printf (" WRR =>%s\n", WRR
);
772 printf (" WRW =>%s\n", WRW
);
773 printf (" WWR =>%s\n", WWR
);
774 printf (" WWW =>%s\n", WWW
);
775 printf (" WRRR =>%s\n", WRRR
);
776 printf (" WRRW =>%s\n", WRRW
);
777 printf (" WRWR =>%s\n", WRWR
);
778 printf (" WRWW =>%s\n", WRWW
);
779 printf (" WWRR =>%s\n", WWRR
);
780 printf (" WWRW =>%s\n", WWRW
);
781 printf (" WWWR =>%s\n", WWWR
);
782 printf (" WWWW =>%s\n", WWWW
);
783 printf (" WRRRR =>%s\n", WRRRR
);
784 printf (" WRRRW =>%s\n", WRRRW
);
785 printf (" WRRWR =>%s\n", WRRWR
);
786 printf (" WRRWW =>%s\n", WRRWW
);
787 printf (" WRWRR =>%s\n", WRWRR
);
788 printf (" WRWRW =>%s\n", WRWRW
);
789 printf (" WRWWR =>%s\n", WRWWR
);
790 printf (" WRWWW =>%s\n", WRWWW
);
791 printf (" WWRRR =>%s\n", WWRRR
);
792 printf (" WWRRW =>%s\n", WWRRW
);
793 printf (" WWRWR =>%s\n", WWRWR
);
794 printf (" WWRWW =>%s\n", WWRWW
);
795 printf (" WWWRR =>%s\n", WWWRR
);
796 printf (" WWWRW =>%s\n", WWWRW
);
797 printf (" WWWWR =>%s\n", WWWWR
);
798 printf (" WWWWW =>%s\n", WWWWW
);
802 final_r_prefers_first
&= r_prefers_first
;
803 final_r_prefers_readers
&= r_prefers_readers
;
804 final_r_prefers_readers_first_reader
&= r_prefers_readers_first_reader
;
805 final_r_prefers_readers_last_reader
&= r_prefers_readers_last_reader
;
806 final_r_prefers_readers_first_writer
&= r_prefers_readers_first_writer
;
807 final_r_prefers_readers_last_writer
&= r_prefers_readers_last_writer
;
808 final_r_prefers_writers
&= r_prefers_writers
;
809 final_r_prefers_writers_first_writer
&= r_prefers_writers_first_writer
;
810 final_r_prefers_writers_last_writer
&= r_prefers_writers_last_writer
;
811 final_w_prefers_first_a
&= w_prefers_first_a
;
812 final_w_prefers_first_b
&= w_prefers_first_b
;
813 final_w_prefers_first
&= w_prefers_first
;
814 final_w_prefers_readers
&= w_prefers_readers
;
815 final_w_prefers_readers_first_reader
&= w_prefers_readers_first_reader
;
816 final_w_prefers_readers_last_reader
&= w_prefers_readers_last_reader
;
817 final_w_prefers_readers_first_writer
&= w_prefers_readers_first_writer
;
818 final_w_prefers_readers_last_writer
&= w_prefers_readers_last_writer
;
819 final_w_prefers_writers
&= w_prefers_writers
;
820 final_w_prefers_writers_first_writer
&= w_prefers_writers_first_writer
;
821 final_w_prefers_writers_last_writer
&= w_prefers_writers_last_writer
;
822 final_w_prefers_writers_some_reader
&= w_prefers_writers_some_reader
;
823 final_w_prefers_writers_first_reader
&= w_prefers_writers_first_reader
;
824 final_w_prefers_writers_last_reader
&= w_prefers_writers_last_reader
;
827 bool deterministic
= true;
829 printf (" When releasing the last reader lock:\n");
831 if (final_r_prefers_first
)
832 printf (" The first of the enqueued lock attempts is granted.\n");
833 else if (final_r_prefers_readers
)
835 if (final_r_prefers_readers_first_reader
)
836 printf (" If at least one of the enqueued lock attempts is for reading, the\n"
837 " first one of them is granted.\n");
838 else if (final_r_prefers_readers_last_reader
)
839 printf (" If at least one of the enqueued lock attempts is for reading, the\n"
840 " latest (LIFO!) one of them is granted.\n");
843 printf (" If at least one of the enqueued lock attempts is for reading, one\n"
844 " of them is granted.\n");
845 deterministic
= false;
847 if (final_r_prefers_readers_first_writer
)
848 printf (" Otherwise, the first of the waiting write attempts is granted.\n");
849 else if (final_r_prefers_readers_last_writer
)
850 printf (" Otherwise, the latest (LIFO!) waiting write attempt is granted.\n");
853 printf (" Otherwise ???\n");
854 deterministic
= false;
857 else if (final_r_prefers_writers
)
859 if (final_r_prefers_writers_first_writer
)
860 printf (" If at least one of the enqueued lock attempts is for writing, the\n"
861 " first one of them is granted.\n");
862 else if (final_r_prefers_writers_last_writer
)
863 printf (" If at least one of the enqueued lock attempts is for writing, the\n"
864 " latest (LIFO!) one of them is granted.\n");
867 printf (" If at least one of the enqueued lock attempts is for writing, one\n"
868 " of them is granted.\n");
869 deterministic
= false;
875 deterministic
= false;
878 printf (" When releasing a writer lock:\n");
880 if (final_w_prefers_first_a
)
882 if (final_w_prefers_first_b
)
884 if (final_w_prefers_first
)
885 printf (" The first of the enqueued lock attempts is granted.\n");
888 printf (" If at least one of the enqueued lock attempts is for writing, the\n"
889 " first of them is granted.\n"
890 " Otherwise, one of the waiting read attempts is granted.\n");
891 deterministic
= false;
896 printf (" If at least one of the enqueued lock attempts is for writing, one of\n"
897 " the waiting write attempts is granted.\n"
898 " Otherwise, one of the waiting read attempts is granted.\n");
899 deterministic
= false;
902 else if (final_w_prefers_readers
)
904 if (final_w_prefers_readers_first_reader
)
905 printf (" If at least one of the enqueued lock attempts is for reading, the\n"
906 " first of them is granted.\n");
907 else if (final_w_prefers_readers_last_reader
)
908 printf (" If at least one of the enqueued lock attempts is for reading, the\n"
909 " latest (LIFO!) one of them is granted.\n");
912 printf (" If at least one of the enqueued lock attempts is for reading, one of\n"
913 " them is granted.\n");
914 deterministic
= false;
916 if (final_w_prefers_readers_first_writer
)
917 printf (" Otherwise, the first of the waiting write attempts is granted.\n");
918 else if (final_w_prefers_readers_last_writer
)
919 printf (" Otherwise, the latest (LIFO!) of the waiting write attempts is granted.\n");
922 printf (" Otherwise ???\n");
923 deterministic
= false;
926 else if (final_w_prefers_writers
)
928 if (final_w_prefers_writers_first_writer
)
929 printf (" If at least one of the enqueued lock attempts is for writing, the\n"
930 " first one of them is granted.\n");
931 else if (final_w_prefers_writers_last_writer
)
932 printf (" If at least one of the enqueued lock attempts is for writing, the\n"
933 " latest (LIFO!) one of them is granted.\n");
936 printf (" If at least one of the enqueued lock attempts is for writing, one of\n"
937 " the waiting write attempts is granted (not necessarily the first one).\n");
938 deterministic
= false;
940 if (final_w_prefers_writers_some_reader
)
942 if (final_w_prefers_writers_first_reader
)
943 printf (" Otherwise, the first of the waiting read attempts is granted.\n");
944 else if (final_w_prefers_writers_last_reader
)
945 printf (" Otherwise, the latest (LIFO!) of the waiting read attempts is granted.\n");
948 printf (" Otherwise, one of the waiting read attempts is granted.\n");
949 deterministic
= false;
954 printf (" Otherwise, ???\n");
955 deterministic
= false;
961 deterministic
= false;
964 if (final_r_prefers_readers
)
966 if (final_w_prefers_readers
)
967 printf (" This implementation always prefers readers.\n");
969 printf (" This implementation does not globally prefer readers, only when releasing\n"
970 " a reader lock.\n");
974 if (final_w_prefers_readers
)
975 printf (" This implementation does not globally prefer readers, only when releasing\n"
976 " a writer lock.\n");
978 printf (" This implementation does not prefer readers.\n");
981 if (final_r_prefers_writers
)
983 if (final_w_prefers_writers
)
984 printf (" This implementation always prefers writers.\n");
986 printf (" This implementation does not globally prefer writers, only when releasing\n"
987 " a reader lock.\n");
991 if (final_w_prefers_writers
)
992 printf (" This implementation does not globally prefer writers, only when releasing\n"
993 " a writer lock.\n");
995 printf (" This implementation does not prefer writers.\n");
999 printf (" This implementation is deterministic.\n");
1001 /* The wait queue handling is unsuitable if it always prefers readers,
1002 because it leads to writer starvation: On machines with 8 or more CPUs,
1003 test-pthread-rwlock may never terminate. See
1004 <https://lists.gnu.org/archive/html/bug-gnulib/2024-06/msg00291.html>
1005 <https://lists.gnu.org/archive/html/bug-gnulib/2024-07/msg00081.html>
1007 return final_r_prefers_readers
&& final_w_prefers_readers
;
1013 /* Initialize the sprintf_lock. */
1014 ASSERT (pthread_rwlock_init (&sprintf_lock
, NULL
) == 0);
1016 #if __GLIBC__ >= 2 && defined __linux__
1018 /* Find the wait queue handling of a PREFER_READER lock. */
1019 printf ("glibc/Linux PREFER_READER\n");
1021 pthread_rwlockattr_t attr
;
1022 ASSERT (pthread_rwlockattr_init (&attr
) == 0);
1023 ASSERT (pthread_rwlockattr_setkind_np (&attr
, PTHREAD_RWLOCK_PREFER_READER_NP
) == 0);
1024 ASSERT (pthread_rwlock_init (&lock
, &attr
) == 0);
1025 ASSERT (pthread_rwlockattr_destroy (&attr
) == 0);
1026 find_wait_queue_handling ();
1027 ASSERT (pthread_rwlock_destroy (&lock
) == 0);
1030 /* Find the wait queue handling of an PREFER_WRITER lock. */
1031 printf ("glibc/Linux PREFER_WRITER\n");
1033 pthread_rwlockattr_t attr
;
1034 ASSERT (pthread_rwlockattr_init (&attr
) == 0);
1035 ASSERT (pthread_rwlockattr_setkind_np (&attr
, PTHREAD_RWLOCK_PREFER_WRITER_NP
) == 0);
1036 ASSERT (pthread_rwlock_init (&lock
, &attr
) == 0);
1037 ASSERT (pthread_rwlockattr_destroy (&attr
) == 0);
1038 find_wait_queue_handling ();
1039 ASSERT (pthread_rwlock_destroy (&lock
) == 0);
1042 /* Find the wait queue handling of a PREFER_WRITER_NONRECURSIVE lock. */
1043 printf ("glibc/Linux PREFER_WRITER_NONRECURSIVE\n");
1045 pthread_rwlockattr_t attr
;
1046 ASSERT (pthread_rwlockattr_init (&attr
) == 0);
1047 ASSERT (pthread_rwlockattr_setkind_np (&attr
, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
) == 0);
1048 ASSERT (pthread_rwlock_init (&lock
, &attr
) == 0);
1049 ASSERT (pthread_rwlockattr_destroy (&attr
) == 0);
1050 find_wait_queue_handling ();
1051 ASSERT (pthread_rwlock_destroy (&lock
) == 0);
1054 /* Find the wait queue handling of a DEFAULT lock. */
1055 printf ("glibc/Linux DEFAULT\n");
1057 pthread_rwlockattr_t attr
;
1058 ASSERT (pthread_rwlockattr_init (&attr
) == 0);
1059 ASSERT (pthread_rwlockattr_setkind_np (&attr
, PTHREAD_RWLOCK_DEFAULT_NP
) == 0);
1060 ASSERT (pthread_rwlock_init (&lock
, &attr
) == 0);
1061 ASSERT (pthread_rwlockattr_destroy (&attr
) == 0);
1062 find_wait_queue_handling ();
1063 ASSERT (pthread_rwlock_destroy (&lock
) == 0);
1068 /* Find the wait queue handling of a default-initialized lock. */
1069 printf ("Default\n");
1070 ASSERT (pthread_rwlock_init (&lock
, NULL
) == 0);
1072 int fail
= find_wait_queue_handling ();
1073 ASSERT (pthread_rwlock_destroy (&lock
) == 0);
1077 return test_exit_status
;