From 8f1032c16a6e30d789be20320b1f8c443833fadd Mon Sep 17 00:00:00 2001
From: Mark Mitchell <mark@codesourcery.com>
Date: Mon, 3 Jan 2005 21:31:39 +0000
Subject: [PATCH] configure.ac: Check for sys/ipc.h and sys/sem.h.

	* configure.ac: Check for sys/ipc.h and sys/sem.h.
	* config.h.in: Regenerated.
	* configure: Likewise.
	* testsuite/testsuite_hooks.cc (_GLIBCXX_SYSV_SEM): Conditionally
	define.
	(sys/types.h): Include.
	(sys/ipc.h): Likewise.
	(sys/sem.h): Likewise.
	(__gnu_test::semun): New type.
	(__gnu_test::semaphore::sempaphore): New function.
	(__gnu_test::semaphore::~semaphore): Likewise.
	(__gnu_test::semaphore::wait): Likewise.
	(__gnu_test::semaphore::signal): Likewise.
	* testsuite/testsuite_hooks.h (__gnu_test::semaphore): New class.
	* testsuite/27_io/basic_filebuf/close/char/4789.cc: Use
	semaphores, not sleep.
	* 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/char/13582-2.cc: Likewise.
	* testsuite/27_io/basic_filebuf/imbue/wchar_t/14975-2.cc:
	Likewise.
	* testsuite/27_io/basic_filebuf/open/char/9507.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/9961-1.cc: Likewise.

From-SVN: r92865
---
 libstdc++-v3/ChangeLog                        | 30 ++++++
 libstdc++-v3/config.h.in                      |  6 ++
 libstdc++-v3/configure                        |  4 +-
 libstdc++-v3/configure.ac                     |  2 +-
 .../27_io/basic_filebuf/close/char/4879.cc    |  8 +-
 .../27_io/basic_filebuf/close/char/9964.cc    |  9 +-
 .../27_io/basic_filebuf/imbue/char/13171-2.cc |  7 +-
 .../27_io/basic_filebuf/imbue/char/13582-2.cc |  4 +-
 .../basic_filebuf/imbue/wchar_t/14975-2.cc    | 14 +--
 .../27_io/basic_filebuf/open/char/9507.cc     |  9 +-
 .../basic_filebuf/underflow/char/10097.cc     |  5 +-
 .../testsuite/27_io/objects/char/7.cc         |  8 +-
 .../testsuite/27_io/objects/char/9661-1.cc    |  8 +-
 .../testsuite/27_io/objects/wchar_t/7.cc      |  6 +-
 .../testsuite/27_io/objects/wchar_t/9661-1.cc | 10 +-
 libstdc++-v3/testsuite/testsuite_hooks.cc     | 92 +++++++++++++++++++
 libstdc++-v3/testsuite/testsuite_hooks.h      | 24 +++++
 17 files changed, 208 insertions(+), 38 deletions(-)

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 1c522145fb31..77a917b78ed7 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,33 @@
+2005-01-03  Mark Mitchell  <mark@codesourcery.com>
+
+	* configure.ac: Check for sys/ipc.h and sys/sem.h. 
+	* config.h.in: Regenerated.
+	* configure: Likewise.
+	* testsuite/testsuite_hooks.cc (_GLIBCXX_SYSV_SEM): Conditionally
+	define.
+	(sys/types.h): Include.
+	(sys/ipc.h): Likewise.
+	(sys/sem.h): Likewise.
+	(__gnu_test::semun): New type.
+	(__gnu_test::semaphore::sempaphore): New function.
+	(__gnu_test::semaphore::~semaphore): Likewise.
+	(__gnu_test::semaphore::wait): Likewise.
+	(__gnu_test::semaphore::signal): Likewise.
+	* testsuite/testsuite_hooks.h (__gnu_test::semaphore): New class.
+	* testsuite/27_io/basic_filebuf/close/char/4789.cc: Use
+	semaphores, not sleep.
+	* 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/char/13582-2.cc: Likewise.
+	* testsuite/27_io/basic_filebuf/imbue/wchar_t/14975-2.cc:
+	Likewise.
+	* testsuite/27_io/basic_filebuf/open/char/9507.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/9961-1.cc: Likewise.
+
 2005-01-03  Paolo Carlini  <pcarlini@suse.de>
 
 	* include/bits/istream.tcc (ignore(streamsize), ignore(streamsize,
diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in
index acb7d732abc2..86c110648726 100644
--- a/libstdc++-v3/config.h.in
+++ b/libstdc++-v3/config.h.in
@@ -506,6 +506,9 @@
 /* Define to 1 if you have the <sys/ioctl.h> header file. */
 #undef HAVE_SYS_IOCTL_H
 
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+#undef HAVE_SYS_IPC_H
+
 /* Define to 1 if you have the <sys/isa_defs.h> header file. */
 #undef HAVE_SYS_ISA_DEFS_H
 
@@ -518,6 +521,9 @@
 /* Define to 1 if you have the <sys/resource.h> header file. */
 #undef HAVE_SYS_RESOURCE_H
 
+/* Define to 1 if you have the <sys/sem.h> header file. */
+#undef HAVE_SYS_SEM_H
+
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #undef HAVE_SYS_STAT_H
 
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index 0024e82faa2e..77c8d2c4fa05 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -7927,9 +7927,11 @@ if $GLIBCXX_IS_NATIVE; then
 
 
 
+
+
 for ac_header in nan.h ieeefp.h endian.h sys/isa_defs.h machine/endian.h \
   machine/param.h sys/machine.h fp.h locale.h float.h inttypes.h gconv.h \
-  sys/types.h
+  sys/types.h sys/ipc.h sys/sem.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
 if eval "test \"\${$as_ac_Header+set}\" = set"; then
diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index f5e306acc262..5d0a54f9c4cf 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -117,7 +117,7 @@ if $GLIBCXX_IS_NATIVE; then
   # Check for available headers.
   AC_CHECK_HEADERS([nan.h ieeefp.h endian.h sys/isa_defs.h machine/endian.h \
   machine/param.h sys/machine.h fp.h locale.h float.h inttypes.h gconv.h \
-  sys/types.h])
+  sys/types.h sys/ipc.h sys/sem.h])
 
   GLIBCXX_CHECK_COMPILER_FEATURES
   GLIBCXX_CHECK_LINKER_FEATURES
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 bd585443be1b..1d251174099a 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
@@ -41,6 +41,8 @@ test_04()
 
   bool test __attribute__((unused)) = true;
   const char* name = "tmp_fifo1";
