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