294 lines
7.3 KiB
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 );
|
|
}
|