[gcc r17-4395] libstdc++: Make __gnu_test::semaphore work without SysV semget [PR127425]
Jonathan Wakely
redi@gcc.gnu.org
Thu Sep 17 17:51:53 GMT 2026
https://gcc.gnu.org/g:409e74cc30b03afda59fc0d5711be71cd2e1bb59
commit r17-4395-g409e74cc30b03afda59fc0d5711be71cd2e1bb59
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Wed Sep 16 10:56:07 2026 +0100
libstdc++: Make __gnu_test::semaphore work without SysV semget [PR127425]
Port the testsuite's simple semaphore type to use POSIX semaphores when
System V semaphores are not supported, as the latter are part of the XSI
option and not mandated by POSIX. For the POSIX semaphore path we need
to use mmap to create the semaphore in shared memory and also need to
handle ancient systems without MAP_ANONYMOUS support. We use unnamed
semaphores because using sem_open to create a named semaphore requires
creating two or more unique names per test that work even when the tests
are run in parallel, which would get awkward.
Although it might appear better to prefer the new path and use POSIX
semaphores by default, that wouldn't work because macOS defines
_POSIX_SEMAPHORES to a positive value but its sem_init always returns
ENOSYS at runtime. Instead of trying sem_init and then switching to
shmget as a runtime fallback, we might as well just continue using the
code that we know works fine - i.e. the SysV semaphore implementation.
The new sem_init path is only used for systems where the existing code
doesn't work, which currently just PASS the tests incorrectly as
described in Bug 127425.
For the case where neither SysV nor POSIX semaphores are available, make
the __gnu_test::semaphore constructor abort, so the tests FAIL loudly
instead of a silent PASS. This fixes the main points raised in the bug
report.
Move the definition of the semaphore to a new header, so that it's only
defined in the handful of tests that actually use it, and move the
definitions of the member functions to a new .cc file.
In passing, fix a resource leak in the existing code for the case where
semget creates a new semaphore set but semctl fails to initialize it.
Because SysV semaphores are kernel objects, the set would not be
destroyed when the process exits. Use semctl with IPC_RMID before
throwing an exception, so that the kernel removes the semaphore set.
Also make the __gnu_test::semaphore class non-copyable to prevent
misuse and double-frees.
Also add a dejagnu dg-require-sysv-or-posix-semaphore directive so that
tests which don't support either type of semaphore will be UNSUPPORTED
instead of PASS (or FAIL with the new aborting constructor). This test
uses _XOPEN_UNIX rather than the three autoconf macros that are checked
in testsuite_semaphore.cc but that is a reasonable proxy for SysV
semaphore support. It might mean that some very old systems mark those
tests as UNSUPPORTED when they do actually support the SysV semaphores
without defining the _XOPEN_UNIX macro. I can live with that.
It would be nice to use std::unique_ptr with a custom deleter to manage
the SysV semaphore set or the mmap region and POSIX semaphore. That
could only be done as local variables in testsuite_semaphore.cc not as
a non-static data member of __gnu_test::semaphore, because the tests
which use __gnu_test::semaphore need to run as C++98 and so they can't
use std::unique_ptr in the header. The additional logic to define and
use a custom deleter doesn't seem worth it if it wouldn't actually
remove the __gnu_test::semaphore destructor.
libstdc++-v3/ChangeLog:
PR libstdc++/127425
* doc/xml/manual/test.xml: Document new testsuite header.
* doc/html/manual/test.html: Regenerate.
* testsuite/27_io/basic_filebuf/close/char/4879.cc: Use new
dg-require-sysv-or-posix-semaphore directive.
* testsuite/27_io/basic_filebuf/close/char/9964.cc: Likewise.
* testsuite/27_io/basic_filebuf/imbue/char/13171-2.cc: Likewise.
* testsuite/27_io/basic_filebuf/imbue/wchar_t/14975-2.cc:
Likewise.
* testsuite/27_io/basic_filebuf/seekoff/char/26777.cc: Likewise.
* testsuite/27_io/basic_filebuf/underflow/char/10097.cc:
Likewise.
* testsuite/27_io/objects/char/7.cc: Likewise.
* testsuite/27_io/objects/char/9661-1.cc: Likewise.
* testsuite/27_io/objects/wchar_t/7.cc: Likewise.
* testsuite/27_io/objects/wchar_t/9661-1.cc: Likewise.
* testsuite/lib/dg-options.exp
(dg-require-sysv-or-posix-semaphore): New proc.
* testsuite/lib/libstdc++.exp (v3-build_support): Add new file
to list of testsuite source files.
(check_v3_target_posix_or_sysv_semaphore): New proc.
* testsuite/util/testsuite_hooks.cc (semaphore): Move to new
file.
* testsuite/util/testsuite_hooks.h (semaphore): Likewise.
* testsuite/util/testsuite_semaphore.cc: Move definition of
semaphore member functions here. Fix resource leak in
constructor if semctl fails. Add fallback using mmap+sem_init
instead of semget+semctl.
* testsuite/util/testsuite_semaphore.h: Move definition of
semaphore to here. Replace sem_set_ data member with anonymous
union. Add deleted copy operations.
Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com>
Diff:
---
libstdc++-v3/doc/html/manual/test.html | 6 +-
libstdc++-v3/doc/xml/manual/test.xml | 8 +
.../27_io/basic_filebuf/close/char/4879.cc | 2 +
.../27_io/basic_filebuf/close/char/9964.cc | 2 +
.../27_io/basic_filebuf/imbue/char/13171-2.cc | 2 +
.../27_io/basic_filebuf/imbue/wchar_t/14975-2.cc | 2 +
.../27_io/basic_filebuf/seekoff/char/26777.cc | 2 +
.../27_io/basic_filebuf/underflow/char/10097.cc | 2 +
libstdc++-v3/testsuite/27_io/objects/char/7.cc | 2 +
.../testsuite/27_io/objects/char/9661-1.cc | 2 +
libstdc++-v3/testsuite/27_io/objects/wchar_t/7.cc | 2 +
.../testsuite/27_io/objects/wchar_t/9661-1.cc | 2 +
libstdc++-v3/testsuite/lib/dg-options.exp | 9 ++
libstdc++-v3/testsuite/lib/libstdc++.exp | 11 ++
libstdc++-v3/testsuite/util/testsuite_hooks.cc | 96 ------------
libstdc++-v3/testsuite/util/testsuite_hooks.h | 24 ---
libstdc++-v3/testsuite/util/testsuite_semaphore.cc | 170 +++++++++++++++++++++
libstdc++-v3/testsuite/util/testsuite_semaphore.h | 68 +++++++++
18 files changed, 291 insertions(+), 121 deletions(-)
diff --git a/libstdc++-v3/doc/html/manual/test.html b/libstdc++-v3/doc/html/manual/test.html
index 404d7ddbf879..1db7dd5bcae7 100644
--- a/libstdc++-v3/doc/html/manual/test.html
+++ b/libstdc++-v3/doc/html/manual/test.html
@@ -647,7 +647,11 @@ only default variables.
</p><p>
A number of class abstractions for performance counters, and
reporting functions including:
- </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem"><p>time_counter</p></li><li class="listitem"><p>resource_counter</p></li><li class="listitem"><p>report_performance</p></li></ul></div></li></ul></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="test.special"></a>Special Topics</h3></div></div></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a id="test.exception.safety"></a>
+ </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem"><p>time_counter</p></li><li class="listitem"><p>resource_counter</p></li><li class="listitem"><p>report_performance</p></li></ul></div></li><li class="listitem"><p>
+ <span class="emphasis"><em>testsuite_semaphore.h</em></span>
+ </p><p>
+ A simple binary semaphore used for some multi-process I/O tests.
+ </p></li></ul></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="test.special"></a>Special Topics</h3></div></div></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a id="test.exception.safety"></a>
Qualifying Exception Safety Guarantees
<a id="id-1.3.6.3.5.7.2.1.1.1" class="indexterm"></a>
</h4></div></div></div><div class="section"><div class="titlepage"><div><div><h5 class="title"><a id="test.exception.safety.overview"></a>Overview</h5></div></div></div><p>
diff --git a/libstdc++-v3/doc/xml/manual/test.xml b/libstdc++-v3/doc/xml/manual/test.xml
index 68b5f8aedb41..f5c441bd9413 100644
--- a/libstdc++-v3/doc/xml/manual/test.xml
+++ b/libstdc++-v3/doc/xml/manual/test.xml
@@ -1081,6 +1081,14 @@ only default variables.
<listitem><para>report_performance</para></listitem>
</itemizedlist>
</listitem>
+ <listitem>
+ <para>
+ <emphasis>testsuite_semaphore.h</emphasis>
+ </para>
+ <para>
+ A simple binary semaphore used for some multi-process I/O tests.
+ </para>
+ </listitem>
</itemizedlist>
</section>
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/close/char/4879.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/close/char/4879.cc
index 3e0b134edb95..5246a33e8493 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/close/char/4879.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/close/char/4879.cc
@@ -1,5 +1,6 @@
// { dg-require-fork "" }
// { dg-require-mkfifo "" }
+// { dg-require-sysv-or-posix-semaphore "" }
// Copyright (C) 2001-2026 Free Software Foundation, Inc.
//
@@ -33,6 +34,7 @@
#include <sys/stat.h>
#include <testsuite_hooks.h>
+#include <testsuite_semaphore.h>
// libstdc++/2913, libstdc++/4879
// John Fardo <jfardo@laurelnetworks.com>, Brad Garcia <garsh@attbi.com>
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/close/char/9964.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/close/char/9964.cc
index ba864fa7e9e8..84b406ac0727 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/close/char/9964.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/close/char/9964.cc
@@ -1,5 +1,6 @@
// { dg-require-fork "" }
// { dg-require-mkfifo "" }
+// { dg-require-sysv-or-posix-semaphore "" }
// Copyright (C) 2001-2026 Free Software Foundation, Inc.
//
@@ -32,6 +33,7 @@
#include <sys/stat.h>
#include <testsuite_hooks.h>
+#include <testsuite_semaphore.h>
// libstdc++/9964
bool test_07()
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/char/13171-2.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/char/13171-2.cc
index 5a42e18834b0..210efae9a98a 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/char/13171-2.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/char/13171-2.cc
@@ -2,6 +2,7 @@
// { dg-require-namedlocale "en_US.ISO8859-1" }
// { dg-require-fork "" }
// { dg-require-mkfifo "" }
+// { dg-require-sysv-or-posix-semaphore "" }
// Copyright (C) 2003-2026 Free Software Foundation, Inc.
//
@@ -30,6 +31,7 @@
#include <sys/stat.h>
#include <testsuite_hooks.h>
+#include <testsuite_semaphore.h>
// libstdc++/13171
bool test01()
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/wchar_t/14975-2.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/wchar_t/14975-2.cc
index f4dadd917ee9..886b7d66053b 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/wchar_t/14975-2.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/wchar_t/14975-2.cc
@@ -1,6 +1,7 @@
// { dg-require-namedlocale "en_US.ISO8859-1" }
// { dg-require-fork "" }
// { dg-require-mkfifo "" }
+// { dg-require-sysv-or-posix-semaphore "" }
// 2004-04-16 Petur Runolfsson <peturr02@ru.is>
@@ -31,6 +32,7 @@
#include <sys/stat.h>
#include <testsuite_hooks.h>
+#include <testsuite_semaphore.h>
// libstdc++/14975
bool test01()
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/seekoff/char/26777.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/seekoff/char/26777.cc
index b003090f920c..1931db09ad04 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/seekoff/char/26777.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/seekoff/char/26777.cc
@@ -1,5 +1,6 @@
// { dg-require-fork "" }
// { dg-require-mkfifo "" }
+// { dg-require-sysv-or-posix-semaphore "" }
// 2006-03-22 Paolo Carlini <pcarlini@suse.de>
@@ -21,6 +22,7 @@
// <http://www.gnu.org/licenses/>.
#include <testsuite_hooks.h>
+#include <testsuite_semaphore.h>
#include <fstream>
#include <sstream>
#include <cstdlib>
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/char/10097.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/char/10097.cc
index e7c9a91aca04..c320b99920bd 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/char/10097.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/underflow/char/10097.cc
@@ -1,5 +1,6 @@
// { dg-require-fork "" }
// { dg-require-mkfifo "" }
+// { dg-require-sysv-or-posix-semaphore "" }
// 2001-05-21 Benjamin Kosnik <bkoz@redhat.com>
@@ -31,6 +32,7 @@
#include <sys/stat.h>
#include <testsuite_hooks.h>
+#include <testsuite_semaphore.h>
class UnderBuf : public std::filebuf
{
diff --git a/libstdc++-v3/testsuite/27_io/objects/char/7.cc b/libstdc++-v3/testsuite/27_io/objects/char/7.cc
index b5e6fe5b6d7b..2edcf56f7889 100644
--- a/libstdc++-v3/testsuite/27_io/objects/char/7.cc
+++ b/libstdc++-v3/testsuite/27_io/objects/char/7.cc
@@ -1,5 +1,6 @@
// { dg-require-fork "" }
// { dg-require-mkfifo "" }
+// { dg-require-sysv-or-posix-semaphore "" }
// 2003-04-26 Petur Runolfsson <peturr02@ru.is>
@@ -31,6 +32,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <testsuite_hooks.h>
+#include <testsuite_semaphore.h>
// Check that cout.flush() is called when last ios_base::Init is destroyed.
bool test07()
diff --git a/libstdc++-v3/testsuite/27_io/objects/char/9661-1.cc b/libstdc++-v3/testsuite/27_io/objects/char/9661-1.cc
index d9e39cd80c83..9374685969db 100644
--- a/libstdc++-v3/testsuite/27_io/objects/char/9661-1.cc
+++ b/libstdc++-v3/testsuite/27_io/objects/char/9661-1.cc
@@ -1,5 +1,6 @@
// { dg-require-fork "" }
// { dg-require-mkfifo "" }
+// { dg-require-sysv-or-posix-semaphore "" }
// 2003-04-30 Petur Runolfsson <peturr02@ru.is>
@@ -21,6 +22,7 @@
// <http://www.gnu.org/licenses/>.
#include <testsuite_hooks.h>
+#include <testsuite_semaphore.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
diff --git a/libstdc++-v3/testsuite/27_io/objects/wchar_t/7.cc b/libstdc++-v3/testsuite/27_io/objects/wchar_t/7.cc
index 2c03fa1791b9..cc6a2fa3e7d0 100644
--- a/libstdc++-v3/testsuite/27_io/objects/wchar_t/7.cc
+++ b/libstdc++-v3/testsuite/27_io/objects/wchar_t/7.cc
@@ -1,5 +1,6 @@
// { dg-require-fork "" }
// { dg-require-mkfifo "" }
+// { dg-require-sysv-or-posix-semaphore "" }
// 2003-05-01 Petur Runolfsson <peturr02@ru.is>
@@ -32,6 +33,7 @@
#include <sys/stat.h>
#include <testsuite_hooks.h>
+#include <testsuite_semaphore.h>
// Check that wcout.flush() is called when last ios_base::Init is destroyed.
bool test07()
diff --git a/libstdc++-v3/testsuite/27_io/objects/wchar_t/9661-1.cc b/libstdc++-v3/testsuite/27_io/objects/wchar_t/9661-1.cc
index f49d010fbf91..f8194aef3eec 100644
--- a/libstdc++-v3/testsuite/27_io/objects/wchar_t/9661-1.cc
+++ b/libstdc++-v3/testsuite/27_io/objects/wchar_t/9661-1.cc
@@ -1,5 +1,6 @@
// { dg-require-fork "" }
// { dg-require-mkfifo "" }
+// { dg-require-sysv-or-posix-semaphore "" }
// 2003-04-30 Petur Runolfsson <peturr02@ru.is>
@@ -21,6 +22,7 @@
// <http://www.gnu.org/licenses/>.
#include <testsuite_hooks.h>
+#include <testsuite_semaphore.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
diff --git a/libstdc++-v3/testsuite/lib/dg-options.exp b/libstdc++-v3/testsuite/lib/dg-options.exp
index 615a57992602..a9563026174d 100644
--- a/libstdc++-v3/testsuite/lib/dg-options.exp
+++ b/libstdc++-v3/testsuite/lib/dg-options.exp
@@ -286,6 +286,15 @@ proc dg-require-cpp-feature-test { n args } {
return
}
+proc dg-require-sysv-or-posix-semaphore { args } {
+ if { ![ check_v3_target_posix_or_sysv_semaphore ] } {
+ upvar dg-do-what dg-do-what
+ set dg-do-what [list [lindex ${dg-do-what} 0] "N" "P"]
+ return
+ }
+ return
+}
+
proc add_options_for_no_pch { flags } {
# Remove any inclusion of bits/stdc++.h from the options.
regsub -all -- "-include bits/stdc...h" $flags "" flags
diff --git a/libstdc++-v3/testsuite/lib/libstdc++.exp b/libstdc++-v3/testsuite/lib/libstdc++.exp
index cda231246cb0..a7b66fe9784b 100644
--- a/libstdc++-v3/testsuite/lib/libstdc++.exp
+++ b/libstdc++-v3/testsuite/lib/libstdc++.exp
@@ -835,6 +835,7 @@ proc v3-build_support { } {
# Build the support objects.
set source_files [list testsuite_abi.cc testsuite_allocator.cc \
testsuite_character.cc testsuite_hooks.cc \
+ testsuite_semaphore.cc \
io/verified_cmd_line_input.cc \
io/prog_bar.cc performance/time/elapsed_timer.cc ]
foreach f $source_files {
@@ -1440,6 +1441,16 @@ proc check_v3_target_nprocs { } {
}]
}
+# Return 1 if the POSIX Semaphores option or the XSI option is supported
+# for the current target, 0 otherwise.
+proc check_v3_target_posix_or_sysv_semaphore { } {
+ set name "posix_or_sysv_semaphore"
+ set inc "#include <unistd.h>"
+ set cond "_POSIX_SEMAPHORES > 0 || _XOPEN_UNIX > 0"
+ set result [v3_check_preprocessor_condition $name $cond $inc]
+ return $result
+}
+
# Return 1 if linking with -static-libstdc++ works, 0 otherwise.
proc check_v3_target_static_libstdcxx { } {
return [check_v3_target_prop_cached et_static_libstdcxx {
diff --git a/libstdc++-v3/testsuite/util/testsuite_hooks.cc b/libstdc++-v3/testsuite/util/testsuite_hooks.cc
index 946bd4a3847a..33ce7112701a 100644
--- a/libstdc++-v3/testsuite/util/testsuite_hooks.cc
+++ b/libstdc++-v3/testsuite/util/testsuite_hooks.cc
@@ -36,20 +36,6 @@
#include <locale>
#include <cxxabi.h>
-// If we have <sys/types.h>, <sys/ipc.h>, and <sys/sem.h>, then assume
-// that System V semaphores are available.
-#if defined(_GLIBCXX_HAVE_SYS_TYPES_H) \
- && defined(_GLIBCXX_HAVE_SYS_IPC_H) \
- && defined(_GLIBCXX_HAVE_SYS_SEM_H)
-#define _GLIBCXX_SYSV_SEM
-#endif
-
-#ifdef _GLIBCXX_SYSV_SEM
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/sem.h>
-#endif
-
namespace __gnu_test
{
#ifdef _GLIBCXX_RES_LIMITS
@@ -227,88 +213,6 @@ namespace __gnu_test
unsigned int destructor::_M_count = 0;
int copy_tracker::next_id_ = 0;
-#ifdef _GLIBCXX_SYSV_SEM
- // This union is not declared in system headers. Instead, it must
- // be defined by user programs.
- union semun
- {
- int val;
- struct semid_ds *buf;
- unsigned short *array;
- };
-#endif
-
- semaphore::semaphore()
- {
-#ifdef _GLIBCXX_SYSV_SEM
- // Remember the PID for the process that created the semaphore set
- // so that only one process will destroy the set.
- pid_ = getpid();
-
- // GLIBC does not define SEM_R and SEM_A.
-#ifndef SEM_R
-#define SEM_R 0400
-#endif
-
-#ifndef SEM_A
-#define SEM_A 0200
-#endif
-
- // Get a semaphore set with one semaphore.
- sem_set_ = semget(IPC_PRIVATE, 1, SEM_R | SEM_A);
- if (sem_set_ == -1)
- std::__throw_runtime_error("could not obtain semaphore set");
-
- // Initialize the semaphore.
- union semun val;
- val.val = 0;
- if (semctl(sem_set_, 0, SETVAL, val) == -1)
- std::__throw_runtime_error("could not initialize semaphore");
-#else
- // There are no semaphores on this system. We have no way to mark
- // a test as "unsupported" at runtime, so we just exit, pretending
- // that the test passed.
- exit(0);
-#endif
- }
-
- semaphore::~semaphore()
- {
-#ifdef _GLIBCXX_SYSV_SEM
- union semun val;
- val.val = 0; // Avoid uninitialized variable warning.
- // Destroy the semaphore set only in the process that created it.
- if (pid_ == getpid())
- semctl(sem_set_, 0, IPC_RMID, val);
-#endif
- }
-
- void
- semaphore::signal()
- {
-#ifdef _GLIBCXX_SYSV_SEM
- struct sembuf op[1] =
- {
- { 0, 1, 0 }
- };
- if (semop(sem_set_, op, 1) == -1)
- std::__throw_runtime_error("could not signal semaphore");
-#endif
- }
-
- void
- semaphore::wait()
- {
-#ifdef _GLIBCXX_SYSV_SEM
- struct sembuf op[1] =
- {
- { 0, -1, SEM_UNDO }
- };
- if (semop(sem_set_, op, 1) == -1)
- std::__throw_runtime_error("could not wait for semaphore");
-#endif
- }
-
// For use in 22_locale/time_get and time_put.
std::tm
test_tm(int sec, int min, int hour, int mday, int mon,
diff --git a/libstdc++-v3/testsuite/util/testsuite_hooks.h b/libstdc++-v3/testsuite/util/testsuite_hooks.h
index 49e8f0fe30bf..9d7bec18aa6f 100644
--- a/libstdc++-v3/testsuite/util/testsuite_hooks.h
+++ b/libstdc++-v3/testsuite/util/testsuite_hooks.h
@@ -335,30 +335,6 @@ namespace __gnu_test
}
};
- // A binary semaphore for use across multiple processes.
- class semaphore
- {
- public:
- // Creates a binary semaphore. The semaphore is initially in the
- // unsignaled state.
- semaphore();
-
- // Destroy the semaphore.
- ~semaphore();
-
- // Signal the semaphore. If there are processes blocked in
- // "wait", exactly one will be permitted to proceed.
- void signal();
-
- // Wait until the semaphore is signaled.
- void wait();
-
- private:
- int sem_set_;
-
- pid_t pid_;
- };
-
// For use in 22_locale/time_get and time_put.
std::tm test_tm(int sec, int min, int hour, int mday, int mon,
int year, int wday, int yday, int isdst);
diff --git a/libstdc++-v3/testsuite/util/testsuite_semaphore.cc b/libstdc++-v3/testsuite/util/testsuite_semaphore.cc
new file mode 100644
index 000000000000..208ec09ad289
--- /dev/null
+++ b/libstdc++-v3/testsuite/util/testsuite_semaphore.cc
@@ -0,0 +1,170 @@
+// -*- C++ -*-
+
+// Semaphore type for the C++ library testsuite.
+//
+// Copyright (C) 2005-2026 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+//
+
+#include "testsuite_semaphore.h"
+#include <bits/stdexcept_throw.h>
+
+#if defined(_GLIBCXX_HAVE_SYS_TYPES_H) \
+ && defined(_GLIBCXX_HAVE_SYS_IPC_H) \
+ && defined(_GLIBCXX_HAVE_SYS_SEM_H)
+// If we have <sys/types.h>, <sys/ipc.h>, and <sys/sem.h>, then assume
+// that System V semaphores are available.
+# include <sys/types.h>
+# include <sys/ipc.h>
+# include <sys/sem.h>
+# define _GLIBCXX_SYSV_SEM
+#elif defined(_POSIX_SEMAPHORES) && _POSIX_SEMAPHORES > 0
+# include <semaphore.h> // sem_init, sem_post etc.
+# include <sys/mman.h> // mmap, MAP_SHARED etc.
+# include <errno.h> // EINTR
+# include <fcntl.h> // open, O_RDWR
+# define _GLIBCXX_POSIX_SEM
+#else
+# include <stdlib.h> // abort
+#endif
+
+namespace __gnu_test
+{
+#ifdef _GLIBCXX_SYSV_SEM
+ // This union is not declared in system headers. Instead, it must
+ // be defined by user programs.
+ union semun
+ {
+ int val = 0;
+ struct semid_ds *buf;
+ unsigned short *array;
+ };
+
+ static void
+ destroy_semset(int set)
+ {
+ semctl(set, 0, IPC_RMID, semun{});
+ }
+#endif
+
+#ifdef _GLIBCXX_POSIX_SEM
+ // Create a new anonymous memory mapping that will be shared after fork().
+ static void*
+ mmap_anon(size_t len)
+ {
+ int flags = MAP_SHARED;
+ int fd = -1;
+#ifdef MAP_ANONYMOUS
+ flags |= MAP_ANONYMOUS;
+#elif defined MAP_ANON
+ flags |= MAP_ANON;
+#else
+ // Use the older idiom of mapping pages from /dev/zero
+ fd = open("/dev/zero", O_RDWR);
+ if (fd == -1)
+ std::__throw_runtime_error("could not open /dev/zero for mmap");
+#endif
+
+ void* p = mmap(nullptr, len, PROT_READ | PROT_WRITE, flags, fd, 0);
+ if (fd != -1)
+ close(fd);
+ if (p == MAP_FAILED)
+ std::__throw_runtime_error("could not create mmap mapping for semaphore");
+ return p;
+ }
+#endif
+
+ semaphore::semaphore()
+ {
+#ifdef _GLIBCXX_SYSV_SEM
+ // Get a System V semaphore set with one semaphore.
+ sem_set_ = semget(IPC_PRIVATE, 1, 0600);
+ if (sem_set_ == -1)
+ std::__throw_runtime_error("could not obtain semaphore set");
+
+ // Initialize the semaphore.
+ if (semctl(sem_set_, 0, SETVAL, semun{}) == -1)
+ {
+ destroy_semset(sem_set_);
+ std::__throw_runtime_error("could not initialize semaphore");
+ }
+#elif defined _GLIBCXX_POSIX_SEM
+ // Map some shared memory and initialize a POSIX semaphore there.
+ sem_ = mmap_anon(sizeof(sem_t));
+ if (sem_init((sem_t*)sem_, 1, 0))
+ {
+ munmap(sem_, sizeof(sem_t));
+ std::__throw_runtime_error("could not init semaphore in mmap mapping");
+ }
+#else
+ // There are no semaphores on this system so make the test FAIL at runtime.
+ // Use { dg-require-sysv-or-posix-semaphore "" } to make it UNSUPPORTED.
+ abort();
+#endif
+
+ // Remember the PID for the process that created the semaphore
+ // so that only one process will destroy it.
+ pid_ = getpid();
+ }
+
+ semaphore::~semaphore()
+ {
+ // Destroy the semaphore set only in the process that created it.
+#ifdef _GLIBCXX_SYSV_SEM
+ if (pid_ == getpid())
+ destroy_semset(sem_set_);
+#elif defined _GLIBCXX_POSIX_SEM
+ if (pid_ == getpid())
+ sem_destroy((sem_t*)sem_);
+ munmap(sem_, sizeof(sem_t));
+#endif
+ }
+
+ void
+ semaphore::signal()
+ {
+#ifdef _GLIBCXX_SYSV_SEM
+ struct sembuf op[1] = { };
+ op[0].sem_op = 1;
+ if (semop(sem_set_, op, 1) == -1)
+ std::__throw_runtime_error("could not signal semaphore");
+#elif defined _GLIBCXX_POSIX_SEM
+ if (sem_post((sem_t*)sem_))
+ std::__throw_runtime_error("could not signal semaphore");
+#endif
+ }
+
+ void
+ semaphore::wait()
+ {
+#ifdef _GLIBCXX_SYSV_SEM
+ struct sembuf op[1] = { };
+ op[0].sem_op = -1;
+ op[0].sem_flg = SEM_UNDO;
+ if (semop(sem_set_, op, 1) == -1)
+ std::__throw_runtime_error("could not wait for semaphore");
+#elif defined _GLIBCXX_POSIX_SEM
+ while (true)
+ {
+ if (sem_wait((sem_t*)sem_) == 0)
+ return;
+ if (errno != EINTR)
+ std::__throw_runtime_error("could not wait for semaphore");
+ }
+#endif
+ }
+} // namespace __gnu_test
diff --git a/libstdc++-v3/testsuite/util/testsuite_semaphore.h b/libstdc++-v3/testsuite/util/testsuite_semaphore.h
new file mode 100644
index 000000000000..1394dc8d180c
--- /dev/null
+++ b/libstdc++-v3/testsuite/util/testsuite_semaphore.h
@@ -0,0 +1,68 @@
+// -*- C++ -*-
+// Semaphore type for the C++ library testsuite.
+//
+// Copyright (C) 2005-2026 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+//
+// This 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+//
+
+#ifndef _GLIBCXX_TESTSUITE_SEMAPHORE_H
+#define _GLIBCXX_TESTSUITE_SEMAPHORE_H
+
+#include <bits/c++config.h>
+
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+namespace __gnu_test
+{
+ // A binary semaphore for use across multiple processes.
+ class semaphore
+ {
+ public:
+ // Creates a binary semaphore. The semaphore is initially in the
+ // unsignaled state.
+ semaphore();
+
+ // Destroy the semaphore.
+ ~semaphore();
+
+ // Signal the semaphore. If there are processes blocked in
+ // "wait", exactly one will be permitted to proceed.
+ void signal();
+
+ // Wait until the semaphore is signaled.
+ void wait();
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++11-extensions"
+ semaphore(const semaphore&) = delete;
+ semaphore& operator=(const semaphore&) = delete;
+#pragma GCC diagnostic pop
+
+ private:
+ union {
+ int sem_set_;
+ void* sem_;
+ };
+ pid_t pid_;
+ };
+
+} // namespace __gnu_test
+
+#endif // _GLIBCXX_TESTSUITE_SEMAPHORE_H
+
More information about the Libstdc++-cvs
mailing list