M68k C++ Exceptions working!
Rosimildo da Silva
rdasilva at connecttel.com
Wed Jan 12 05:13:18 UTC 2000
Charles-Antoine Gauthier wrote:
>
> Now all we need to figure out is whether exception handling is
> multithread safe and for which configurations, if any. I don't quite
> know what needs to be done to test this. A simple test would be to force
> a context switch from the exception handler to another higher priority
> thread that throws an exception, but that may not prove that the __throw
> functions and its friends are multithread safe.
>
> Any suggestions?
>
First of all, Congratulations. Now, the java VM porting is even closier.
:-).
What do you imagine, is making exceptions not thread safe ?
Some description here might to come up with some test cases.
I imagine that an exception carring some data, and it been propagated a
few levels( 3 or 4 )
could be a start for a test. I have put together a test case for that.
it seems to run fine on PC386.
In a thread safe environment, the data holded by each instance of the
exception class should be kept
consistent.
You might want to improve it, with a more agressive schedule.
Sorry, if you find errors. I just put this together in 10 minutes.
Rosimildo.
-------------- next part --------------
/*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <pthread.h>
#include <sched.h>
#include <rtems.h>
const int MAX_THREADS = 3;
const int MAX_BUFFER = 1024;
// to be fancy we could use posix keys to hold these values,
// but I am too lazy to do that...
struct DataPerThread
{
char match;
size_t current_seq;
rtems_id tid;
} dataPerThread[ MAX_THREADS ] = {
{ 'A', 0, 0 },
{ 'B', 100, 0 },
{ 'C', 1000, 0 }
};
// Class to hold the "exception data"
class MTExceptionChecker
{
public:
MTExceptionChecker( char match, size_t seq );
bool stillGood( char match, size_t seq ) const;
rtems_id get_tid() const { return tid; }
size_t get_seq() const { return seq_num; }
private:
rtems_id tid; // thread identifier
size_t seq_num; // unique sequencer number incremented per exception
char buffer[ MAX_BUFFER ]; // buffer to hold an unique parttern per thread.
};
// Ctor; Creates a instance of the exception class.
MTExceptionChecker::MTExceptionChecker( char match, size_t seq ) :
seq_num( seq )
{
rtems_task_ident( RTEMS_SELF, 0, &tid );
memset( buffer, match, sizeof( buffer ) );
}
// checks if the internal data of the exception still consistent
// with the ones used to generate it.
bool MTExceptionChecker::stillGood( char match, size_t seq ) const
{
rtems_id id;
rtems_task_ident( RTEMS_SELF, 0, &id );
if( ( id == tid ) && ( seq_num == seq ) )
{
for( int i=0; i < MAX_BUFFER; i++ )
{
if( buffer[ i ] != match )
return false;
// make this slow...
sched_yield();
}
return true;
}
return false;
}
// Raises one exception to the calling thread.
void funcBadBoy( int index )
{
dataPerThread[ index ].current_seq++;
throw MTExceptionChecker( dataPerThread[ index ].match,
dataPerThread[ index ].current_seq );
}
// Catch exception, and if it still consistent, re-raise it to the
// next try block...
void funcLevel( int level, int index )
{
try
{
funcBadBoy( index );
}
catch( const MTExceptionChecker & e )
{
if( !e.stillGood( dataPerThread[ index ].match,
dataPerThread[ index ].current_seq ) )
{
printf( "Level(%d, %d) failure: tid=%X, seq=%d\n",
level, index, e.get_tid(), e.get_seq() );
}
throw e;
}
catch( ... )
{
printf( "weird exception raised, level(%d,%d), tid =%X\n",
level, index, dataPerThread[ index ].tid );
assert( 0 );
}
}
void funcLevel0( int index )
{
try
{
funcLevel( 1, index );
}
catch( const MTExceptionChecker & e )
{
if( !e.stillGood( dataPerThread[ index ].match,
dataPerThread[ index ].current_seq ) )
{
printf( "Level(0, %d) failure: tid=%X, seq=%d\n",
index, e.get_tid(), e.get_seq() );
}
}
catch( ... )
{
printf( "Level(0, %d) - weird exception raised, tid =%X\n",
index, dataPerThread[ index ].tid );
assert( 0 );
}
}
void *thread_1( void *arg )
{
rtems_id id;
rtems_task_ident( RTEMS_SELF, 0, &id );
printf( "Thread 1 executing, id=%X\n", id );
dataPerThread[ 0 ].tid = id;
while( true )
{
funcLevel0( 0 );
// sched_yield();
}
return 0;
}
void *thread_2( void *arg )
{
rtems_id id;
rtems_task_ident( RTEMS_SELF, 0, &id );
printf( "Thread 2 executing, id=%X\n", id );
dataPerThread[ 1 ].tid = id;
while( true )
{
funcLevel0( 1 );
// sched_yield();
}
return 0;
}
void *thread_3( void *arg )
{
rtems_id id;
rtems_task_ident( RTEMS_SELF, 0, &id );
printf( "Thread 3 executing, id=%X\n", id );
dataPerThread[ 2 ].tid = id;
while( true )
{
funcLevel0( 2 );
// sched_yield();
}
return 0;
}
int rtems_main(int argc, char **argv)
{
int status;
pthread_t id1;
pthread_t id2;
pthread_t id3;
printf( "Exception Checker starting\n" );
status = pthread_create( &id1, NULL, thread_1, NULL );
printf( "Thread 1 - created. Status=%d\n", status );
status = pthread_create( &id2, NULL, thread_2, NULL );
printf( "Thread 2 - created. Status=%d\n", status );
status = pthread_create( &id3, NULL, thread_3, NULL );
printf( "Thread 3 - created. Status=%d\n", status );
size_t i = 0;
while( true )
{
sched_yield();
// Uncomment this if you wnat to force errors
#if 0
if( i == 10000 )
{
dataPerThread[ 0 ].current_seq++;
}
if( i == 20000 )
{
dataPerThread[ 1 ].current_seq++;
}
if( i == 30000 )
{
dataPerThread[ 2 ].current_seq++;
i = 0;
}
i++;
#endif
}
return 0;
}
More information about the users
mailing list