diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2020-02-09 20:07:51 +0000 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2020-02-09 20:07:51 +0000 |
commit | d5ec049d44f019deaeed8adc0bd10819e5569e93 (patch) | |
tree | 26b03705007a5b239c5239124f8c9381dd83001a /nptl | |
parent | 28c30a6232aa9a54783c146590498a061fc0112a (diff) | |
download | glibc-d5ec049d44f019deaeed8adc0bd10819e5569e93.tar.gz glibc-d5ec049d44f019deaeed8adc0bd10819e5569e93.tar.xz glibc-d5ec049d44f019deaeed8adc0bd10819e5569e93.zip |
pthread: Move some rwlock tests from nptl to sysdeps/pthread
So they can be checked with htl too.
Diffstat (limited to 'nptl')
-rw-r--r-- | nptl/Makefile | 9 | ||||
-rw-r--r-- | nptl/tst-rwlock-tryrdlock-stall.c | 355 | ||||
-rw-r--r-- | nptl/tst-rwlock-trywrlock-stall.c | 108 | ||||
-rw-r--r-- | nptl/tst-rwlock1.c | 116 | ||||
-rw-r--r-- | nptl/tst-rwlock13.c | 70 | ||||
-rw-r--r-- | nptl/tst-rwlock16.c | 182 | ||||
-rw-r--r-- | nptl/tst-rwlock4.c | 189 | ||||
-rw-r--r-- | nptl/tst-rwlock5.c | 84 |
8 files changed, 4 insertions, 1109 deletions
diff --git a/nptl/Makefile b/nptl/Makefile index bf21413c26..3ad3024a39 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -244,10 +244,10 @@ tests = tst-attr2 tst-attr3 tst-default-attr \ tst-robust6 tst-robust7 tst-robust8 tst-robust9 \ tst-robustpi1 tst-robustpi2 tst-robustpi3 tst-robustpi4 tst-robustpi5 \ tst-robustpi6 tst-robustpi7 tst-robustpi8 tst-robustpi9 \ - tst-rwlock1 tst-rwlock2 tst-rwlock2a tst-rwlock2b tst-rwlock3 \ - tst-rwlock4 tst-rwlock5 tst-rwlock6 tst-rwlock7 tst-rwlock8 \ - tst-rwlock9 tst-rwlock10 tst-rwlock11 tst-rwlock12 tst-rwlock13 \ - tst-rwlock14 tst-rwlock15 tst-rwlock16 tst-rwlock17 tst-rwlock18 \ + tst-rwlock2 tst-rwlock2a tst-rwlock2b tst-rwlock3 \ + tst-rwlock6 tst-rwlock7 tst-rwlock8 \ + tst-rwlock9 tst-rwlock10 tst-rwlock11 tst-rwlock12 \ + tst-rwlock14 tst-rwlock15 tst-rwlock17 tst-rwlock18 \ tst-once5 \ tst-key1 tst-key2 tst-key3 tst-key4 \ tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \ @@ -306,7 +306,6 @@ tests = tst-attr2 tst-attr3 tst-default-attr \ tst-thread-exit-clobber tst-minstack-cancel tst-minstack-exit \ tst-minstack-throw \ tst-rwlock-pwn \ - tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall \ tst-unwind-thread tests-container = tst-pthread-getattr diff --git a/nptl/tst-rwlock-tryrdlock-stall.c b/nptl/tst-rwlock-tryrdlock-stall.c deleted file mode 100644 index bb2a64f301..0000000000 --- a/nptl/tst-rwlock-tryrdlock-stall.c +++ /dev/null @@ -1,355 +0,0 @@ -/* Bug 23844: Test for pthread_rwlock_tryrdlock stalls. - Copyright (C) 2019-2020 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <https://www.gnu.org/licenses/>. */ - -/* For a full analysis see comment: - https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14 - - Provided here for reference: - - --- Analysis of pthread_rwlock_tryrdlock() stall --- - A read lock begins to execute. - - In __pthread_rwlock_rdlock_full: - - We can attempt a read lock, but find that the lock is - in a write phase (PTHREAD_RWLOCK_WRPHASE, or WP-bit - is set), and the lock is held by a primary writer - (PTHREAD_RWLOCK_WRLOCKED is set). In this case we must - wait for explicit hand over from the writer to us or - one of the other waiters. The read lock threads are - about to execute: - - 341 r = (atomic_fetch_add_acquire (&rwlock->__data.__readers, - 342 (1 << PTHREAD_RWLOCK_READER_SHIFT)) - 343 + (1 << PTHREAD_RWLOCK_READER_SHIFT)); - - An unlock beings to execute. - - Then in __pthread_rwlock_wrunlock: - - 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers); - ... - 549 while (!atomic_compare_exchange_weak_release - 550 (&rwlock->__data.__readers, &r, - 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED) - 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 - 553 : PTHREAD_RWLOCK_WRPHASE)))) - 554 { - ... - 556 } - - We clear PTHREAD_RWLOCK_WRLOCKED, and if there are - no readers so we leave the lock in PTHRAD_RWLOCK_WRPHASE. - - Back in the read lock. - - The read lock adjusts __readres as above. - - 383 while ((r & PTHREAD_RWLOCK_WRPHASE) != 0 - 384 && (r & PTHREAD_RWLOCK_WRLOCKED) == 0) - 385 { - ... - 390 if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, &r, - 391 r ^ PTHREAD_RWLOCK_WRPHASE)) - 392 { - - And then attemps to start the read phase. - - Assume there happens to be a tryrdlock at this point, noting - that PTHREAD_RWLOCK_WRLOCKED is clear, and PTHREAD_RWLOCK_WRPHASE - is 1. So the try lock attemps to start the read phase. - - In __pthread_rwlock_tryrdlock: - - 44 if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) - 45 { - ... - 49 if (((r & PTHREAD_RWLOCK_WRLOCKED) != 0) - 50 && (rwlock->__data.__flags - 51 == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)) - 52 return EBUSY; - 53 rnew = r + (1 << PTHREAD_RWLOCK_READER_SHIFT); - 54 } - ... - 89 while (!atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, - 90 &r, rnew)); - - And succeeds. - - Back in the write unlock: - - 557 if ((r >> PTHREAD_RWLOCK_READER_SHIFT) != 0) - 558 { - ... - 563 if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0) - 564 & PTHREAD_RWLOCK_FUTEX_USED) != 0) - 565 futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private); - 566 } - - We note that PTHREAD_RWLOCK_FUTEX_USED is non-zero - and don't wake anyone. This is OK because we handed - over to the trylock. It will be the trylock's responsibility - to wake any waiters. - - Back in the read lock: - - The read lock fails to install PTHRAD_REWLOCK_WRPHASE as 0 because - the __readers value was adjusted by the trylock, and so it falls through - to waiting on the lock for explicit handover from either a new writer - or a new reader. - - 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, - 449 1 | PTHREAD_RWLOCK_FUTEX_USED, - 450 abstime, private); - - We use PTHREAD_RWLOCK_FUTEX_USED to indicate the futex - is in use. - - At this point we have readers waiting on the read lock - to unlock. The wrlock is done. The trylock is finishing - the installation of the read phase. - - 92 if ((r & PTHREAD_RWLOCK_WRPHASE) != 0) - 93 { - ... - 105 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0); - 106 } - - The trylock does note that we were the one that - installed the read phase, but the comments are not - correct, the execution ordering above shows that - readers might indeed be waiting, and they are. - - The atomic_store_relaxed throws away PTHREAD_RWLOCK_FUTEX_USED, - and the waiting reader is never worken becuase as noted - above it is conditional on the futex being used. - - The solution is for the trylock thread to inspect - PTHREAD_RWLOCK_FUTEX_USED and wake the waiting readers. - - --- Analysis of pthread_rwlock_trywrlock() stall --- - - A write lock begins to execute, takes the write lock, - and then releases the lock... - - In pthread_rwlock_wrunlock(): - - 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers); - ... - 549 while (!atomic_compare_exchange_weak_release - 550 (&rwlock->__data.__readers, &r, - 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED) - 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 - 553 : PTHREAD_RWLOCK_WRPHASE)))) - 554 { - ... - 556 } - - ... leaving it in the write phase with zero readers - (the case where we leave the write phase in place - during a write unlock). - - A write trylock begins to execute. - - In __pthread_rwlock_trywrlock: - - 40 while (((r & PTHREAD_RWLOCK_WRLOCKED) == 0) - 41 && (((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0) - 42 || (prefer_writer && ((r & PTHREAD_RWLOCK_WRPHASE) != 0)))) - 43 { - - The lock is not locked. - - There are no readers. - - 45 if (atomic_compare_exchange_weak_acquire ( - 46 &rwlock->__data.__readers, &r, - 47 r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED)) - - We atomically install the write phase and we take the - exclusive write lock. - - 48 { - 49 atomic_store_relaxed (&rwlock->__data.__writers_futex, 1); - - We get this far. - - A reader lock begins to execute. - - In pthread_rwlock_rdlock: - - 437 for (;;) - 438 { - 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) - 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) - 441 { - 442 int private = __pthread_rwlock_get_private (rwlock); - 443 if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) - 444 && (!atomic_compare_exchange_weak_relaxed - 445 (&rwlock->__data.__wrphase_futex, - 446 &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED))) - 447 continue; - 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, - 449 1 | PTHREAD_RWLOCK_FUTEX_USED, - 450 abstime, private); - - We are in a write phase, so the while() on line 439 is true. - - The value of wpf does not have PTHREAD_RWLOCK_FUTEX_USED set - since this is the first reader to lock. - - The atomic operation sets wpf with PTHREAD_RELOCK_FUTEX_USED - on the expectation that this reader will be woken during - the handoff. - - Back in pthread_rwlock_trywrlock: - - 50 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); - 51 atomic_store_relaxed (&rwlock->__data.__cur_writer, - 52 THREAD_GETMEM (THREAD_SELF, tid)); - 53 return 0; - 54 } - ... - 57 } - - We write 1 to __wrphase_futex discarding PTHREAD_RWLOCK_FUTEX_USED, - and so in the unlock we will not awaken the waiting reader. - - The solution to this is to realize that if we did not start the write - phase we need not write 1 or any other value to __wrphase_futex. - This ensures that any readers (which saw __wrphase_futex != 0) can - set PTHREAD_RWLOCK_FUTEX_USED and this can be used at unlock to - wake them. - - If we installed the write phase then all other readers are looping - here: - - In __pthread_rwlock_rdlock_full: - - 437 for (;;) - 438 { - 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) - 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) - 441 { - ... - 508 } - - waiting for the write phase to be installed or removed before they - can begin waiting on __wrphase_futex (part of the algorithm), or - taking a concurrent read lock, and thus we can safely write 1 to - __wrphase_futex. - - If we did not install the write phase then the readers may already - be waiting on the futex, the original writer wrote 1 to __wrphase_futex - as part of starting the write phase, and we cannot also write 1 - without loosing the PTHREAD_RWLOCK_FUTEX_USED bit. - - --- - - Summary for the pthread_rwlock_tryrdlock() stall: - - The stall is caused by pthread_rwlock_tryrdlock failing to check - that PTHREAD_RWLOCK_FUTEX_USED is set in the __wrphase_futex futex - and then waking the futex. - - The fix for bug 23844 ensures that waiters on __wrphase_futex are - correctly woken. Before the fix the test stalls as readers can - wait forever on __wrphase_futex. */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <pthread.h> -#include <support/xthread.h> -#include <errno.h> - -/* We need only one lock to reproduce the issue. We will need multiple - threads to get the exact case where we have a read, try, and unlock - all interleaving to produce the case where the readers are waiting - and the try fails to wake them. */ -pthread_rwlock_t onelock; - -/* The number of threads is arbitrary but empirically chosen to have - enough threads that we see the condition where waiting readers are - not woken by a successful tryrdlock. */ -#define NTHREADS 32 - -_Atomic int do_exit; - -void * -run_loop (void *arg) -{ - int i = 0, ret; - while (!do_exit) - { - /* Arbitrarily choose if we are the writer or reader. Choose a - high enough ratio of readers to writers to make it likely - that readers block (and eventually are susceptable to - stalling). - - If we are a writer, take the write lock, and then unlock. - If we are a reader, try the lock, then lock, then unlock. */ - if ((i % 8) != 0) - xpthread_rwlock_wrlock (&onelock); - else - { - if ((ret = pthread_rwlock_tryrdlock (&onelock)) != 0) - { - if (ret == EBUSY) - xpthread_rwlock_rdlock (&onelock); - else - exit (EXIT_FAILURE); - } - } - /* Thread does some work and then unlocks. */ - xpthread_rwlock_unlock (&onelock); - i++; - } - return NULL; -} - -int -do_test (void) -{ - int i; - pthread_t tids[NTHREADS]; - xpthread_rwlock_init (&onelock, NULL); - for (i = 0; i < NTHREADS; i++) - tids[i] = xpthread_create (NULL, run_loop, NULL); - /* Run for some amount of time. Empirically speaking exercising - the stall via pthread_rwlock_tryrdlock is much harder, and on - a 3.5GHz 4 core x86_64 VM system it takes somewhere around - 20-200s to stall, approaching 100% stall past 200s. We can't - wait that long for a regression test so we just test for 20s, - and expect the stall to happen with a 5-10% chance (enough for - developers to see). */ - sleep (20); - /* Then exit. */ - printf ("INFO: Exiting...\n"); - do_exit = 1; - /* If any readers stalled then we will timeout waiting for them. */ - for (i = 0; i < NTHREADS; i++) - xpthread_join (tids[i]); - printf ("INFO: Done.\n"); - xpthread_rwlock_destroy (&onelock); - printf ("PASS: No pthread_rwlock_tryrdlock stalls detected.\n"); - return 0; -} - -#define TIMEOUT 30 -#include <support/test-driver.c> diff --git a/nptl/tst-rwlock-trywrlock-stall.c b/nptl/tst-rwlock-trywrlock-stall.c deleted file mode 100644 index b4e60c5af3..0000000000 --- a/nptl/tst-rwlock-trywrlock-stall.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Bug 23844: Test for pthread_rwlock_trywrlock stalls. - Copyright (C) 2019-2020 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <https://www.gnu.org/licenses/>. */ - -/* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c. - - Summary for the pthread_rwlock_trywrlock() stall: - - The stall is caused by pthread_rwlock_trywrlock setting - __wrphase_futex futex to 1 and loosing the - PTHREAD_RWLOCK_FUTEX_USED bit. - - The fix for bug 23844 ensures that waiters on __wrphase_futex are - correctly woken. Before the fix the test stalls as readers can - wait forever on __wrphase_futex. */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <pthread.h> -#include <support/xthread.h> -#include <errno.h> - -/* We need only one lock to reproduce the issue. We will need multiple - threads to get the exact case where we have a read, try, and unlock - all interleaving to produce the case where the readers are waiting - and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a - subsequent unlock fails to wake them. */ -pthread_rwlock_t onelock; - -/* The number of threads is arbitrary but empirically chosen to have - enough threads that we see the condition where waiting readers are - not woken by a successful unlock. */ -#define NTHREADS 32 - -_Atomic int do_exit; - -void * -run_loop (void *arg) -{ - int i = 0, ret; - while (!do_exit) - { - /* Arbitrarily choose if we are the writer or reader. Choose a - high enough ratio of readers to writers to make it likely - that readers block (and eventually are susceptable to - stalling). - - If we are a writer, take the write lock, and then unlock. - If we are a reader, try the lock, then lock, then unlock. */ - if ((i % 8) != 0) - { - if ((ret = pthread_rwlock_trywrlock (&onelock)) != 0) - { - if (ret == EBUSY) - xpthread_rwlock_wrlock (&onelock); - else - exit (EXIT_FAILURE); - } - } - else - xpthread_rwlock_rdlock (&onelock); - /* Thread does some work and then unlocks. */ - xpthread_rwlock_unlock (&onelock); - i++; - } - return NULL; -} - -int -do_test (void) -{ - int i; - pthread_t tids[NTHREADS]; - xpthread_rwlock_init (&onelock, NULL); - for (i = 0; i < NTHREADS; i++) - tids[i] = xpthread_create (NULL, run_loop, NULL); - /* Run for some amount of time. The pthread_rwlock_tryrwlock stall - is very easy to trigger and happens in seconds under the test - conditions. */ - sleep (10); - /* Then exit. */ - printf ("INFO: Exiting...\n"); - do_exit = 1; - /* If any readers stalled then we will timeout waiting for them. */ - for (i = 0; i < NTHREADS; i++) - xpthread_join (tids[i]); - printf ("INFO: Done.\n"); - xpthread_rwlock_destroy (&onelock); - printf ("PASS: No pthread_rwlock_tryrwlock stalls detected.\n"); - return 0; -} - -#include <support/test-driver.c> diff --git a/nptl/tst-rwlock1.c b/nptl/tst-rwlock1.c deleted file mode 100644 index d14d3036a2..0000000000 --- a/nptl/tst-rwlock1.c +++ /dev/null @@ -1,116 +0,0 @@ -/* Copyright (C) 2002-2020 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <https://www.gnu.org/licenses/>. */ - -#include <pthread.h> -#include <stdio.h> - - -static int -do_test (void) -{ - pthread_rwlock_t r; - - if (pthread_rwlock_init (&r, NULL) != 0) - { - puts ("rwlock_init failed"); - return 1; - } - puts ("rwlock_init succeeded"); - - if (pthread_rwlock_rdlock (&r) != 0) - { - puts ("1st rwlock_rdlock failed"); - return 1; - } - puts ("1st rwlock_rdlock succeeded"); - - if (pthread_rwlock_rdlock (&r) != 0) - { - puts ("2nd rwlock_rdlock failed"); - return 1; - } - puts ("2nd rwlock_rdlock succeeded"); - - if (pthread_rwlock_unlock (&r) != 0) - { - puts ("1st rwlock_unlock failed"); - return 1; - } - puts ("1st rwlock_unlock succeeded"); - - if (pthread_rwlock_unlock (&r) != 0) - { - puts ("2nd rwlock_unlock failed"); - return 1; - } - puts ("2nd rwlock_unlock succeeded"); - - if (pthread_rwlock_wrlock (&r) != 0) - { - puts ("1st rwlock_wrlock failed"); - return 1; - } - puts ("1st rwlock_wrlock succeeded"); - - if (pthread_rwlock_unlock (&r) != 0) - { - puts ("3rd rwlock_unlock failed"); - return 1; - } - puts ("3rd rwlock_unlock succeeded"); - - if (pthread_rwlock_wrlock (&r) != 0) - { - puts ("2nd rwlock_wrlock failed"); - return 1; - } - puts ("2nd rwlock_wrlock succeeded"); - - if (pthread_rwlock_unlock (&r) != 0) - { - puts ("4th rwlock_unlock failed"); - return 1; - } - puts ("4th rwlock_unlock succeeded"); - - if (pthread_rwlock_rdlock (&r) != 0) - { - puts ("3rd rwlock_rdlock failed"); - return 1; - } - puts ("3rd rwlock_rdlock succeeded"); - - if (pthread_rwlock_unlock (&r) != 0) - { - puts ("5th rwlock_unlock failed"); - return 1; - } - puts ("5th rwlock_unlock succeeded"); - - if (pthread_rwlock_destroy (&r) != 0) - { - puts ("rwlock_destroy failed"); - return 1; - } - puts ("rwlock_destroy succeeded"); - - return 0; -} - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-rwlock13.c b/nptl/tst-rwlock13.c deleted file mode 100644 index 749ec4b621..0000000000 --- a/nptl/tst-rwlock13.c +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (C) 2004-2020 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <https://www.gnu.org/licenses/>. */ - -#include <pthread.h> -#include <stdio.h> -#include <string.h> - - -static int -do_test (void) -{ - pthread_rwlock_t r; - int ret; - - memset (&r, 0xaa, sizeof (r)); - if ((ret = pthread_rwlock_init (&r, NULL)) != 0) - { - printf ("rwlock_init failed: %d\n", ret); - return 1; - } - - if ((ret = pthread_rwlock_rdlock (&r)) != 0) - { - printf ("rwlock_rdlock failed: %d\n", ret); - return 1; - } - - if ((ret = pthread_rwlock_unlock (&r)) != 0) - { - printf ("rwlock_unlock failed: %d\n", ret); - return 1; - } - - if ((ret = pthread_rwlock_wrlock (&r)) != 0) - { - printf ("rwlock_wrlock failed: %d\n", ret); - return 1; - } - - if ((ret = pthread_rwlock_unlock (&r)) != 0) - { - printf ("second rwlock_unlock failed: %d\n", ret); - return 1; - } - - if ((ret = pthread_rwlock_destroy (&r)) != 0) - { - printf ("second rwlock_destroy failed: %d\n", ret); - return 1; - } - - return 0; -} - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-rwlock16.c b/nptl/tst-rwlock16.c deleted file mode 100644 index 29720c9d8d..0000000000 --- a/nptl/tst-rwlock16.c +++ /dev/null @@ -1,182 +0,0 @@ -/* Copyright (C) 2015-2020 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <https://www.gnu.org/licenses/>. */ - -/* This tests that with a reader-preferring rwlock, all readers are woken if - one reader "steals" lock ownership from a blocked writer. */ - -#include <errno.h> -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <semaphore.h> -#include <unistd.h> - -/* If we strictly prefer writers over readers, a program must not expect - that, in the presence of concurrent writers, one reader will also acquire - the lock when another reader has already done so. Thus, use the - default rwlock type that does not strictly prefer writers. */ -static pthread_rwlock_t r = PTHREAD_RWLOCK_INITIALIZER; - -static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t cv = PTHREAD_COND_INITIALIZER; - -/* Avoid using glibc-internal atomic operations. */ -static sem_t stop; -static int consumer_stop = 0; - -static void * -writer (void *arg) -{ - int s; - - do - { - if (pthread_rwlock_wrlock (&r) != 0) - { - puts ("wrlock failed"); - exit (EXIT_FAILURE); - } - if (pthread_rwlock_unlock (&r) != 0) - { - puts ("unlock failed"); - exit (EXIT_FAILURE); - } - sem_getvalue (&stop, &s); - } - while (s == 0); - return NULL; -} - -static void * -reader_producer (void *arg) -{ - int s; - - do - { - if (pthread_rwlock_rdlock (&r) != 0) - { - puts ("rdlock reader failed"); - exit (EXIT_FAILURE); - } - - sem_getvalue (&stop, &s); - - pthread_mutex_lock (&m); - if (s != 0) - consumer_stop = 1; - pthread_cond_signal (&cv); - pthread_mutex_unlock (&m); - - if (pthread_rwlock_unlock (&r) != 0) - { - puts ("unlock reader failed"); - exit (EXIT_FAILURE); - } - } - while (s == 0); - puts ("producer finished"); - return NULL; -} - -static void * -reader_consumer (void *arg) -{ - int s; - - do - { - if (pthread_rwlock_rdlock (&r) != 0) - { - puts ("rdlock reader failed"); - exit (EXIT_FAILURE); - } - - pthread_mutex_lock (&m); - s = consumer_stop; - if (s == 0) - pthread_cond_wait (&cv, &m); - pthread_mutex_unlock (&m); - - if (pthread_rwlock_unlock (&r) != 0) - { - puts ("unlock reader failed"); - exit (EXIT_FAILURE); - } - } - while (s == 0); - puts ("consumer finished"); - return NULL; -} - - -static int -do_test (void) -{ - pthread_t w1, w2, rp, rc; - - if (pthread_create (&w1, NULL, writer, NULL) != 0) - { - puts ("create failed"); - return 1; - } - if (pthread_create (&w2, NULL, writer, NULL) != 0) - { - puts ("create failed"); - return 1; - } - if (pthread_create (&rc, NULL, reader_consumer, NULL) != 0) - { - puts ("create failed"); - return 1; - } - if (pthread_create (&rp, NULL, reader_producer, NULL) != 0) - { - puts ("create failed"); - return 1; - } - - sleep (2); - sem_post (&stop); - - if (pthread_join (w1, NULL) != 0) - { - puts ("w1 join failed"); - return 1; - } - if (pthread_join (w2, NULL) != 0) - { - puts ("w2 join failed"); - return 1; - } - if (pthread_join (rp, NULL) != 0) - { - puts ("reader_producer join failed"); - return 1; - } - if (pthread_join (rc, NULL) != 0) - { - puts ("reader_consumer join failed"); - return 1; - } - - return 0; -} - - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-rwlock4.c b/nptl/tst-rwlock4.c deleted file mode 100644 index 479107a5f2..0000000000 --- a/nptl/tst-rwlock4.c +++ /dev/null @@ -1,189 +0,0 @@ -/* Copyright (C) 2002-2020 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <https://www.gnu.org/licenses/>. */ - -#include <errno.h> -#include <pthread.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/mman.h> -#include <sys/wait.h> - - -static int -do_test (void) -{ - size_t ps = sysconf (_SC_PAGESIZE); - char tmpfname[] = "/tmp/tst-rwlock4.XXXXXX"; - char data[ps]; - void *mem; - int fd; - pthread_rwlock_t *r; - pthread_rwlockattr_t a; - pid_t pid; - char *p; - int err; - int s; - - fd = mkstemp (tmpfname); - if (fd == -1) - { - printf ("cannot open temporary file: %m\n"); - return 1; - } - - /* Make sure it is always removed. */ - unlink (tmpfname); - - /* Create one page of data. */ - memset (data, '\0', ps); - - /* Write the data to the file. */ - if (write (fd, data, ps) != (ssize_t) ps) - { - puts ("short write"); - return 1; - } - - mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (mem == MAP_FAILED) - { - printf ("mmap failed: %m\n"); - return 1; - } - - r = (pthread_rwlock_t *) (((uintptr_t) mem + __alignof (pthread_rwlock_t)) - & ~(__alignof (pthread_rwlock_t) - 1)); - p = (char *) (r + 1); - - if (pthread_rwlockattr_init (&a) != 0) - { - puts ("rwlockattr_init failed"); - return 1; - } - - if (pthread_rwlockattr_getpshared (&a, &s) != 0) - { - puts ("1st rwlockattr_getpshared failed"); - return 1; - } - - if (s != PTHREAD_PROCESS_PRIVATE) - { - puts ("default pshared value wrong"); - return 1; - } - - if (pthread_rwlockattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) - { - puts ("rwlockattr_setpshared failed"); - return 1; - } - - if (pthread_rwlockattr_getpshared (&a, &s) != 0) - { - puts ("2nd rwlockattr_getpshared failed"); - return 1; - } - - if (s != PTHREAD_PROCESS_SHARED) - { - puts ("pshared value after setpshared call wrong"); - return 1; - } - - if (pthread_rwlock_init (r, &a) != 0) - { - puts ("rwlock_init failed"); - return 1; - } - - if (pthread_rwlock_rdlock (r) != 0) - { - puts ("rwlock_rdlock failed"); - return 1; - } - - if (pthread_rwlockattr_destroy (&a) != 0) - { - puts ("rwlockattr_destroy failed"); - return 1; - } - - err = pthread_rwlock_trywrlock (r); - if (err == 0) - { - puts ("rwlock_trywrlock succeeded"); - return 1; - } - else if (err != EBUSY) - { - puts ("rwlock_trywrlock didn't return EBUSY"); - return 1; - } - - *p = 0; - - puts ("going to fork now"); - pid = fork (); - if (pid == -1) - { - puts ("fork failed"); - return 1; - } - else if (pid == 0) - { - /* Play some lock ping-pong. It's our turn to unlock first. */ - if ((*p)++ != 0) - { - puts ("child: *p != 0"); - return 1; - } - - if (pthread_rwlock_unlock (r) != 0) - { - puts ("child: 1st rwlock_unlock failed"); - return 1; - } - - puts ("child done"); - } - else - { - if (pthread_rwlock_wrlock (r) != 0) - { - puts ("parent: rwlock_wrlock failed"); - return 1; - } - - if (*p != 1) - { - puts ("*p != 1"); - return 1; - } - - puts ("parent done"); - } - - return 0; -} - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" diff --git a/nptl/tst-rwlock5.c b/nptl/tst-rwlock5.c deleted file mode 100644 index c589764196..0000000000 --- a/nptl/tst-rwlock5.c +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (C) 2002-2020 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <https://www.gnu.org/licenses/>. */ - -#include <pthread.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -static int do_test (void); - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" - -static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; -static pthread_rwlock_t r; - - -static void * -tf (void *arg) -{ - if (pthread_rwlock_wrlock (&r) == 0) - { - puts ("child: rwlock_wrlock succeeded"); - exit (1); - } - - puts ("child: rwlock_wrlock returned"); - - exit (1); -} - - -static int -do_test (void) -{ - pthread_t th; - - if (pthread_rwlock_init (&r, NULL) != 0) - { - puts ("rwlock_init failed"); - return 1; - } - - if (pthread_rwlock_wrlock (&r) != 0) - { - puts ("rwlock_wrlock failed"); - return 1; - } - - if (pthread_mutex_lock (&m) != 0) - { - puts ("mutex_lock failed"); - return 1; - } - - if (pthread_create (&th, NULL, tf, NULL) != 0) - { - puts ("create failed"); - return 1; - } - - delayed_exit (1); - /* This call should never return. */ - xpthread_mutex_lock (&m); - - puts ("2nd mutex_lock returned"); - return 1; -} |