saturnng/libChf/tests/test04.c

294 lines
7.3 KiB
C

/* $Id: test04.c,v 2.1 2000/05/29 13:10:38 cibrario Rel $
Chf test program.
General condition handling - single and multithreaded
$Log: test04.c,v $
Revision 2.1 2000/05/29 13:10:38 cibrario
*** empty log message ***
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <setjmp.h>
#ifdef _REENTRANT
# include <pthread.h>
#endif
#define CHF_MODULE_ID 255
#define CHF_EXTENDED_INFO
#include "Chf.h"
struct tdata_s {
const ChfDescriptor *d, *e;
int phase;
};
ChfAction h1( const ChfDescriptor* c, const ChfState s, ChfPointer p )
{
struct tdata_s* tdata_p = ( struct tdata_s* )p;
ChfAction action;
if ( c != tdata_p->e || ChfGetNextDescriptor( c ) != tdata_p->d ) {
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
}
else
action = CHF_CONTINUE;
return action;
}
ChfAction h2( const ChfDescriptor* c, const ChfState s, ChfPointer p )
{
struct tdata_s* tdata_p = ( struct tdata_s* )p;
ChfAction action;
switch ( s ) {
case CHF_SIGNALING:
{
if ( c != tdata_p->e || ChfGetNextDescriptor( c ) != tdata_p->d || ( tdata_p->phase != 2 && tdata_p->phase != 4 ) ) {
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
}
else {
action = ( ChfGetConditionCode( c ) != 8 ? CHF_CONTINUE : CHF_UNWIND );
}
break;
}
case CHF_UNWINDING:
{
if ( tdata_p->phase != 4 )
exit( EXIT_FAILURE );
tdata_p->phase = 5;
action = CHF_CONTINUE;
break;
}
default:
{
exit( EXIT_FAILURE );
}
}
return action;
}
ChfAction h3( const ChfDescriptor* c, const ChfState s, ChfPointer p )
{
struct tdata_s* tdata_p = ( struct tdata_s* )p;
ChfAction action;
/* This handler must be invoked only during the first signal */
if ( tdata_p->phase != 3 )
exit( EXIT_FAILURE );
switch ( s ) {
case CHF_SIGNALING:
{
if ( ChfGetConditionCode( c ) != 9 || ChfGetNextDescriptor( c ) != NULL ) {
exit( EXIT_FAILURE );
}
else {
tdata_p->phase = 4;
action = CHF_CONTINUE;
}
break;
}
default:
{
exit( EXIT_FAILURE );
}
}
return action;
}
ChfAction h4( const ChfDescriptor* c, const ChfState s, ChfPointer p )
{
struct tdata_s* tdata_p = ( struct tdata_s* )p;
ChfAction action;
/* This handler must be invoked only during the first signal */
if ( tdata_p->phase != 2 )
exit( EXIT_FAILURE );
switch ( s ) {
case CHF_SIGNALING:
{
if ( c != tdata_p->e || ChfGetNextDescriptor( c ) != tdata_p->d ) {
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
}
else {
/* This generates a new group and signals it */
tdata_p->phase = 3;
ChfCondition 9, CHF_INFO ChfEnd;
ChfSignal();
if ( tdata_p->phase != 4 )
exit( EXIT_FAILURE );
tdata_p->phase = 5;
if ( c != tdata_p->e || ChfGetNextDescriptor( c ) != tdata_p->d ) {
ChfCondition 10, CHF_FATAL ChfEnd;
action = CHF_RESIGNAL;
} else
action = CHF_CONTINUE;
}
break;
}
default:
{
exit( EXIT_FAILURE );
}
}
return action;
}
void* task( void* arg )
{
volatile struct tdata_s tdata;
/* The sleep() is here to increase contention between threads */
sleep( 1 );
printf( "\tThread %d\n", ( int )arg );
/* Push the handler */
ChfPushHandler( h1, NULL, ( ChfPointer )( &tdata ) );
/* Generate a condition group and signal it */
ChfCondition 6, CHF_INFO, ( int )arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 7, CHF_INFO, ( int )arg ChfEnd;
tdata.e = ChfGetTopCondition();
/* The sleep() is here to increase contention between threads */
sleep( 1 );
ChfSignal();
/* Pop the handler */
ChfPopHandler();
/* Generate a new condition group with (apparently) wrong linkage
and signal it; this checks that the handler has actually been
removed.
*/
ChfCondition 6, CHF_INFO, ( int )arg ChfEnd;
tdata.d = NULL;
ChfCondition 7, CHF_INFO, ( int )arg ChfEnd;
tdata.e = NULL;
ChfSignal();
/* Conditional unwind test */
{
sigjmp_buf jb;
tdata.phase = 0;
if ( setjmp( jb ) == 0 ) {
ChfPushHandler( h2, jb, ( ChfPointer )( &tdata ) );
/* Generate a condition group and signal it */
tdata.phase = 1;
ChfCondition 6, CHF_INFO, ( int )arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 7, CHF_INFO, ( int )arg ChfEnd;
tdata.e = ChfGetTopCondition();
/* This does not trigger an unwind */
tdata.phase = 2;
ChfSignal();
tdata.phase = 3;
ChfCondition 6, CHF_INFO, ( int )arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 8, CHF_INFO, ( int )arg ChfEnd;
tdata.e = ChfGetTopCondition();
/* This MUST trigger an unwind */
tdata.phase = 4;
ChfSignal();
exit( EXIT_FAILURE );
} else {
/* Unwind */
if ( tdata.phase != 5 )
exit( EXIT_FAILURE );
ChfPopHandler();
}
}
/* Condition generation and signal while a signal is in progress;
this requires two handlers.
*/
{
tdata.phase = 0;
ChfPushHandler( h3, NULL, ( ChfPointer )&tdata );
ChfPushHandler( h4, NULL, ( ChfPointer )&tdata );
tdata.phase = 1;
ChfCondition 6, CHF_INFO, ( int )arg ChfEnd;
tdata.d = ChfGetTopCondition();
ChfCondition 7, CHF_INFO, ( int )arg ChfEnd;
tdata.e = ChfGetTopCondition();
tdata.phase = 2;
ChfSignal();
if ( tdata.phase != 5 )
exit( EXIT_FAILURE );
ChfPopHandler();
ChfPopHandler();
}
return ( void* )0;
}
#define N_THREADS 50
int main( int argc, char* argv[] )
{
int st;
int i;
void* ret;
#ifdef _REENTRANT
pthread_t t[ N_THREADS ];
#endif
puts( "test04" );
/* Initialization */
if ( st = ChfMsgcatInit( argv[ 0 ], CHF_DEFAULT, "./test01.cat", 50, 10, 1 ) )
exit( st );
#ifdef _REENTRANT
/* Create */
for ( i = 0; i < N_THREADS; i++ )
if ( pthread_create( &( t[ i ] ), NULL, task, ( void* )i ) ) {
perror( "pthread_create" );
exit( EXIT_FAILURE );
}
/* Join */
for ( i = 0; i < N_THREADS; i++ )
if ( pthread_join( t[ i ], &ret ) ) {
perror( "pthread_join" );
exit( EXIT_FAILURE );
}
#else
task( ( void* )0 );
#endif
/* Exit Chf */
ChfExit();
exit( EXIT_SUCCESS );
}