1:/*---------------------------------------------------------------------------
   2: 
   3:  FILENAME:
   4:        template.c
   5: 
   6:  PURPOSE:
   7:        Provide the radlib template process entry point.
   8: 
   9:  REVISION HISTORY:
  10:        Date            Engineer        Revision        Remarks
  11:        01/01/2004      Your Name       0               Original
  12: 
  13:  NOTES:
  14:        All references to "template" should be replaced by a meaningful
  15:        process name, including the file names and data structures.
  16: 
  17:----------------------------------------------------------------------------*/
  18:
  19:// System include files
  20:#include <sys/types.h>
  21:#include <sys/wait.h>
  22:#include <unistd.h>
  23:
  24:// radlib include files
  25:
  26:// Local include files
  27:#include "template.h"
  28:
  29:
  30:// global memory declarations
  31:
  32:// global memory referenced
  33:
  34:// static (local) memory declarations
  35:
  36:// declare the process work area
  37:static TEMPLATE_WORK    templateWork;
  38:
  39:// define the configuration file IDs in use
  40:enum ConfigIds
  41:{
  42:    CFG_ID_FILE_DEV         = 0,
  43:    CFG_ID_VERBOSE_MODE     = 1
  44:};
  45:
  46:// and the corresponding string identifiers
  47:static char             *configIDs[] =
  48:{
  49:    "FILE_DEV",
  50:    "VERBOSE_MSGS"
  51:};
  52:
  53:
  54:// methods
  55:
  56:static void msgHandler
  57:(
  58:    char        *srcQueueName,
  59:    UINT        msgType,
  60:    void        *msg,
  61:    UINT        length,
  62:    void        *userData
  63:)
  64:{
  65:    STIM        stim;
  66:
  67:    stim.type           = STIM_QMSG;
  68:    stim.srcQueueName   = srcQueueName;
  69:    stim.msgType        = msgType;
  70:    stim.msg            = msg;
  71:    stim.length         = length;
  72:
  73:    radStatesProcess (templateWork.stateMachine, &stim);
  74:
  75:    return;
  76:}
  77:
  78:static void evtHandler
  79:(
  80:    UINT        eventsRx,
  81:    UINT        rxData,
  82:    void        *userData
  83:)
  84:{
  85:    STIM        stim;
  86:
  87:    stim.type           = STIM_EVENT;
  88:    stim.eventsRx       = eventsRx;
  89:    stim.eventData      = rxData;
  90:
  91:    radStatesProcess (templateWork.stateMachine, &stim);
  92:
  93:    return;
  94:}
  95:
  96:static void timer1Handler (void *parm)
  97:{
  98:    STIM        stim;
  99:
 100:    memset (&stim, 0, sizeof (stim));
 101:
 102:    stim.type           = STIM_TIMER;
 103:    stim.timerNumber    = TEMPLATE_TIMER_NUM1;
 104:
 105:    radStatesProcess (templateWork.stateMachine, &stim);
 106:
 107:    return;
 108:}
 109:
 110:static void timer2Handler (void *parm)
 111:{
 112:    STIM        stim;
 113:
 114:    memset (&stim, 0, sizeof (stim));
 115:
 116:    stim.type           = STIM_TIMER;
 117:    stim.timerNumber    = TEMPLATE_TIMER_NUM2;
 118:
 119:    radStatesProcess (templateWork.stateMachine, &stim);
 120:
 121:    return;
 122:}
 123:
 124:static void stdinDataCallback (int fd, void *userData)
 125:{
 126:    STIM        stim;
 127:
 128:    memset (&stim, 0, sizeof (stim));
 129:
 130:    stim.type           = STIM_IO;
 131:    stim.iofd           = fd;
 132:
 133:    radStatesProcess (templateWork.stateMachine, &stim);
 134:
 135:    return;
 136:}
 137:
 138:
 139:// process initialization
 140:static int templateSysInit (void)
 141:{
 142:    char            devPath[256], temp[32];
 143:    char            *installPath;
 144:    struct stat     fileData;
 145:    FILE            *pidfile;
 146:
 147:    // get the install path
 148:    installPath = getenv ("APPLICATION_RUN_DIRECTORY");
 149:    if (installPath == NULL)
 150:    {
 151:        installPath = ".";
 152:    }
 153:    chdir (installPath);
 154:
 155:
 156:    // check for our pid file, don't run if it is there
 157:    sprintf (devPath, "%s/%s", installPath, TEMPLATE_LOCK_FILENAME);
 158:    if (stat (devPath, &fileData) == 0)
 159:    {
 160:        printf ("lock file %s exists, older copy may be running - aborting!\n",
 161:                devPath);
 162:        return -1;
 163:    }
 164:
 165:
 166:    // create our device directory if it is not there
 167:    sprintf (devPath, "%s/dev", installPath);
 168:    if (stat (devPath, &fileData) != 0)
 169:    {
 170:        if (mkdir (devPath, 0755) != 0)
 171:        {
 172:            printf ("Cannot create device dir: %s - aborting!\n",
 173:                    devPath);
 174:            return -1;
 175:        }
 176:    }
 177:
 178:    return 0;
 179:}
 180:
 181:// system exit
 182:static int templateSysExit (void)
 183:{
 184:    char            devPath[256];
 185:    char            *installPath;
 186:    struct stat     fileData;
 187:
 188:    // get the install path
 189:    installPath = getenv ("APPLICATION_RUN_DIRECTORY");
 190:    if (installPath == NULL)
 191:    {
 192:        installPath = ".";
 193:    }
 194:
 195:    // delete our pid file
 196:    sprintf (devPath, "%s/%s", installPath, TEMPLATE_LOCK_FILENAME);
 197:    if (stat (devPath, &fileData) == 0)
 198:    {
 199:        printf ("\nlock file %s exists, deleting it...\n",
 200:                devPath);
 201:        if (unlink (devPath) == -1)
 202:        {
 203:            printf ("lock file %s delete failed!\n",
 204:                    devPath);
 205:        }
 206:    }
 207:
 208:    return 0;
 209:}
 210:
 211:static void defaultSigHandler (int signum)
 212:{
 213:    switch (signum)
 214:    {
 215:        case SIGPIPE:
 216:            // if you are using sockets or pipes, you will need to catch this
 217:            // we have a far end socket disconnection, we'll handle it in the
 218:            // "read/write" code
 219:            signal (signum, defaultSigHandler);
 220:            break;
 221:
 222:        case SIGILL:
 223:        case SIGBUS:
 224:        case SIGFPE:
 225:        case SIGSEGV:
 226:        case SIGXFSZ:
 227:        case SIGSYS:
 228:            // unrecoverable signal - we must exit right now!
 229:            radMsgLog (PRI_CATASTROPHIC, "templated: recv sig %d: bailing out!", signum);
 230:            abort ();
 231:        
 232:        case SIGCHLD:
 233:            wait (NULL);
 234:            signal (signum, defaultSigHandler);
 235:            break;
 236:
 237:        default:
 238:            // can we allow the process to exit normally?
 239:            if (radProcessGetExitFlag())
 240:            {
 241:                // NO! - we gotta bail here!
 242:                radMsgLog (PRI_HIGH, "templated: recv sig %d: exiting now!", signum);
 243:                exit (0);                
 244:            }
 245:            
 246:            // we can allow the process to exit normally...
 247:            radMsgLog (PRI_HIGH, "templated: recv sig %d: exiting!", signum);
 248:        
 249:            radProcessSetExitFlag ();
 250:        
 251:            signal (signum, defaultSigHandler);
 252:            break;
 253:    }
 254:
 255:    return;
 256:}
 257:
 258:
 259:// the main entry point for the template process
 260:int main (int argc, char *argv[])
 261:{
 262:    void            (*alarmHandler)(int);
 263:    STIM            stim;
 264:    int             i;
 265:    char            qname[256], cfgname[256], instance[32], value[32];
 266:    char            pidName[256];
 267:    char            *installPath;
 268:    CF_ID           configFileId;
 269:    struct stat     fileStatus;
 270:    FILE            *pidfile;
 271:
 272:
 273:    // initialize some system stuff first
 274:    if (templateSysInit () == -1)
 275:    {
 276:        radMsgLogInit (PROC_NAME_TEMPLATE, TRUE, TRUE);
 277:        radMsgLog (PRI_CATASTROPHIC, "system init failed!\n");
 278:        radMsgLogExit ();
 279:        exit (1);
 280:    }
 281:
 282:    // create some file paths for later use
 283:    installPath = getenv ("APPLICATION_RUN_DIRECTORY");
 284:    if (installPath == NULL)
 285:    {
 286:        installPath = ".";
 287:    }
 288:    sprintf (qname, "%s/dev/%s", installPath, PROC_NAME_TEMPLATE);
 289:    sprintf (cfgname, "%s/%s", installPath, TEMPLATE_CONFIG_FILENAME);
 290:    sprintf (pidName, "%s/%s", installPath, TEMPLATE_LOCK_FILENAME);
 291:
 292:    memset (&templateWork, 0, sizeof (templateWork));
 293:
 294:
 295:
 296:    // call the global radlib system init function
 297:    if (radSystemInit (TEMPLATE_SYSTEM_ID) == ERROR)
 298:    {
 299:        radMsgLogInit (PROC_NAME_TEMPLATE, TRUE, TRUE);
 300:        radMsgLog (PRI_CATASTROPHIC, "%s: radSystemInit failed!");
 301:        radMsgLogExit ();
 302:        exit (1);
 303:    }
 304:
 305:
 306:    // call the radlib process init function
 307:    if (radProcessInit (PROC_NAME_TEMPLATE,
 308:                        qname,
 309:                        PROC_NUM_TIMERS_TEMPLATE,
 310:                        FALSE,                     // FALSE => not as daemon
 311:                        msgHandler,
 312:                        evtHandler,
 313:                        NULL)
 314:            == ERROR)
 315:    {
 316:        radMsgLogInit (PROC_NAME_TEMPLATE, TRUE, TRUE);
 317:        radMsgLog (PRI_CATASTROPHIC, "radProcessInit failed: %s",
 318:                   PROC_NAME_TEMPLATE);
 319:        radMsgLogExit ();
 320:
 321:        radSystemExit (TEMPLATE_SYSTEM_ID);
 322:
 323:        exit (1);
 324:    }
 325:
 326:    // save our process pid and create the lock file 
 327:    templateWork.myPid = getpid ();
 328:    pidfile = fopen (pidName, "w");
 329:    if (pidfile == NULL)
 330:    {
 331:        radMsgLog (PRI_CATASTROPHIC, "lock file create failed!\n");
 332:
 333:        radProcessExit ();
 334:        radSystemExit (TEMPLATE_SYSTEM_ID);
 335:
 336:        exit (1);
 337:    }
 338:    fprintf (pidfile, "%d", templateWork.myPid);
 339:    fclose (pidfile);
 340:
 341:
 342:    // save the current alarm signal handler, set all signal handlers
 343:    // to the default handler, then set the alarm handler back to original
 344:    alarmHandler = radProcessSignalGetHandler (SIGALRM);
 345:    radProcessSignalCatchAll (defaultSigHandler);
 346:    radProcessSignalCatch (SIGALRM, alarmHandler);
 347:
 348:
 349:    // get our configuration values
 350:    if (stat (cfgname, &fileStatus) == -1)
 351:    {
 352:        // file does not exist, populate with defaults
 353:        configFileId = radCfOpen (cfgname);
 354:        if (configFileId == NULL)
 355:        {
 356:            radMsgLog (PRI_CATASTROPHIC, "radCfOpen 1 failed!\n");
 357:
 358:            radProcessExit ();
 359:            radSystemExit (TEMPLATE_SYSTEM_ID);
 360:
 361:            exit (1);
 362:        }
 363:
 364:        radCfPutEntry (configFileId,
 365:                       configIDs[CFG_ID_FILE_DEV],
 366:                       NULL,
 367:                       "/dev/ttyS0",
 368:                       "template serial device");
 369:        radCfPutEntry (configFileId,
 370:                       configIDs[CFG_ID_VERBOSE_MODE],
 371:                       NULL,
 372:                       "1",
 373:                       "produce more and verbose diagnostics");
 374:
 375:        // write out the new file
 376:        if (radCfFlush (configFileId) == ERROR)
 377:        {
 378:            radMsgLog (PRI_CATASTROPHIC, "radCfFlush failed!\n");
 379:
 380:            radProcessExit ();
 381:            radSystemExit (TEMPLATE_SYSTEM_ID);
 382:
 383:            exit (1);
 384:        }
 385:
 386:        radCfClose (configFileId);
 387:    }
 388:
 389:
 390:    // now open the config file for reading
 391:    configFileId = radCfOpen (cfgname);
 392:    if (configFileId == NULL)
 393:    {
 394:        radMsgLog (PRI_CATASTROPHIC, "radCfOpen 2 failed!\n");
 395:
 396:        radProcessExit ();
 397:        radSystemExit (TEMPLATE_SYSTEM_ID);
 398:
 399:        exit (1);
 400:    }
 401:
 402:    if (radCfGetFirstEntry (configFileId,
 403:                            configIDs[CFG_ID_FILE_DEV],
 404:                            NULL,
 405:                            value)
 406:            == ERROR)
 407:    {
 408:        radMsgLog (PRI_CATASTROPHIC, "radCfGetFirstEntry failed!\n");
 409:        radCfClose (configFileId);
 410:
 411:        radProcessExit ();
 412:        radSystemExit (TEMPLATE_SYSTEM_ID);
 413:
 414:        exit (1);
 415:    }
 416:    strcpy (templateWork.fileDev, value);
 417:
 418:    if (radCfGetFirstEntry (configFileId,
 419:                            configIDs[CFG_ID_VERBOSE_MODE],
 420:                            NULL,
 421:                            value)
 422:            == ERROR)
 423:    {
 424:        radMsgLog (PRI_CATASTROPHIC, "radCfGetFirstEntry failed!\n");
 425:        radCfClose (configFileId);
 426:
 427:        radProcessExit ();
 428:        radSystemExit (TEMPLATE_SYSTEM_ID);
 429:
 430:        exit (1);
 431:    }
 432:    templateWork.verboseMode = atoi (value);
 433:
 434:    radCfClose (configFileId);
 435:
 436:
 437:    // open stdin and setup for "radProcessWait" calls
 438:    // (stdin is already open, but other devices should be opened
 439:    // prior to registration)
 440:    if (radProcessIORegisterSTDIN (stdinDataCallback, NULL) == ERROR)
 441:    {
 442:        radMsgLog (PRI_HIGH, "IORegDescriptor failed");
 443:
 444:        radProcessExit ();
 445:        radSystemExit (TEMPLATE_SYSTEM_ID);
 446:
 447:        exit (1);
 448:    }
 449:
 450:    radMsgLog (PRI_STATUS, "stdin 'opened' and registered ...");
 451:
 452:
 453:    // create our state machine - where all run-time work is done
 454:    templateWork.stateMachine = radStatesInit (&templateWork);
 455:    if (templateWork.stateMachine == NULL)
 456:    {
 457:        radMsgLog (PRI_HIGH, "radStatesInit failed");
 458:
 459:        radProcessExit ();
 460:        radSystemExit (TEMPLATE_SYSTEM_ID);
 461:
 462:        exit (1);
 463:    }
 464:
 465:    if (radStatesAddHandler (templateWork.stateMachine, TEMPLATE_STATE_IDLE,
 466:                             templateIdleState)
 467:            == ERROR)
 468:    {
 469:        radMsgLog (PRI_HIGH, "radStatesAddHandler failed");
 470:        radStatesExit (templateWork.stateMachine);
 471:
 472:        radProcessExit ();
 473:        radSystemExit (TEMPLATE_SYSTEM_ID);
 474:
 475:        exit (1);
 476:    }
 477:    if (radStatesAddHandler (templateWork.stateMachine, TEMPLATE_STATE_RUN,
 478:                             templateRunState)
 479:            == ERROR)
 480:    {
 481:        radMsgLog (PRI_HIGH, "radStatesAddHandler failed");
 482:        radStatesExit (templateWork.stateMachine);
 483:
 484:        radProcessExit ();
 485:        radSystemExit (TEMPLATE_SYSTEM_ID);
 486:
 487:        exit (1);
 488:    }
 489:    if (radStatesAddHandler (templateWork.stateMachine, TEMPLATE_STATE_ERROR,
 490:                             templateErrorState)
 491:            == ERROR)
 492:    {
 493:        radMsgLog (PRI_HIGH, "radStatesAddHandler failed");
 494:        radStatesExit (templateWork.stateMachine);
 495:
 496:        radProcessExit ();
 497:        radSystemExit (TEMPLATE_SYSTEM_ID);
 498:
 499:        exit (1);
 500:    }
 501:
 502:    radStatesSetState (templateWork.stateMachine, TEMPLATE_STATE_IDLE);
 503:
 504:
 505:    // create a couple of timers
 506:    templateWork.timerNum1 = radTimerCreate (NULL, timer1Handler, NULL);
 507:    if (templateWork.timerNum1 == NULL)
 508:    {
 509:        radMsgLog (PRI_HIGH, "radTimerCreate failed");
 510:        radStatesExit (templateWork.stateMachine);
 511:
 512:        radProcessExit ();
 513:        radSystemExit (TEMPLATE_SYSTEM_ID);
 514:
 515:        exit (1);
 516:    }
 517:
 518:    templateWork.timerNum2 = radTimerCreate (NULL, timer2Handler, NULL);
 519:    if (templateWork.timerNum2 == NULL)
 520:    {
 521:        radMsgLog (PRI_HIGH, "radTimerCreate failed");
 522:        radTimerDelete (templateWork.timerNum1);
 523:        radStatesExit (templateWork.stateMachine);
 524:
 525:        radProcessExit ();
 526:        radSystemExit (TEMPLATE_SYSTEM_ID);
 527:
 528:        exit (1);
 529:    }
 530:
 531:    // initialize the radlib message router interface
 532:    if (radMsgRouterInit (".") == ERROR)
 533:    {
 534:        radMsgLog (PRI_HIGH, "radMsgRouterInit failed");
 535:        radTimerDelete (templateWork.timerNum2);
 536:        radTimerDelete (templateWork.timerNum1);
 537:        radStatesExit (templateWork.stateMachine);
 538:
 539:        radProcessExit ();
 540:        radSystemExit (TEMPLATE_SYSTEM_ID);
 541:
 542:        exit (1);
 543:    }
 544:
 545:    radMsgRouterMessageRegister (TEMPLATE_MSGID_USER_RESPONSE);
 546:
 547:
 548:    printf ("\n**************************************************************************************\n");
 549:    printf ("There are now 3 radlib processes running:\n");
 550:    printf ("    radmrouted    the radlib message router daemon\n");
 551:    printf ("    template2d    the template daemon which does the prime number computations\n");
 552:    printf ("    templated     the non-daemon process which does console I/O (and prints this text)\n\n");    
 553:    printf ("Enter a positive integer 'x' then <CR> - the number of prime numbers < 'x'\n");
 554:    printf ("will be returned (it is computed by the 'template2d' daemon)\n\n");
 555:    printf ("There are two timers running which will expire and log a message every\n");
 556:    printf ("%d and %d seconds respectively\n\n", 
 557:            TEMPLATE_TIMER1_PERIOD/1000, TEMPLATE_TIMER2_PERIOD/1000);
 558:    printf ("<CTRL-C> to exit ('templated'), then 'runtemplates stop' to stop the \n");
 559:    printf ("'template2d' and 'radmrouted' (message router) daemons\n");
 560:    printf ("**************************************************************************************\n\n");
 561:
 562:
 563:    // dummy up a stimulus to get the state machine running
 564:    stim.type = STIM_DUMMY;
 565:    radStatesProcess (templateWork.stateMachine, &stim);
 566:
 567:
 568:    while (!templateWork.exiting)
 569:    {
 570:        // wait on timers, events, file descriptors, msgs, everything!
 571:        if (radProcessWait (0) == ERROR)
 572:        {
 573:            templateWork.exiting = TRUE;
 574:        }
 575:    }
 576:
 577:
 578:    radMsgLog (PRI_STATUS, "exiting normally...");
 579:
 580:    radTimerDelete (templateWork.timerNum2);
 581:    radTimerDelete (templateWork.timerNum1);
 582:    radStatesExit (templateWork.stateMachine);
 583:    templateSysExit ();
 584:
 585:    radProcessExit ();
 586:    radSystemExit (TEMPLATE_SYSTEM_ID);
 587:
 588:    exit (0);
 589:}
 590: