This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Avoiding sleep in V3 testsuite
- From: Mark Mitchell <mark at codesourcery dot com>
- To: libstdc++ at gcc dot gnu dot org
- Date: Mon, 27 Dec 2004 14:36:13 -0800
- Subject: Avoiding sleep in V3 testsuite
- Reply-to: mark at codesourcery dot com
The use of "sleep" in several tests in the V3 testsuite is very
sloppy. First, sleep is being used as a way to achieve inter-process
synchronization, but that is not 100% reliable. Second, and more
important in practice, the use of sleep makes running the tests take
longer than other means of syncrhonization -- and means that tests
take just as long on fast machines as on slow ones.
Furthermore, some of the uses of sleep don't make sense to me. For
example, I've been looking 27_io/basic_filebuf/open/char/9507.cc,
which is:
try_mkfifo(name, S_IRWXU);
if (!fork())
{
std::filebuf fbuf;
fbuf.open(name, std::ios_base::in);
fbuf.sgetc();
sleep(2);
fbuf.close();
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);
VERIFY( !fbuf.is_open() );
Since the semantics of FIFOs are that the child's open-for-read will
block until the parent's open-for-write occurs, the sleep call in the
parent is just a wasted second.
Here's a sketch of how I'm proposing to fix this. (I'll figure out a
better way to define _GLIBCXX_SYSV_SEM.) Any objections?
(Actually, come to think of it, I can't see any reason that we need
synchronization at all in this test -- except maybe that we're using
"exit" -- rather than "_exit" -- to leave the child, which seems
confused in and of itself. Since this test uses fifos, we can safely
assume that _exit exists. So, I guess to fix 9507.cc, in particular,
it would suffice just to remove the sleep calls.)
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
Index: testsuite_hooks.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/testsuite_hooks.cc,v
retrieving revision 1.22
diff -c -5 -p -r1.22 testsuite_hooks.cc
*** testsuite_hooks.cc 13 May 2004 16:29:39 -0000 1.22
--- testsuite_hooks.cc 27 Dec 2004 22:13:40 -0000
***************
*** 40,49 ****
--- 40,57 ----
#include <stdexcept>
#include <clocale>
#include <locale>
#include <cxxabi.h>
+ #define _GLIBCXX_SYSV_SEM 1
+
+ #ifdef _GLIBCXX_SYSV_SEM
+ #include <sys/types.h>
+ #include <sys/ipc.h>
+ #include <sys/sem.h>
+ #endif
+
namespace __gnu_test
{
#ifdef _GLIBCXX_RES_LIMITS
void
set_memory_limits(float size)
*************** namespace __gnu_test
*** 246,255 ****
--- 254,335 ----
unsigned int copy_constructor::throw_on_ = 0;
unsigned int assignment_operator::count_ = 0;
unsigned int assignment_operator::throw_on_ = 0;
unsigned int destructor::_M_count = 0;
int copy_tracker::next_id_ = 0;
+
+ union semun
+ {
+ int val;
+ struct semid_ds *buf;
+ unsigned short *array;
+ };
+
+ 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
+ // No semaphores.
+ 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
{
// Member specializations for the existing facet classes.
Index: testsuite_hooks.h
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/testsuite_hooks.h,v
retrieving revision 1.30
diff -c -5 -p -r1.30 testsuite_hooks.h
*** testsuite_hooks.h 2 Nov 2004 19:00:17 -0000 1.30
--- testsuite_hooks.h 27 Dec 2004 22:13:40 -0000
*************** namespace __gnu_test
*** 378,387 ****
--- 378,411 ----
const_iterator it = v.begin();
const_iterator end = v.end();
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
{
template<class _CharT>
Index: 27_io/basic_filebuf/open/char/9507.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/27_io/basic_filebuf/open/char/9507.cc,v
retrieving revision 1.6
diff -c -5 -p -r1.6 9507.cc
*** 27_io/basic_filebuf/open/char/9507.cc 6 Feb 2004 11:45:23 -0000 1.6
--- 27_io/basic_filebuf/open/char/9507.cc 27 Dec 2004 22:13:40 -0000
***************
*** 35,66 ****
void test_06()
{
using namespace __gnu_test;
bool test __attribute__((unused)) = true;
const char* name = "tmp_fifo2";
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);
fbuf.close();
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);
VERIFY( !fbuf.is_open() );
VERIFY( r == NULL );
}
int
--- 35,67 ----
void test_06()
{
using namespace __gnu_test;
bool test __attribute__((unused)) = true;
const char* name = "tmp_fifo2";
+ semaphore s1;
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();
! s1.wait();
fbuf.close();
exit(0);
}
std::filebuf fbuf;
std::filebuf* r = fbuf.open(name,
std::ios_base::in
| std::ios_base::out
| std::ios_base::ate);
+ s1.signal();
VERIFY( !fbuf.is_open() );
VERIFY( r == NULL );
}
int