/* $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 #include #include #include #ifdef _REENTRANT #include #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