home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / sun / volume03 / shared.mem < prev    next >
Encoding:
Internet Message Format  |  1991-10-25  |  31.5 KB

  1. Path: uunet!seismo!dimacs.rutgers.edu!aramis.rutgers.edu!athos.rutgers.edu!mcgrew
  2. From: mcgrew@athos.rutgers.edu (Charles Mcgrew)
  3. Newsgroups: comp.sources.sun
  4. Subject: v03i010:  Shared memory source example
  5. Message-ID: <Oct.25.12.18.51.1991.28461@athos.rutgers.edu>
  6. Date: 25 Oct 91 16:18:52 GMT
  7. Organization: Rutgers Univ., New Brunswick, N.J.
  8. Lines: 923
  9. Approved: mcgrew@aramis.rutgers.edu
  10.  
  11. Submitted-by: rwolf@dretor.dciem.dnd.ca (Robert J Wolf)
  12. Posting-number: Volume 3, Issue 10
  13. Archive-name: shared-mem
  14.  
  15.     [I did not test these, but as programming examples they look
  16.      very good. -CWM]
  17.  
  18.  
  19.     Enclosed is free-ware sample shared memory programs.  It demonstrates how
  20.     to use shared memory to allow one program to sent messages to another
  21.     program.
  22.     
  23.     This example implements a circular buffer inside shared memory.  All timing
  24.     and race conditions have been eliminated and no semaphores, no signals and
  25.     no other external access controls are needed.  The shared memory does it
  26.     all!  In fact the method used is so simple and lightning fast I would be
  27.     surprised if anyone can improve it.  Plus it is portable and will probably
  28.     run on all unix versions.  I have verified its operation on IBM AIX, DG UX,
  29.     SCO Unix, SunOS.  In fact this approach is so simple & effective it could
  30.     be ported to OS/2 or VMS by changing a few system calls to setup the shared
  31.     memory.
  32.     
  33.     If people want their programs to communicate bi-directionally then great,
  34.     use two pieces of shared memory and reverse the consumer and producer roles
  35.     for the second one!  The key is not to have more than one process writing
  36.     to the same piece of shared memory.
  37.     
  38.     If people think the programs should use C pointers inside the shared memory
  39.     instead of offsets then you are wrong because two programs may not use the
  40.     same virtual addres to the same shared memory segment.  It may work on some
  41.     machines but not all!  I know because I found out the hard way.
  42.     
  43.     I highly recommend people use it.
  44.     
  45.     I can currently me reached via e-mail at
  46.     rwolf@dciem.dnd.ca
  47.     uunet!csri.toronto.edu!dciem!rwolf
  48.     Internet: 192.16.207.3
  49.     
  50.     Thank you & good luck
  51.     Robert Wolf
  52.     56 Shadberry Drive
  53.     North York (Toronto), Ontario
  54.     M2H 3C8   Canada
  55.     (416) 490-8493
  56.     
  57.     Legal Note.
  58.     This software is freely given to the world with the following
  59.     conditions:
  60.     1) No change to the code and/or the comments must be done.  It must be
  61.     distributed exactly as is.  Any desired changes should be
  62.     sent to me and I will consider it for update.
  63.     2) This software may not be published in any form with out my
  64.     express written consent.
  65.           
  66.     1991 July 17
  67. #! /bin/sh
  68. # This is a shell archive.  Remove anything before this line, then unpack
  69. # it by saving it into a file and typing "sh file".  To overwrite existing
  70. # files, type "sh file -c".  You can also feed this as standard input via
  71. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  72. # will see the following message at the end:
  73. #        "End of shell archive."
  74. # Contents:  READ.ME makefile run.sh producer.c consumer.c
  75. # Wrapped by rwolf@accord on Wed Jul 17 10:13:46 1991
  76. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  77. if test -f READ.ME -a "${1}" != "-c" ; then 
  78.   echo shar: Will not over-write existing file \"READ.ME\"
  79. else
  80. echo shar: Extracting \"READ.ME\" \(2144 characters\)
  81. sed "s/^X//" >READ.ME <<'END_OF_READ.ME'
  82. X    Enclosed is free-ware sample shared memory programs.  It demonstrates how
  83. X    to use shared memory to allow one program to sent messages to another
  84. X    program.
  85. X    
  86. X    This example implements a circular buffer inside shared memory.  All timing
  87. X    and race conditions have been eliminated and no semaphores, no signals and
  88. X    no other external access controls are needed.  The shared memory does it
  89. X    all!  In fact the method used is so simple and lightning fast I would be
  90. X    surprised if anyone can improve it.  Plus it is portable and will probably
  91. X    run on all unix versions.  I have verified its operation on IBM AIX, DG UX,
  92. X    SCO Unix, SunOS.  In fact this approach is so simple & effective it could
  93. X    be ported to OS/2 or VMS by changing a few system calls to setup the shared
  94. X    memory.
  95. X    
  96. X    If people want their programs to communicate bi-directionally then great,
  97. X    use two pieces of shared memory and reverse the consumer and producer roles
  98. X    for the second one!  The key is not to have more than one process writing
  99. X    to the same piece of shared memory.
  100. X    
  101. X    If people think the programs should use C pointers inside the shared memory
  102. X    instead of offsets then you are wrong because two programs may not use the
  103. X    same virtual addres to the same shared memory segment.  It may work on some
  104. X    machines but not all!  I know because I found out the hard way.
  105. X    
  106. X    I highly recommend people use it.
  107. X    
  108. X    I can currently me reached via e-mail at
  109. X    rwolf@dciem.dnd.ca
  110. X    uunet!csri.toronto.edu!dciem!rwolf
  111. X    Internet: 192.16.207.3
  112. X    
  113. X    Thank you & good luck
  114. X    Robert Wolf
  115. X    56 Shadberry Drive
  116. X    North York (Toronto), Ontario
  117. X    M2H 3C8   Canada
  118. X    (416) 490-8493
  119. X    
  120. X    Legal Note.
  121. X    This software is freely given to the world with the following
  122. X    conditions:
  123. X    1) No change to the code and/or the comments must be done.  It must be
  124. X    distributed exactly as is.  Any desired changes should be
  125. X    sent to me and I will consider it for update.
  126. X    2) This software may not be published in any form with out my
  127. X    express written consent.
  128. X          
  129. X    1991 July 17
  130. END_OF_READ.ME
  131. if test 2144 -ne `wc -c <READ.ME`; then
  132.     echo shar: \"READ.ME\" unpacked with wrong size!
  133. fi
  134. # end of overwriting check
  135. fi
  136. if test -f makefile -a "${1}" != "-c" ; then 
  137.   echo shar: Will not over-write existing file \"makefile\"
  138. else
  139. echo shar: Extracting \"makefile\" \(522 characters\)
  140. sed "s/^X//" >makefile <<'END_OF_makefile'
  141. X# Makefile for the sample shared memory programs.
  142. X
  143. XCFLAGS = -g -a
  144. X
  145. XLIBS =
  146. X
  147. XPROGRAMS = producer consumer
  148. X
  149. X# Generate all the programs
  150. Xall : $(PROGRAMS)
  151. X
  152. Xproducer : producer.c
  153. X    cc $(CFLAGS) -o producer producer.c $(LIBS)
  154. X
  155. Xconsumer : consumer.c
  156. X    cc $(CFLAGS) -o consumer consumer.c $(LIBS)
  157. X
  158. X# Lint commands for the two programs
  159. Xlint_producer :
  160. X    lint producer.c > producer.lnt
  161. X
  162. Xlint_consumer :
  163. X    lint consumer.c > consumer.lnt
  164. X
  165. X# This target is used to delete the executable and object files
  166. Xclean :
  167. X    -rm $(PROGRAMS) *.o *.lnt
  168. END_OF_makefile
  169. if test 522 -ne `wc -c <makefile`; then
  170.     echo shar: \"makefile\" unpacked with wrong size!
  171. fi
  172. # end of overwriting check
  173. fi
  174. if test -f run.sh -a "${1}" != "-c" ; then 
  175.   echo shar: Will not over-write existing file \"run.sh\"
  176. else
  177. echo shar: Extracting \"run.sh\" \(130 characters\)
  178. sed "s/^X//" >run.sh <<'END_OF_run.sh'
  179. Xecho starting consumer
  180. Xconsumer -i shared.dat -s 500000 -o consumer.out &
  181. Xsleep 3
  182. Xecho starting producer
  183. Xproducer -o shared.dat &
  184. END_OF_run.sh
  185. if test 130 -ne `wc -c <run.sh`; then
  186.     echo shar: \"run.sh\" unpacked with wrong size!
  187. fi
  188. # end of overwriting check
  189. fi
  190. if test -f producer.c -a "${1}" != "-c" ; then 
  191.   echo shar: Will not over-write existing file \"producer.c\"
  192. else
  193. echo shar: Extracting \"producer.c\" \(10418 characters\)
  194. sed "s/^X//" >producer.c <<'END_OF_producer.c'
  195. X/****producer
  196. X
  197. X    Synopsis.
  198. X        Program to produce some data and dump into a circular buffer stored in
  199. X        shared memory (ie producer).  Another process is expected to read the
  200. X        data from the shared memory (ie consumer).
  201. X
  202. X    Usage.
  203. X          producer -o shared memory info file name
  204. X
  205. X    Function.
  206. X
  207. X    Routine description.
  208. X
  209. X         shm_head | shm_tail | ................. |
  210. X
  211. X                     shm_head - will offset to the next free space
  212. X                     shm_tail - will offset to the next new data
  213. X                           Note: if shm_head = shm_tail then empty
  214. X
  215. X    Notes.
  216. X        1) If there is no room in the shared memory circular buffer then
  217. X           give up the time-slice to another process.  In order to do this
  218. X           call the time function which is a kernal call that will retrieve
  219. X           the current time.  After a kernal call is about to complete, the
  220. X           operating system does a process priority scheduling check.  The
  221. X           hope here is another process will be scheduled and hopefully it
  222. X           will be the process to read the circular buffer (ie consumer).
  223. X           There is no guarantee it will be the desired process but it will
  224. X           at least improve the efficiency and throughput of the system which
  225. X           will beneficial to everyone.
  226. X
  227. X    Update Log.
  228. X    1990 Jun 12    Robert Wolf
  229. X                   56 Shadberry Drive
  230. X                   North York, Ontario
  231. X                   M2H 3C8   Canada
  232. X                   (416) 490-8493
  233. X
  234. X    Legal Note.
  235. X        This software is freely given to the world with the following
  236. X        conditions:
  237. X        1) No change to the code and/or the comments must be done.  It must be
  238. X           distributed exactly as is.  Any desired changes should be
  239. X           sent to me and I will consider it for update.
  240. X        2) This software may not be published in any form with out my
  241. X           express written consent.
  242. X      
  243. X****/
  244. X
  245. X#include <stdio.h>
  246. X#include <signal.h>
  247. X#include <errno.h>
  248. X#include <sys/types.h>
  249. X#include <sys/stat.h>
  250. X#include <sys/ipc.h>
  251. X#include <sys/shm.h>
  252. X#include <string.h>
  253. X
  254. Xextern char *shmat();
  255. Xextern long  time();
  256. X
  257. Xextern int   getopt();
  258. Xextern char *optarg;
  259. X
  260. X#ifndef TRUE                        /* True */
  261. X#define TRUE 1
  262. X#endif
  263. X
  264. X#ifndef FALSE                       /* False */
  265. X#define FALSE 0
  266. X#endif
  267. X
  268. X#ifndef EOS                         /* End of string */
  269. X#define EOS '\0'
  270. X#endif
  271. X
  272. X#ifndef EOF                         /* End of file */
  273. X#define EOF (-1)
  274. X#endif
  275. X
  276. X#define MAX_FILE_SIZE   60          /* Maximum file name size */
  277. X
  278. Xstatic char *shm_block = (char *) NULL;     /* shared memory block */
  279. X
  280. Xint main(argc, argv)
  281. Xint   argc;
  282. Xchar *argv[];
  283. X{
  284. X    int  shm_id;                        /* shared memory id */
  285. X    int  shm_size;                      /* shared memory size */
  286. X    char *shm_addr;                     /* shared memory address selection */
  287. X    int  shm_flag;                      /* shared memory flags */
  288. X    char *shm_start;                    /* start of shared memory */
  289. X    long *shm_head, *shm_tail;          /* head/tail offset of shared memory */
  290. X    int  avail_space;                   /* available space */
  291. X
  292. X    static char data_string[] = "abcdefghijklmnopqrstuvwxyz0123456789\n";
  293. X    long  data_index, data_len, i;
  294. X
  295. X    void die();
  296. X
  297. X    data_len = strlen(data_string);
  298. X
  299. X    /* Process the command line arguments */
  300. X    if (prod_arguments(argc, argv, &shm_id, &shm_size))
  301. X        die();
  302. X
  303. X    /* Setup the signal handling */
  304. X    if (prod_signal(die))
  305. X        die();
  306. X
  307. X    /* Attach to the shared memory data */
  308. X    shm_addr = (char *) 0;               /* allow o/s to select the address */
  309. X    shm_flag = 0;                        /* read/write mode */
  310. X    shm_block = shmat(shm_id, shm_addr, shm_flag);
  311. X    if ((int) shm_block == (-1)) {
  312. X         fputs("\nERROR: producer, can not attach to shared memory, ", stderr);
  313. X         fprintf(stderr, "errno=%d\n", errno);
  314. X         shm_block = (char *) NULL;
  315. X         die();
  316. X    }
  317. X
  318. X    /* Setup the head and tail pointers */
  319. X    shm_head = (long *) shm_block;
  320. X    shm_tail = (long *) (shm_block + sizeof(long));
  321. X
  322. X    shm_start = shm_block + 2L * sizeof(long);
  323. X
  324. X    *shm_head = 0L;
  325. X    *shm_tail = 0L;
  326. X
  327. X#ifdef SHM_DEBUG
  328. X    printf("shm_block=%ld shm_start=%ld\n",   shm_block, shm_start);
  329. X    printf("shm_head =%ld *shm_head=%ld\n",   shm_head, *shm_head);
  330. X    printf("shm_tail =%ld *shm_tail=%ld\n\n", shm_tail, *shm_tail);
  331. X#endif
  332. X
  333. X    /* Fill the shared memory continuously */
  334. X    data_index = 0;
  335. X    while (1) {
  336. X
  337. X        /* Head pointer is ahead of tail pointer */
  338. X        if (*shm_head >= *shm_tail) {
  339. X
  340. X            avail_space = shm_size - 2L * sizeof(long) - (*shm_head) + 1L;
  341. X            if (*shm_tail == 0L)
  342. X                 avail_space--;
  343. X            if (avail_space <= 0L) {
  344. X                 (void) time((long *) 0);           /* see note 1 above */
  345. X                 continue;
  346. X            }
  347. X
  348. X            for (i = 0L; i < avail_space; i++) {
  349. X                shm_start[*shm_head + i] = data_string[data_index];
  350. X                data_index = (data_index + 1) % data_len;
  351. X            }
  352. X            *shm_head += avail_space;
  353. X            if (*shm_head + 2L * sizeof(long) > shm_size)     /* wrap at end */
  354. X                *shm_head = 0L;
  355. X
  356. X#ifdef SHM_DEBUG
  357. X            printf("shm_block=%ld shm_start=%ld\n", shm_block, shm_start);
  358. X            printf("shm_head =%ld *shm_head=%ld\n", shm_head, *shm_head);
  359. X            printf("shm_tail =%ld *shm_tail=%ld\n", shm_tail, *shm_tail);
  360. X            printf("num_read=%d\n\n", num_read);
  361. X#endif
  362. X
  363. X        /* Head pointer is behind the tail pointer */
  364. X        } else {
  365. X            avail_space = (*shm_tail) - (*shm_head) - 1L;
  366. X            if (avail_space <= 0L) {
  367. X                 (void) time((long *) 0);           /* see note 1 above */
  368. X                 continue;
  369. X            }
  370. X
  371. X            for (i = 0L; i < avail_space; i++) {
  372. X                shm_start[*shm_head + i] = data_string[data_index];
  373. X                data_index = (data_index + 1) % data_len;
  374. X            }
  375. X            *shm_head += avail_space;
  376. X
  377. X#ifdef SHM_DEBUG
  378. X            printf("shm_block=%ld shm_start=%ld\n", shm_block, shm_start);
  379. X            printf("shm_head =%ld *shm_head=%ld\n",   shm_head, *shm_head);
  380. X            printf("shm_tail =%ld *shm_tail=%ld\n",   shm_tail, *shm_tail);
  381. X            printf("num_read=%d\n\n", num_read);
  382. X#endif
  383. X        }
  384. X    }
  385. X
  386. X}
  387. X
  388. X/*---------------------------------------*/
  389. X/* die: Terminate the program gracefully */
  390. X/*---------------------------------------*/
  391. Xstatic void die()
  392. X{
  393. X    /* Deattach from shared memory */
  394. X    if (shm_block != (char *) NULL) {
  395. X        if (shmdt(shm_block) == (-1))
  396. X            fprintf(stderr, "\nERROR: producer, shmdt() failed, errno=%d\n",
  397. X                                                                      errno);
  398. X    }
  399. X
  400. X    fputs( "\nproducer: Program terminated\n", stdout);
  401. X
  402. X    exit(0);
  403. X}
  404. X
  405. X/*----------------------------------------------------*/
  406. X/* prod_arguments: Process the command line arguments */
  407. X/*      TRUE  : errors detected                       */
  408. X/*      FALSE : no errors                             */
  409. X/*----------------------------------------------------*/
  410. Xstatic int prod_arguments(argc, argv, shm_id, shm_size)
  411. Xint   argc;
  412. Xchar *argv[];
  413. Xint  *shm_id, *shm_size;
  414. X{
  415. X    int ch;                          /* argument option */
  416. X    int rcode;                       /* return code */
  417. X    FILE *shm_info_fid;              /* shared memory info file descriptor */
  418. X
  419. X    void helpscreen();
  420. X
  421. X    *shm_id   = 0;
  422. X    *shm_size = 0;
  423. X
  424. X    rcode = FALSE;
  425. X    do {
  426. X        /* Get the next command line argument */
  427. X        ch = getopt(argc, argv, "o:");
  428. X
  429. X        /* Process the argument */
  430. X        switch (ch) {
  431. X
  432. X        case EOF:  /* no more arguments */
  433. X            break;
  434. X
  435. X        case 'o':  /* shared memory information filename */
  436. X            shm_info_fid = fopen(optarg, "r");
  437. X            if (shm_info_fid == (FILE *) NULL) {
  438. X                fprintf(stdout, "\nCan not open info file '%s'\n", optarg);
  439. X                rcode = TRUE;
  440. X                break;
  441. X            }
  442. X
  443. X            if (fscanf(shm_info_fid, "%d%d", shm_id, shm_size) != 2) {
  444. X                fputs("\nCan not parse info file\n", stdout);
  445. X                rcode = TRUE;
  446. X                break;
  447. X            }
  448. X
  449. X            if (fclose(shm_info_fid) != 0) {
  450. X                fputs("\nCan not close info file\n", stdout);
  451. X                rcode = TRUE;
  452. X            }
  453. X            break;
  454. X
  455. X        case '?':  /* error */
  456. X            helpscreen();
  457. X            rcode = TRUE;
  458. X            break;
  459. X
  460. X        default :  /* safety net */
  461. X            break;
  462. X        }
  463. X    } while (ch != EOF);
  464. X
  465. X    /* Check the shared memory info file name was specified */
  466. X    if ((!rcode)  &&  (*shm_id <= 0  ||  *shm_size <= 0)) {
  467. X        helpscreen();
  468. X        fprintf(stderr, "\nERROR: Missing -o parameter\n");
  469. X        rcode = TRUE;
  470. X    }
  471. X
  472. X    return (rcode);
  473. X
  474. X}
  475. X
  476. X/*--------------------------------------------------*/
  477. X/* helpscreen: Display a help message on the screen */
  478. X/*--------------------------------------------------*/
  479. Xstatic void helpscreen()
  480. X{
  481. X    fputc('\n', stderr);
  482. X    fputs("ERROR: Invalid usage: producer\n", stderr);
  483. X    fputs("       -o shared memory info file name\n", stderr);
  484. X}
  485. X
  486. X/*---------------------------------------------------*/
  487. X/* prod_signal: Sets up the handling of all signals. */
  488. X/*      TRUE  : errors detected                      */
  489. X/*      FALSE : no errors                            */
  490. X/*---------------------------------------------------*/
  491. Xstatic int prod_signal(sig_function)
  492. Xvoid (*sig_function)();
  493. X{
  494. X    void (*sig_handle)();       /* signal handler */
  495. X
  496. X    sig_handle = signal(SIGINT, sig_function);
  497. X    if ((int) sig_handle == (-1)) {
  498. X        fprintf(stderr, "\nERROR: signal(SIGINT) fails, errno=%d\n", errno);
  499. X        return (TRUE);
  500. X    }
  501. X
  502. X    sig_handle = signal(SIGQUIT, sig_function);
  503. X    if ((int) sig_handle == (-1)) {
  504. X        fprintf(stderr, "\nERROR: signal(SIGQUIT) fails, errno=%d\n", errno);
  505. X        return (TRUE);
  506. X    }
  507. X
  508. X    sig_handle = signal(SIGHUP, sig_function);
  509. X    if ((int) sig_handle == (-1)) {
  510. X        fprintf(stderr, "\nERROR: signal(SIGHUP) fails, errno=%d\n", errno);
  511. X        return (TRUE);
  512. X    }
  513. X
  514. X    sig_handle = signal(SIGTERM, sig_function);
  515. X    if ((int) sig_handle == (-1)) {
  516. X        fprintf(stderr, "\nERROR: signal(SIGTERM) fails, errno=%d\n", errno);
  517. X        return (TRUE);
  518. X    }
  519. X
  520. X    return (FALSE);
  521. X}
  522. END_OF_producer.c
  523. if test 10418 -ne `wc -c <producer.c`; then
  524.     echo shar: \"producer.c\" unpacked with wrong size!
  525. fi
  526. # end of overwriting check
  527. fi
  528. if test -f consumer.c -a "${1}" != "-c" ; then 
  529.   echo shar: Will not over-write existing file \"consumer.c\"
  530. else
  531. echo shar: Extracting \"consumer.c\" \(13115 characters\)
  532. sed "s/^X//" >consumer.c <<'END_OF_consumer.c'
  533. X/****consumer
  534. X
  535. X    Synopsis.
  536. X        Program to read a circular buffer stored in shared memory.
  537. X        Another process is expected to write the data into the shared memory
  538. X        (ie producer).
  539. X
  540. X    Usage.
  541. X         consumer -i shared memory info file name -s shared memory size
  542. X                  -o output file name
  543. X
  544. X    Function.
  545. X
  546. X    Routine description.
  547. X
  548. X         shm_head | shm_tail | ................. |
  549. X
  550. X                     shm_head - will offset to the next free space
  551. X                     shm_tail - will offset to the next new data
  552. X                           Note: if shm_head = shm_tail then empty
  553. X
  554. X    Notes.
  555. X        1) If there is no data in the shared memory circular buffer then
  556. X           give up the time-slice to another process.  In order to do this
  557. X           call the time function which is a kernal call that will retrieve
  558. X           the current time.  After a kernal call is about to complete, the
  559. X           operating system does a process priority scheduling check.  The
  560. X           hope here is another process will be scheduled and hopefully it
  561. X           will be the process to write into the circular buffer (ie producer).
  562. X           There is no guarantee it will be the desired process but it will
  563. X           at least improve the efficiency and throughput of the system which
  564. X           will beneficial to everyone.
  565. X
  566. X    Update Log.
  567. X    1990 Jun 12    Robert Wolf
  568. X                   56 Shadberry Drive
  569. X                   North York, Ontario
  570. X                   M2H 3C8   Canada
  571. X                   (416) 490-8493
  572. X
  573. X    Legal Note.
  574. X        This software is freely given to the world with the following
  575. X        conditions:
  576. X        1) No change to the code and/or the comments must be done.  It must be
  577. X           distributed exactly as is.  Any desired changes should be
  578. X           sent to me and I will consider it for update.
  579. X        2) This software may not be published in any form with out my
  580. X           express written consent.
  581. X      
  582. X****/
  583. X
  584. X#include <stdio.h>
  585. X#include <signal.h>
  586. X#include <fcntl.h>
  587. X#include <errno.h>
  588. X#include <sys/types.h>
  589. X#include <sys/stat.h>
  590. X#include <sys/ipc.h>
  591. X#include <sys/shm.h>
  592. X
  593. Xextern char *shmat();
  594. Xextern long  time();
  595. Xextern int   getopt();
  596. Xextern char *optarg;
  597. X
  598. X#ifndef TRUE                        /* True */
  599. X#define TRUE 1
  600. X#endif
  601. X
  602. X#ifndef FALSE                       /* False */
  603. X#define FALSE 0
  604. X#endif
  605. X
  606. X#ifndef EOS                         /* End of string */
  607. X#define EOS '\0'
  608. X#endif
  609. X
  610. X#ifndef EOF                         /* End of file */
  611. X#define EOF (-1)
  612. X#endif
  613. X
  614. X#define MAX_FILE_SIZE   60          /* Maximum file name size */
  615. X#define MIN_SHM_SIZE   (2L * sizeof(long) + 8L)   /* min. shared memory size */
  616. X
  617. Xstatic int  shm_id = (-1);                  /* shared memory id */
  618. Xstatic char *shm_block = (char *) NULL;     /* shared memory block */
  619. X
  620. Xstatic char shm_info_fname[MAX_FILE_SIZE+1]; /* shared memory info file name */
  621. X
  622. Xint main(argc, argv)
  623. Xint   argc;
  624. Xchar *argv[];
  625. X{
  626. X    int  shm_size;                        /* shared memory size */
  627. X    char output_fname[MAX_FILE_SIZE+1];   /* output file name */
  628. X    int  output_fid;                      /* output file descriptor */
  629. X    FILE *shm_info_fid;                   /* shared memory info file desc. */
  630. X    int  shm_perm;                        /* shared memory permissions */
  631. X    int  shm_flags;                       /* shared memory operation flags */
  632. X    int  shm_key;                         /* shared memory key */
  633. X    int  num_written;                     /* number of bytes written */
  634. X    char *shm_addr;                       /* shared memory address selection */
  635. X    int  shm_aflags;                      /* shared memory attaching flags */
  636. X    char *shm_start;                      /* start of shared memory */
  637. X    long *shm_head, *shm_tail;          /* head/tail offsets of shared memory */
  638. X    int  avail_data;                      /* available data */
  639. X
  640. X    void die();
  641. X
  642. X    /* Process the command line arguments */
  643. X    if (cons_arguments(argc, argv, &shm_size, output_fname))
  644. X                       
  645. X        die();
  646. X
  647. X    /* Setup the signal handling */
  648. X    if (cons_signal(die))
  649. X        die();
  650. X
  651. X    /* Open the output file */
  652. X    if (output_fname[0] == EOS)
  653. X        output_fid = 1;                /* ie standard output */
  654. X    else {
  655. X        output_fid = open(output_fname, O_WRONLY);
  656. X        if (output_fid == (-1))
  657. X            output_fid = creat(output_fname, S_IRUSR | S_IWUSR);
  658. X        if (output_fid < 0) {
  659. X            fprintf(stderr, "\nERROR: Can not open output file : %s\n",
  660. X                                                                 output_fname);
  661. X            die();
  662. X        }
  663. X    }
  664. X
  665. X    /* Create the shared memory segment */
  666. X    shm_perm =  SHM_R       |  SHM_W       |
  667. X               (SHM_R >> 3) | (SHM_W >> 3) |
  668. X               (SHM_R >> 6) | (SHM_W >> 6);
  669. X    shm_flags = IPC_CREAT | IPC_EXCL | shm_perm;
  670. X    shm_key = 1;
  671. X    do {
  672. X        shm_id = shmget(shm_key, shm_size, shm_flags);
  673. X        if (shm_id == (-1)) {
  674. X            if (errno != EEXIST) {
  675. X                fputs("\nconsumer: ERROR: shmget(), failed, ", stderr);
  676. X                fprintf(stderr, "errno=%d\n", errno);
  677. X                die();
  678. X            }
  679. X            shm_key++;
  680. X        }
  681. X    } while (shm_id == (-1));
  682. X
  683. X    /* Attach to the shared memory data */
  684. X    shm_addr = (char *) 0;               /* allow o/s to select the address */
  685. X    shm_aflags = 0;                      /* read/write mode */
  686. X    shm_block = shmat(shm_id, shm_addr, shm_aflags);
  687. X    if ((int) shm_block == (-1)) {
  688. X         fputs("\nERROR: consumer, can not attach to shared memory, ", stderr);
  689. X         fprintf(stderr, "errno=%d\n", errno);
  690. X         shm_block = (char *) NULL;
  691. X         die();
  692. X    }
  693. X
  694. X    /* Output the shared memory id and shared memory size */
  695. X    /* to the shared memory informatio file               */
  696. X    shm_info_fid = fopen(shm_info_fname, "w");
  697. X    if (shm_info_fid == (FILE *) NULL) {
  698. X         fputs("\nERROR: Could not open shared memory info file, ", stderr);
  699. X         fprintf(stderr, "errno=%d\n", errno);
  700. X         die();
  701. X    }
  702. X
  703. X    fprintf(shm_info_fid, "%d %d\n", shm_id, shm_size);
  704. X
  705. X    if (fclose(shm_info_fid) != 0) {
  706. X         fputs("\nERROR: Could not open shared memory info file, ", stderr);
  707. X         fprintf(stderr, "errno=%d\n", errno);
  708. X         die();
  709. X    }
  710. X
  711. X    /* Setup the head and tail pointers */
  712. X    shm_head = (long *) shm_block;
  713. X    shm_tail = (long *) (shm_block + sizeof(long));
  714. X
  715. X    shm_start = shm_block + 2L * sizeof(long);
  716. X
  717. X    *shm_head = 0L;
  718. X    *shm_tail = 0L;
  719. X
  720. X#ifdef SHM_DEBUG
  721. X    printf("shm_block=%ld shm_start=%ld\n",   shm_block, shm_start);
  722. X    printf("shm_head =%ld *shm_head=%ld\n",   shm_head, *shm_head);
  723. X    printf("shm_tail =%ld *shm_tail=%ld\n\n", shm_tail, *shm_tail);
  724. X#endif
  725. X
  726. X    /* Read the port continuously */
  727. X    while (1) {
  728. X
  729. X        /* Tail pointer is equal to head pointer */
  730. X        if (*shm_tail == *shm_head)
  731. X             (void) time((long *) 0);           /* see note 1 above */
  732. X
  733. X        /* Tail pointer is behind of head pointer */
  734. X        else if (*shm_tail < *shm_head) {
  735. X            avail_data = (*shm_head) - (*shm_tail);
  736. X            num_written = write(output_fid, shm_start + (*shm_tail),
  737. X                                                                  avail_data);
  738. X            if (num_written != avail_data) {
  739. X                fprintf(stderr, "\nERROR: consumer: write() failed, errno=%d\n",
  740. X                                                                      errno);
  741. X                die();
  742. X            }
  743. X            *shm_tail += avail_data;
  744. X
  745. X        /* Tail pointer is ahead of head pointer */
  746. X        } else {
  747. X            avail_data = shm_size - 2L * sizeof(long) - (*shm_tail) + 1L;
  748. X            num_written = write(output_fid, shm_start + *shm_tail, avail_data);
  749. X            if (num_written != avail_data) {
  750. X                fprintf(stderr, "\nERROR: consumer: write() failed, errno=%d\n",
  751. X                                                                      errno);
  752. X                die();
  753. X            }
  754. X            *shm_tail = 0L;
  755. X        }
  756. X
  757. X    }
  758. X
  759. X}
  760. X
  761. X/*---------------------------------------*/
  762. X/* die: Terminate the program gracefully */
  763. X/*---------------------------------------*/
  764. Xstatic void die()
  765. X{
  766. X    /* Delete the shared memory info file */
  767. X    if (shm_info_fname[0] != EOS)
  768. X        unlink(shm_info_fname);
  769. X
  770. X    /* Deattach from shared memory */
  771. X    if (shm_block != (char *) NULL) {
  772. X        if (shmdt(shm_block) == (-1))
  773. X            fprintf(stderr, "\nERROR: consumer, shmdt() failed, errno=%d\n",
  774. X                                                                      errno);
  775. X    }
  776. X
  777. X    /* Remove the shared memory entity */
  778. X    if (shm_id != (-1)) {
  779. X        if (shmctl(shm_id, IPC_RMID, 0) == (-1))
  780. X            fprintf(stderr, "\nERROR: consumer, shmctl() failed, errno=%d\n",
  781. X                                                                      errno);
  782. X    }
  783. X
  784. X    fputs( "\nconsumer: Program terminated\n", stdout);
  785. X
  786. X    exit(0);
  787. X}
  788. X
  789. X/*----------------------------------------------------*/
  790. X/* cons_arguments: Process the command line arguments */
  791. X/*      TRUE  : errors detected                       */
  792. X/*      FALSE : no errors                             */
  793. X/*----------------------------------------------------*/
  794. Xstatic int cons_arguments(argc, argv, shm_size, output_fname)
  795. Xint   argc;
  796. Xchar *argv[];
  797. Xint  *shm_size;
  798. Xchar  output_fname[];
  799. X{
  800. X    int ch;                          /* argument option */
  801. X    int rcode;                       /* return code */
  802. X
  803. X    static char msg_too_big[] = "\nERROR: -%c parameter is too large\n";
  804. X    static char msg_invalid[] = "\nERROR: -%c parameter invalid value\n";
  805. X    static char msg_missing[] = "\nERROR: Missing -%c parameter\n";
  806. X
  807. X    void helpscreen();
  808. X
  809. X    shm_info_fname[0] = EOS;
  810. X    *shm_size         = 0;
  811. X    output_fname[0]   = EOS;
  812. X
  813. X    rcode = FALSE;
  814. X    do {
  815. X        /* Get the next command line argument */
  816. X        ch = getopt(argc, argv, "i:s:o:");
  817. X
  818. X        /* Process the argument */
  819. X        switch (ch) {
  820. X
  821. X        case EOF:  /* no more arguments */
  822. X            break;
  823. X
  824. X        case 'i':  /* shared memory info file name */
  825. X            if (strlen(optarg) > MAX_FILE_SIZE) {
  826. X                fprintf(stderr, msg_too_big, ch);
  827. X                rcode = TRUE;
  828. X            } else
  829. X                strcpy(shm_info_fname, optarg);
  830. X            break;
  831. X
  832. X        case 's':  /* shared memory size */
  833. X            if (sscanf(optarg, "%d", shm_size) != 1  ||
  834. X                                                  *shm_size < MIN_SHM_SIZE) {
  835. X                fprintf(stderr, msg_invalid, ch);
  836. X                rcode = TRUE;
  837. X                break;
  838. X            }
  839. X
  840. X            break;
  841. X
  842. X        case 'o':  /* output file name */
  843. X            if (strlen(optarg) > MAX_FILE_SIZE) {
  844. X                fprintf(stderr, msg_too_big, ch);
  845. X                rcode = TRUE;
  846. X            } else
  847. X                strcpy(output_fname, optarg);
  848. X            break;
  849. X
  850. X        case '?':  /* error */
  851. X            helpscreen();
  852. X            rcode = TRUE;
  853. X            break;
  854. X
  855. X        default :  /* safety net */
  856. X            break;
  857. X        }
  858. X    } while (ch != EOF);
  859. X
  860. X    /* Check the shared memory info file name was specified */
  861. X    if ((!rcode)  &&  shm_info_fname[0] == EOS) {
  862. X        helpscreen();
  863. X        fprintf(stderr, msg_missing, 'i');
  864. X        rcode = TRUE;
  865. X    }
  866. X
  867. X    /* Check the shared memory size was specified */
  868. X    if ((!rcode)  &&  *shm_size <= 0) {
  869. X        helpscreen();
  870. X        fprintf(stderr, msg_missing, 's');
  871. X        rcode = TRUE;
  872. X    }
  873. X
  874. X    return (rcode);
  875. X
  876. X}
  877. X
  878. X/*--------------------------------------------------*/
  879. X/* helpscreen: Display a help message on the screen */
  880. X/*--------------------------------------------------*/
  881. Xstatic void helpscreen()
  882. X{
  883. X    fputc('\n', stderr);
  884. X    fputs("ERROR: Invalid usage: consumer\n", stderr);
  885. X    fputs("       -i shared memory info file name\n", stderr);
  886. X    fputs("       -s shared memory size\n", stderr);
  887. X    fputs("       -o output file name\n", stderr);
  888. X}
  889. X
  890. X/*---------------------------------------------------*/
  891. X/* cons_signal: Sets up the handling of all signals. */
  892. X/*      TRUE  : errors detected                      */
  893. X/*      FALSE : no errors                            */
  894. X/*---------------------------------------------------*/
  895. Xstatic int cons_signal(sig_function)
  896. Xvoid (*sig_function)();
  897. X{
  898. X    void (*sig_handle)();       /* signal handler */
  899. X
  900. X    sig_handle = signal(SIGINT, sig_function);
  901. X    if ((int) sig_handle == (-1)) {
  902. X        fprintf(stderr, "\nERROR: signal(SIGINT) fails, errno=%d\n", errno);
  903. X        return (TRUE);
  904. X    }
  905. X
  906. X    sig_handle = signal(SIGQUIT, sig_function);
  907. X    if ((int) sig_handle == (-1)) {
  908. X        fprintf(stderr, "\nERROR: signal(SIGQUIT) fails, errno=%d\n", errno);
  909. X        return (TRUE);
  910. X    }
  911. X
  912. X    sig_handle = signal(SIGHUP, sig_function);
  913. X    if ((int) sig_handle == (-1)) {
  914. X        fprintf(stderr, "\nERROR: signal(SIGHUP) fails, errno=%d\n", errno);
  915. X        return (TRUE);
  916. X    }
  917. X
  918. X    sig_handle = signal(SIGTERM, sig_function);
  919. X    if ((int) sig_handle == (-1)) {
  920. X        fprintf(stderr, "\nERROR: signal(SIGTERM) fails, errno=%d\n", errno);
  921. X        return (TRUE);
  922. X    }
  923. X
  924. X    return (FALSE);
  925. X}
  926. END_OF_consumer.c
  927. if test 13115 -ne `wc -c <consumer.c`; then
  928.     echo shar: \"consumer.c\" unpacked with wrong size!
  929. fi
  930. # end of overwriting check
  931. fi
  932. echo shar: End of shell archive.
  933. exit 0
  934.