saturnng/Chf/test04.c
2022-03-21 11:05:59 +01:00

331 lines
6.1 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);
}