+  semaphore s1, s2;
+
   signal(SIGPIPE, SIG_IGN);
   
   unlink(name);
@@ -60,13 +62,15 @@ test_04()
   else if (fval == 0)
     {
       std::ifstream ifs(name);
-      sleep(1);
+      s1.wait ();
       ifs.close();
+      s2.signal ();
       exit(0);
     }
 
   std::ofstream ofs(name);
-  sleep(2);
+  s1.signal ();
+  s2.wait ();
   ofs.put('t');
 
   /*
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 bd74fad34bf0..57f6de9c5ee6 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
@@ -37,6 +37,7 @@ void test_07()
   using namespace std;
   using namespace __gnu_test;
   bool test __attribute__((unused)) = true;
+  semaphore s1, s2;
 
   const char* name = "tmp_fifo3";
 
@@ -52,18 +53,18 @@ void test_07()
     {
       filebuf fbin;
       fbin.open(name, ios_base::in);
-      sleep(2);
+      s1.wait ();
       fbin.close();
+      s2.signal ();
       exit(0);
     }
   
   filebuf fb;
-  sleep(1);
   filebuf* ret = fb.open(name, ios_base::in | ios_base::out);
   VERIFY( ret != NULL );
   VERIFY( fb.is_open() );
-
-  sleep(3);
+  s1.signal ();
+  s2.wait ();
   fb.sputc('a');
 
   ret = fb.close();
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 367017a3bfef..ec2d321bbf5d 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
@@ -39,6 +39,7 @@ void test01()
   const char* name = "tmp_fifo_13171-2";
   unlink(name);
   try_mkfifo(name, S_IRWXU);
+  semaphore s1, s2;
   
   int child = fork();
   if (child == 0)
@@ -47,7 +48,8 @@ void test01()
       fb.open(name, ios_base::out);
       fb.sputc('S');
       fb.pubsync();
-      sleep(2);
+      s1.signal ();
+      s2.wait ();
       fb.close();
       exit(0);
     }
@@ -55,12 +57,13 @@ void test01()
   filebuf fb;
   fb.pubimbue(loc_fr);
   fb.open(name, ios_base::in);
-  sleep(1);
+  s1.wait ();
   VERIFY( fb.is_open() );
   fb.pubimbue(loc_en);
   filebuf::int_type c = fb.sgetc();
   fb.close();
   VERIFY( c == 'S' );
+  s2.signal ();
 }
 
 int main()
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/char/13582-2.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/char/13582-2.cc
index 316b9f59735d..07f6529de4aa 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/char/13582-2.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/imbue/char/13582-2.cc
@@ -42,7 +42,7 @@ void test01()
   const char* name = "tmp_fifo_13582-2";
   unlink(name);
   try_mkfifo(name, S_IRWXU);
-  
+
   int child = fork();
   if (child == 0)
     {
@@ -50,14 +50,12 @@ void test01()
       fbout.open(name, ios_base::out);
       fbout.sputn("12345", 5);
       fbout.pubsync();
-      sleep(2);
       fbout.close();
       exit(0);
     }
 
   filebuf fbin;
   fbin.open(name, ios_base::in);
-  sleep(1);
   filebuf::int_type n = fbin.sbumpc();
   VERIFY( n == '1' );
   fbin.pubimbue(loc_en);
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 8789b9aa4d8e..a87bf8ffd60f 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
@@ -42,26 +42,28 @@ void test01()
 
   unlink(name);  
   try_mkfifo(name, S_IRWXU);
-  
+  semaphore s1;
+
   int child = fork();
   VERIFY( child != -1 );
 
   if (child == 0)
     {
-      filebuf fbin;
-      fbin.open(name, ios_base::in);
-      sleep(2);
+      {
+	filebuf fbin;
+	fbin.open(name, ios_base::in);
+      }
+      s1.signal ();
       exit(0);
     }
   
   wfilebuf fb;
   fb.pubimbue(loc_us);
-  sleep(1);
   wfilebuf* ret = fb.open(name, ios_base::out);
   VERIFY( ret != NULL );
   VERIFY( fb.is_open() );
 
-  sleep(3);
+  s1.wait ();
 
   try
     {
diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/open/char/9507.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/open/char/9507.cc
index 761f9e585f0a..7c5aeab5d87e 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/open/char/9507.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/open/char/9507.cc
@@ -37,30 +37,33 @@ void test_06()
   using namespace __gnu_test;
   bool test __attribute__((unused)) = true;
   const char* name = "tmp_fifo2";
+  semaphore s1, s2;
 
   signal(SIGPIPE, SIG_IGN);
 
   unlink(name);
   try_mkfifo(name, S_IRWXU);
-	
+  
   if (!fork())
     {
       std::filebuf fbuf;
       fbuf.open(name, std::ios_base::in);
       fbuf.sgetc();
-      sleep(2);
+      s1.signal ();
       fbuf.close();
+      s2.wait ();
       exit(0);
     }
 
   std::filebuf fbuf;
-  sleep(1);
   std::filebuf* r = fbuf.open(name,
 			      std::ios_base::in 
 			      | std::ios_base::out
 			      | std::ios_base::ate);
+  s1.wait ();
   VERIFY( !fbuf.is_open() );
   VERIFY( r == NULL );
+  s2.signal ();
 }
 
 int
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 aaaf1d2d7b64..3bbff078f8e9 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
@@ -58,6 +58,7 @@ void test16()
       VERIFY( false );
     }
   
+  semaphore s1;
   int fval = fork();
   if (fval == -1)
     {
@@ -71,14 +72,13 @@ void test16()
       VERIFY ( fbout.is_open() );
       fbout.sputn("0123456789", 10);
       fbout.pubsync();
-      sleep(2);
+      s1.wait ();
       fbout.close();
       exit(0);
     }
 
   UnderBuf fb;
   fb.open(name, ios_base::in);
-  sleep(1);
   
   fb.sgetc();
   streamsize n = fb.pub_showmanyc();
@@ -94,6 +94,7 @@ void test16()
     }
 
   fb.close();
+  s1.signal ();
 }
 
 int main() 
diff --git a/libstdc++-v3/testsuite/27_io/objects/char/7.cc b/libstdc++-v3/testsuite/27_io/objects/char/7.cc
index 13574e67c92f..609415882b6b 100644
--- a/libstdc++-v3/testsuite/27_io/objects/char/7.cc
+++ b/libstdc++-v3/testsuite/27_io/objects/char/7.cc
@@ -42,26 +42,26 @@ void test07()
 
   unlink(name);  
   try_mkfifo(name, S_IRWXU);
-  
+  semaphore s1;
+
   int child = fork();
   VERIFY( child != -1 );
 
   if (child == 0)
     {
       filebuf fbout;
-      sleep(1);
       fbout.open(name, ios_base::in|ios_base::out);
+      s1.wait ();
       VERIFY ( fbout.is_open() );
       cout.rdbuf(&fbout);
       fbout.sputc('a');
-      sleep(2);
       // NB: fbout is *not* destroyed here!
       exit(0);
     }
   
   filebuf fbin;
   fbin.open(name, ios_base::in);
-  sleep(2);
+  s1.signal ();
   filebuf::int_type c = fbin.sbumpc();
   VERIFY( c != filebuf::traits_type::eof() );
   VERIFY( c == filebuf::traits_type::to_int_type('a') );
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 942cb0943896..9530328afc9a 100644
--- a/libstdc++-v3/testsuite/27_io/objects/char/9661-1.cc
+++ b/libstdc++-v3/testsuite/27_io/objects/char/9661-1.cc
@@ -43,24 +43,25 @@ void test01()
 
   unlink(name);  
   try_mkfifo(name, S_IRWXU);
+  semaphore s1, s2;
   
   int child = fork();
   VERIFY( child != -1 );
 
   if (child == 0)
     {
-      sleep(1);
       FILE* file = fopen(name, "r+");
       VERIFY (file != NULL);
       fputs("Whatever\n", file);
       fflush(file);
-      sleep(2);
+      s1.signal ();
+      s2.wait ();
       fclose(file);
       exit(0);
     }
   
   freopen(name, "r", stdin);
-  sleep(2);
+  s1.wait ();
 
   int c1 = fgetc(stdin);
   VERIFY( c1 != EOF );
@@ -78,6 +79,7 @@ void test01()
   int c5 = cin.rdbuf()->sgetc();
   VERIFY( c5 != EOF );
   VERIFY( c5 == c4 );
+  s2.signal ();
 }
 
 int main()
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 a1c97670038a..ee7aac6ec166 100644
--- a/libstdc++-v3/testsuite/27_io/objects/wchar_t/7.cc
+++ b/libstdc++-v3/testsuite/27_io/objects/wchar_t/7.cc
@@ -42,6 +42,7 @@ void test07()
 
   unlink(name);  
   try_mkfifo(name, S_IRWXU);
+  semaphore s1;
   
   int child = fork();
   VERIFY( child != -1 );
@@ -49,18 +50,17 @@ void test07()
   if (child == 0)
     {
       wfilebuf fbout;
-      sleep(1);
       fbout.open(name, ios_base::out);
+      s1.wait();
       wcout.rdbuf(&fbout);
       fbout.sputc(L'a');
-      sleep(2);
       // NB: fbout is *not* destroyed here!
       exit(0);
     }
   
   wfilebuf fbin;
   fbin.open(name, ios_base::in);
-  sleep(2);
+  s1.signal ();
   wfilebuf::int_type c = fbin.sbumpc();
   VERIFY( c != wfilebuf::traits_type::eof() );
   VERIFY( c == wfilebuf::traits_type::to_int_type(L'a') );
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 38b832049b87..f944ef2524aa 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
@@ -43,23 +43,24 @@ void test01()
 
   unlink(name);  
   try_mkfifo(name, S_IRWXU);
-  
+  semaphore s1, s2;
+
   int child = fork();
   VERIFY( child != -1 );
 
   if (child == 0)
     {
-      sleep(1);
       FILE* file = fopen(name, "w");
       fputs("Whatever\n", file);
       fflush(file);
-      sleep(2);
+      s1.signal ();
+      s2.wait ();
       fclose(file);
       exit(0);
     }
   
   freopen(name, "r", stdin);
-  sleep(2);
+  s1.wait ();
 
   wint_t c1 = fgetwc(stdin);
   VERIFY( c1 != WEOF );
@@ -77,6 +78,7 @@ void test01()
   wint_t c5 = wcin.rdbuf()->sgetc();
   VERIFY( c5 != WEOF );
   VERIFY( c5 == c4 );
+  s2.signal ();
 }
 
 int main()
diff --git a/libstdc++-v3/testsuite/testsuite_hooks.cc b/libstdc++-v3/testsuite/testsuite_hooks.cc
index f503979b65d8..e4cf7fdd7a70 100644
--- a/libstdc++-v3/testsuite/testsuite_hooks.cc
+++ b/libstdc++-v3/testsuite/testsuite_hooks.cc
@@ -42,6 +42,20 @@
 #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
@@ -252,6 +266,84 @@ namespace __gnu_test
   unsigned int assignment_operator::throw_on_ = 0;
   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
+    // Remeber 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)
+      throw std::runtime_error ("could not obtain semaphore set");
+
+    // Initialize the semaphore.
+    union semun val;
+    val.val = 0;
+    if (semctl (sem_set_, 0, SETVAL, val) == -1)
+      throw std::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;
+    // 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)
+      throw std::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)
+      throw std::runtime_error ("could not wait for semaphore");
+#endif    
+  }
 }; // namespace __gnu_test
 
 namespace std
diff --git a/libstdc++-v3/testsuite/testsuite_hooks.h b/libstdc++-v3/testsuite/testsuite_hooks.h
index 4b526e9b19f0..79495fbd357c 100644
--- a/libstdc++-v3/testsuite/testsuite_hooks.h
+++ b/libstdc++-v3/testsuite/testsuite_hooks.h
@@ -380,6 +380,30 @@ namespace __gnu_test
 	return it == end ? v.end() : it;
       }
     };
+
+  // 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_;
+  };
 } // namespace __gnu_test
 
 namespace std
-- 
GitLab