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: