first commit
This commit is contained in:
362
extern/stdcxx/4.2.1/tests/diagnostics/19.exceptions.mt.cpp
vendored
Normal file
362
extern/stdcxx/4.2.1/tests/diagnostics/19.exceptions.mt.cpp
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* 19.exceptions.mt.cpp - test exercising the thread safety
|
||||
* of C++ Standard Library exception classes
|
||||
*
|
||||
* $Id: 19.exceptions.mt.cpp 425530 2006-07-25 21:39:50Z sebor $
|
||||
*
|
||||
***************************************************************************
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed
|
||||
* with this work for additional information regarding copyright
|
||||
* ownership. The ASF licenses this file to you under the Apache
|
||||
* License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*
|
||||
* Copyright 2005-2006 Rogue Wave Software.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <stdexcept> // for exceptions
|
||||
#include <string> // for string
|
||||
|
||||
#include <cassert> // for assert
|
||||
#include <cstdio> // for printf()
|
||||
|
||||
#include <cmdopt.h>
|
||||
#include <driver.h>
|
||||
#include <rw_alarm.h> // for rw_alarm()
|
||||
#include <rw_thread.h> // for rw_thread_pool()
|
||||
#include <valcmp.h>
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef NTHREADS
|
||||
# ifndef _RWSTD_REENTRANT
|
||||
# define MAX_THREADS 0
|
||||
# define NTHREADS 0
|
||||
# else
|
||||
# define MAX_THREADS 32
|
||||
# define NTHREADS 4
|
||||
# endif // _RWSTD_REENTRANT
|
||||
#endif // NTHREADS
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
/* extern */ int rw_opt_nloops = 256 * 1024;
|
||||
/* extern */ int rw_opt_nthreads = NTHREADS;
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
volatile int alarm_expired;
|
||||
|
||||
extern "C" {
|
||||
|
||||
static void handle_alarm (int)
|
||||
{
|
||||
alarm_expired = 1;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
||||
// string to intialize exceptions from
|
||||
static const char what_buf [] = {
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789ABCDEF"
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
exception_tag,
|
||||
logic_error_tag,
|
||||
domain_error_tag,
|
||||
invalid_argument_tag,
|
||||
length_error_tag,
|
||||
out_of_range_tag,
|
||||
runtime_error_tag,
|
||||
range_error_tag,
|
||||
overflow_error_tag,
|
||||
underflow_error_tag,
|
||||
Derived_tag
|
||||
};
|
||||
|
||||
|
||||
struct DerivedException: std::invalid_argument
|
||||
{
|
||||
DerivedException (const char *str)
|
||||
: std::invalid_argument (str) { }
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
throw_exception (unsigned which, const char *what)
|
||||
{
|
||||
switch (which) {
|
||||
case exception_tag: throw std::exception ();
|
||||
case logic_error_tag: throw std::logic_error (what);
|
||||
case domain_error_tag: throw std::domain_error (what);
|
||||
case invalid_argument_tag: throw std::invalid_argument (what);
|
||||
case length_error_tag: throw std::length_error (what);
|
||||
case out_of_range_tag: throw std::out_of_range (what);
|
||||
case runtime_error_tag: throw std::runtime_error (what);
|
||||
case range_error_tag: throw std::range_error (what);
|
||||
case overflow_error_tag: throw std::overflow_error (what);
|
||||
case underflow_error_tag: throw std::underflow_error (what);
|
||||
case Derived_tag: throw DerivedException (what);
|
||||
|
||||
default: _RWSTD_ASSERT (!"logic error: bad exception tag");
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
extern "C" void*
|
||||
test_single_exception (void *arg)
|
||||
{
|
||||
const rw_thread_t* const tid = (rw_thread_t*)arg;
|
||||
|
||||
std::printf ("thread procedure %ld starting...\n", tid->threadno);
|
||||
|
||||
for (unsigned i = 0; i < unsigned (rw_opt_nloops); ++i) {
|
||||
|
||||
if (alarm_expired)
|
||||
break;
|
||||
|
||||
const std::size_t what_len = std::size_t (i % 1024);
|
||||
|
||||
const char* const what = what_buf + sizeof what_buf - what_len - 1;
|
||||
|
||||
const unsigned thrown = i % 11;
|
||||
|
||||
unsigned caught = _RWSTD_UINT_MAX;
|
||||
|
||||
try {
|
||||
// construct and throw an exception object of one
|
||||
// of the predefined standard exception classes
|
||||
// initialized with a distinct what string
|
||||
throw_exception (thrown, what);
|
||||
}
|
||||
catch (DerivedException ex) {
|
||||
// catch the exception object by value and verify
|
||||
// that the pointer returned by what() compares
|
||||
// equal to the string the thrown object was
|
||||
// constructed with
|
||||
caught = Derived_tag;
|
||||
assert (0 == rw_strncmp (ex.what (), what));
|
||||
}
|
||||
catch (std::domain_error ex) {
|
||||
caught = domain_error_tag;
|
||||
assert (0 == rw_strncmp (ex.what (), what));
|
||||
}
|
||||
catch (std::invalid_argument ex) {
|
||||
caught = invalid_argument_tag;
|
||||
assert (0 == rw_strncmp (ex.what (), what));
|
||||
}
|
||||
catch (std::length_error ex) {
|
||||
caught = length_error_tag;
|
||||
assert (0 == rw_strncmp (ex.what (), what));
|
||||
}
|
||||
catch (std::out_of_range ex) {
|
||||
caught = out_of_range_tag;
|
||||
assert (0 == rw_strncmp (ex.what (), what));
|
||||
}
|
||||
catch (std::range_error ex) {
|
||||
caught = range_error_tag;
|
||||
assert (0 == rw_strncmp (ex.what (), what));
|
||||
}
|
||||
catch (std::overflow_error ex) {
|
||||
caught = overflow_error_tag;
|
||||
assert (0 == rw_strncmp (ex.what (), what));
|
||||
}
|
||||
catch (std::underflow_error ex) {
|
||||
caught = underflow_error_tag;
|
||||
assert (0 == rw_strncmp (ex.what (), what));
|
||||
}
|
||||
catch (std::logic_error ex) {
|
||||
caught = logic_error_tag;
|
||||
assert (0 == rw_strncmp (ex.what (), what));
|
||||
}
|
||||
catch (std::runtime_error ex) {
|
||||
caught = runtime_error_tag;
|
||||
assert (0 == rw_strncmp (ex.what (), what));
|
||||
}
|
||||
catch (std::exception ex) {
|
||||
caught = exception_tag;
|
||||
rw_strncmp (ex.what (), what);
|
||||
}
|
||||
|
||||
// verify that an object of the thrown type was caught
|
||||
assert (caught == thrown);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static void
|
||||
test_multi (unsigned i, unsigned nactive)
|
||||
{
|
||||
const std::size_t what_len = (i + nactive) % sizeof what_buf;
|
||||
|
||||
const char* const what = what_buf + sizeof what_buf - what_len - 1;
|
||||
|
||||
const unsigned thrown = (i + nactive) % 10 + 1;
|
||||
|
||||
try {
|
||||
// construct and throw an exception object of a distinct type
|
||||
// with a distinct what string at each level of recursion
|
||||
throw_exception (thrown, what);
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
|
||||
// recursively throw another exception while the caught
|
||||
// exception object is still active
|
||||
if (nactive)
|
||||
test_multi (i, nactive - 1);
|
||||
|
||||
// verify that the caught object's what string matches
|
||||
// the string the object was originally constructed with
|
||||
assert (0 == rw_strncmp (ex.what (), what));
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void*
|
||||
test_multi_exceptions (void *arg)
|
||||
{
|
||||
const rw_thread_t* const tid = (rw_thread_t*)arg;
|
||||
|
||||
std::printf ("thread procedure %ld starting...\n", tid->threadno);
|
||||
|
||||
for (unsigned i = 0; i < unsigned (rw_opt_nloops); ++i) {
|
||||
|
||||
if (alarm_expired)
|
||||
break;
|
||||
|
||||
// exercise up to 4 simultaneously active exceptions
|
||||
test_multi (i, i % 4);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
static int
|
||||
run_test (int, char**)
|
||||
{
|
||||
// get the current alarm (if any) set for the test
|
||||
// on the command line without resetting it
|
||||
const unsigned max_sec = rw_alarm (0, rw_sig_hold);
|
||||
|
||||
// compute a shorter timeout for each of the two subtests
|
||||
const unsigned nsec = 3 < max_sec ? max_sec / 2 : 0;
|
||||
|
||||
rw_info (0, 0, 0,
|
||||
"single active exception per thread"
|
||||
"%{?}; timeout in %u seconds%{;}",
|
||||
0 != max_sec, nsec ? nsec : max_sec);
|
||||
|
||||
// set a shorter alarm if possible
|
||||
if (nsec) {
|
||||
alarm_expired = 0;
|
||||
rw_alarm (nsec, handle_alarm);
|
||||
}
|
||||
|
||||
const std::size_t nthreads = std::size_t (rw_opt_nthreads);
|
||||
|
||||
#if 0 < NTHREADS
|
||||
|
||||
rw_fatal (0 == rw_thread_pool (0, nthreads, 0, test_single_exception, 0),
|
||||
0, __LINE__, "rw_thread_pool() failed");
|
||||
|
||||
#else // if !(0 < NTHREADS)
|
||||
|
||||
rw_thread_t tid = rw_thread_t ();
|
||||
|
||||
test_single_exception (&tid);
|
||||
|
||||
#endif // NTHREADS
|
||||
|
||||
rw_info (0, 0, 0,
|
||||
"multiple active exceptions per thread"
|
||||
"%{?}; timeout in %u seconds%{;}",
|
||||
0 != max_sec, nsec ? nsec : max_sec);
|
||||
|
||||
// set another shorter alarm if possible
|
||||
if (nsec) {
|
||||
alarm_expired = 0;
|
||||
rw_alarm (nsec, handle_alarm);
|
||||
}
|
||||
|
||||
#if 0 < NTHREADS
|
||||
|
||||
rw_fatal (0 == rw_thread_pool (0, nthreads, 0, test_multi_exceptions, 0),
|
||||
0, __LINE__, "rw_thread_pool() failed");
|
||||
|
||||
#else // if !(0 < NTHREADS)
|
||||
|
||||
test_multi_exceptions (&tid);
|
||||
|
||||
#endif // NTHREADS
|
||||
|
||||
// restore the original alarm to go off approximately
|
||||
// when the original alar would have if it hadn't been
|
||||
// replaced above
|
||||
if (nsec)
|
||||
rw_alarm (2 * nsec, rw_sig_restore);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
return rw_test (argc, argv, __FILE__,
|
||||
"lib.std.exceptions",
|
||||
"thread safety", run_test,
|
||||
"|-nloops#0 " // must be non-negative
|
||||
"|-nthreads#0-*", // must be in [0, MAX_THREADS]
|
||||
&rw_opt_nloops,
|
||||
int (MAX_THREADS),
|
||||
&rw_opt_nthreads);
|
||||
}
|
||||
Reference in New Issue
Block a user