/*----------------------------------------------------------+ | SHARE Multi-tasking Example - 1998 Winter conference | | session 5957 | +----------------------------------------------------------*/ #include #include #include #include #include #include #include "shrtyp.h" #include "shrpro.h" #define DECLARE_GLOBALS 1 #include "shrgbl.h" #define NUM_TASKS 3 #define CON_MSG_TOTAL 100*NUM_TASKS static const char * const apcDays[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; static const char * const apcMonths[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static void InitMsgPool(void); static int SubAttach(PTASK, PSZ); static void Title(void); static void TimeAlarm(int); static ANCHOR stAnchor; static int bTooLate = 0; static unsigned char pszText[133]; /*----------------------------------------------------------+ | Demo program that attaches a few subtasks, sends a few | | messages to each and then shuts down. | +----------------------------------------------------------*/ main() { int i, j; int iAttachRC; struct _ecblist *pShutdownECBs; MSG stMsg; TREQUEST stTimerRequest; sigset_t stNoSigs; int sleeptime; PTASK pTask, pOldTask = 0; pAnchor = &stAnchor; /* initialize global pointer to anchor */ /* initialize misc. fields in global area */ memset(pAnchor, 0, sizeof(ANCHOR)); memcpy(pAnchor->ucEye, "ANCHOR ", 8); /* set eye catcher */ memcpy(pAnchor->stMainQueue.abID, "QUE ", 4); Title(); /* print title line to log*/ InitMsgPool(); /* allocate storage for inter-task messages */ /* setup an ecb list that will wait for all tasks to end. An additional ecb will be used to wait on the timer task ending. */ pShutdownECBs = (struct _ecblist *) malloc((1+NUM_TASKS) * sizeof(struct _ecblist)); memset(pShutdownECBs, 0, (1+NUM_TASKS) * sizeof(struct _ecblist)); /*----------------------------------------------------------+ | allocate private storage to be passed to each subtask | | and chain them together | +----------------------------------------------------------*/ for (i=0; i < NUM_TASKS; i++) { pTask = (PTASK) malloc(sizeof(TASK)); memset(pTask, 0, sizeof(TASK)); pTask->pAnchor = pAnchor; pTask->iTaskNum = i+1; memcpy(pTask->stQueue.abID, "QUE ", 4); pShutdownECBs[i].count = 1; pShutdownECBs[i].ecbarr = &pTask->ulTaskEndECB; if (i == 0) { pAnchor->pSubTaskChain = pTask; } else { pOldTask->pNextTask = pTask; } pOldTask = pTask; } /*----------------------------------------------------------+ | initialize the timer subtask info | +----------------------------------------------------------*/ memset(&pAnchor->stTimerTask, 0, sizeof(TASK)); pAnchor->stTimerTask.pAnchor = pAnchor; memcpy(pAnchor->stTimerTask.stQueue.abID, "QUE ", 4); pShutdownECBs[NUM_TASKS].count = 1; pShutdownECBs[NUM_TASKS].ecbarr = &pAnchor->stTimerTask.ulTaskEndECB; /*----------------------------------------------------------+ | attach the timer subtask | +----------------------------------------------------------*/ iAttachRC = SubAttach(&pAnchor->stTimerTask, "SHRTIME"); if (iAttachRC != 0) { printf("SubAttach of timer failed\n"); exit(EXIT_FAILURE); } pTask = pAnchor->pSubTaskChain; /* point to the start of the subtask chain */ /*----------------------------------------------------------+ | attach each generic sub-task | +----------------------------------------------------------*/ for (i=0; i < NUM_TASKS; i++) { /*----------------------------------------------------------+ | attach each sub-task | +----------------------------------------------------------*/ iAttachRC = SubAttach(pTask, "SHRSUB"); if (iAttachRC != 0) { printf("SubAttach failed\n"); exit(EXIT_FAILURE); } pTask = pTask->pNextTask; } /*----------------------------------------------------------+ | send a timer message to the first generic subtask | +----------------------------------------------------------*/ stMsg.uiMsg = TIMERREQ; time(&stTimerRequest.dWakeUpTime); stTimerRequest.dWakeUpTime += 5; /* send the timer message in 5 seconds */ stTimerRequest.pTask = pAnchor->pSubTaskChain; memcpy(stMsg.ucData, &stTimerRequest, sizeof(TREQUEST)); WriteQueue(&pAnchor->stTimerTask.stQueue, 4+sizeof(TREQUEST), (PUCHAR) &stMsg); /*----------------------------------------------------------+ | send a few messages to each generic subtask | +----------------------------------------------------------*/ for (j=0x100; j < 0x103; j++) { pTask = pAnchor->pSubTaskChain; for (i=0; i < NUM_TASKS; i++) { stMsg.uiMsg = j; WriteQueue(&pTask->stQueue, 4, (PUCHAR) &stMsg); pTask = pTask->pNextTask; } } /*----------------------------------------------------------+ | send a timer message to the second generic subtask | +----------------------------------------------------------*/ sleeptime=1; while (sleeptime = sleep(sleeptime)); stMsg.uiMsg = TIMERREQ; time(&stTimerRequest.dWakeUpTime); stTimerRequest.dWakeUpTime += 2; /* send the timer message in 2 seconds */ stTimerRequest.pTask = pAnchor->pSubTaskChain->pNextTask; memcpy(stMsg.ucData, &stTimerRequest, sizeof(TREQUEST)); WriteQueue(&pAnchor->stTimerTask.stQueue, 4+sizeof(TREQUEST), (PUCHAR) &stMsg); /* give the timer messages a chance to occur */ sleeptime=30; while (sleeptime = sleep(sleeptime)); /*----------------------------------------------------------+ | shut down the timer subtask | +----------------------------------------------------------*/ stMsg.uiMsg = SHUTDOWN; WriteQueue(&pAnchor->stTimerTask.stQueue, 4, (PUCHAR) &stMsg); /*----------------------------------------------------------+ | shut down the generic subtasks | +----------------------------------------------------------*/ pTask = pAnchor->pSubTaskChain; for (i=0; i < NUM_TASKS; i++) { /*----------------------------------------------------------+ | ask each subtask to terminate | +----------------------------------------------------------*/ stMsg.uiMsg = SHUTDOWN; WriteQueue(&pTask->stQueue, 4, (PUCHAR) &stMsg); pTask = pTask->pNextTask; } /*----------------------------------------------------------+ | Wait for all subtasks to end. Detach the TCBs when the | | shutdown ecbs are posted. | +----------------------------------------------------------*/ while (1) { int bWaitSomeMore; signal(SIGALRM, &TimeAlarm);/* Catch SIGALRM signal. */ alarm(10); /* Wait max. ten seconds for some task(s) to end */ sigemptyset(&stNoSigs); /* Set no sigs blocked for suspend. */ /* wait for one or more shutdown ecbs to be posted, or for the alarm signal */ ecbsuspend(&stNoSigs, 1+NUM_TASKS, pShutdownECBs); alarm(0); /* Cancel alarm. */ signal(SIGALRM, SIG_DFL); /* Restore default alarm handling. */ bWaitSomeMore = 0; /* reset flag to show whether we need to wait for some more tasks to end */ pTask = pAnchor->pSubTaskChain; for (i=0; i < NUM_TASKS; i++) { if (pTask->ulTaskEndECB & POSTED) { sprintf(pszText, "Subtask #%i ended, detaching", pTask->iTaskNum); Log(pszText); DETACH(&pTask->pTaskTCB, NOSTAE); pTask->ulTaskEndECB = 0; pShutdownECBs[i].count = 0; } else if (pShutdownECBs[i].count != 0) bWaitSomeMore = 1; pTask = pTask->pNextTask; } /* check to see if the timer task has ended */ if (pAnchor->stTimerTask.ulTaskEndECB & POSTED) { sprintf(pszText, "Timer subtask ended, detaching"); Log(pszText); DETACH(&pAnchor->stTimerTask.pTaskTCB, NOSTAE); pAnchor->stTimerTask.ulTaskEndECB = 0; pShutdownECBs[NUM_TASKS].count = 0; } else if (pShutdownECBs[NUM_TASKS].count != 0) bWaitSomeMore = 1; if (!bWaitSomeMore) break; if (bTooLate) break; } /*----------------------------------------------------------+ | If we ran out of time, | +----------------------------------------------------------*/ if(bTooLate) { pTask = pAnchor->pSubTaskChain; for (i=0; i < NUM_TASKS; i++) { if (pShutdownECBs[i].count != 0) { sprintf(pszText, "Subtask #%i not responding, forced shutdown", pTask->iTaskNum); Log(pszText); DETACH(&pTask->pTaskTCB, NOSTAE); } pTask = pTask->pNextTask; } if (pShutdownECBs[NUM_TASKS].count != 0) { sprintf(pszText, "Timer subtask not responding, forced shutdown"); Log(pszText); DETACH(&pAnchor->stTimerTask.pTaskTCB, NOSTAE); } } /*----------------------------------------------------------------+ | cleanup: free storage for each subtask | +----------------------------------------------------------------*/ pTask = pAnchor->pSubTaskChain; /* point to the start of the subtask chain */ for (i=0; i < NUM_TASKS; i++) { pOldTask = pTask; pTask = pTask->pNextTask; free(pOldTask); } free(pShutdownECBs); free(pAnchor->pFreePool); return (EXIT_SUCCESS); } /*-------------------------------------------------------------------+ | SubAttach() is used to attach a sub-task. | +-------------------------------------------------------------------*/ static int SubAttach(PTASK pTask, PSZ pucModule) { int rc; sprintf(pTask->stTaskArg.ucParm,"%08X =u", pTask); pTask->stTaskArg.sLen = 11; pTask->pstTaskArg = (void *) (0x80000000 | (unsigned) &pTask->stTaskArg); rc = ATTACH(&pTask->pTaskTCB, _Aep, pucModule, _Aecb, &pTask->ulTaskEndECB, _Aparam, &pTask->pstTaskArg, _Aend); return (rc); } /*-------------------------------------------------------------------+ | Allocate and initialize the free message pool. | +-------------------------------------------------------------------*/ static void InitMsgPool(void) { int i; PMSGBLOCK pMsg, pMsgPrev; pAnchor->uCDS.stCDS.pMsgFirst = pMsg = pAnchor->pFreePool = (PMSGBLOCK) malloc(CON_MSG_TOTAL * sizeof(MSGBLOCK)); memset(pMsg, 0, CON_MSG_TOTAL * sizeof(MSGBLOCK)); pAnchor->ulFree = CON_MSG_TOTAL; for (i = 0; i < CON_MSG_TOTAL; i++) { memcpy(pMsg->abID, "MSG ", 4); pMsgPrev = pMsg; pMsg++; pMsgPrev->pMsgPrev = pMsg; } /* mark the last message for overflow conditions */ pAnchor->pFreePool[CON_MSG_TOTAL-1].abID[0] = 0xff; return; } /*-------------------------------------------------------------------+ | | | FUNCTION NAME: Title | | | | DESCRIPTIVE NAME: print title line to log | | | +-------------------------------------------------------------------*/ static void Title(void) { time_t dTime; struct tm *pTime; UCHAR abLine[133]; time(&dTime); pTime = localtime(&dTime); /* parse date */ sprintf(abLine, "%s %s, %s %u, %04u", "- SHARE Multi-tasking Example -", apcDays[pTime->tm_wday], apcMonths[pTime->tm_mon], pTime->tm_mday, pTime->tm_year + 1900); Log(abLine); } /*-------------------------------------------------------------------+ | SIGALRM handler | +-------------------------------------------------------------------*/ static void TimeAlarm(int signum) { bTooLate = 1; return; }