Guest User

lastmsg.c

a guest
Jan 16th, 2013
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.43 KB | None | 0 0
  1. /**
  2. * @file lastmsg.c
  3. * @author Ivan Pryakin
  4. * @date 10.12.2013
  5. *
  6. * @brief Main file
  7. *
  8. * @details This program takes creates a new shared memory segement. Its key can be specified with -i option, by default it is equal
  9. * to student id. If -c option is given, it creates a new shared memory segment and attaches structure 'myshm' to it.
  10. * If [Message] is specified it writes this string to shared memory segment, but before outputs whatever string that was
  11. * there before + new line character. If -d option is specified, it deattaches and removes memory segment and outputs
  12. * whatever string that was in there before.
  13. **/
  14.  
  15. #include <stdio.h>
  16. #include <sys/shm.h>
  17. #include <seqev.h>
  18. #include <assert.h>
  19. #include <stdlib.h>
  20. #include <stdbool.h>
  21. #include <string.h>
  22. #include <signal.h>
  23.  
  24. #define MAX_DATA (50) /**< maximum length of a message */
  25. #define PERMISSION (0600) /**< permissions for shared memory segment */
  26. #define DEFAULT_KEY (1028223) /**< default key for shared memory segment */
  27.  
  28. static char* program; /**< program name (used only for usage() function) */
  29.  
  30. struct myshm {
  31.     /* state:
  32.     *   false = OK
  33.     *   true  = TERMINATING
  34.     *  
  35.     * Its purpose is to avoid 'race conditions', i.e. when two cuncurrent processes receive SIGINT/SIGQUIT signal,
  36.     * only one of them has to free resources.
  37.     */
  38.     bool state;
  39.     char data[MAX_DATA];
  40. };
  41.  
  42. /* holds identifiers for sharedmemory segment/event counter/sequencer */
  43. struct shm_keys
  44. {
  45.     int shmid;
  46.     eventcounter_t *event;
  47.     sequencer_t *sequencer;
  48. };
  49.  
  50. /* has two structures - one that holds data and one that holds IDs */
  51. struct t_sharedmemory
  52. {
  53.     struct myshm *shared;
  54.     struct shm_keys keys;
  55. };
  56.  
  57. struct t_sharedmemory flags;
  58.  
  59.  
  60. /**
  61. * @brief this function writes how to use this program.
  62. * @details it is executed when an unknown option is given or no <cmd> is given. Global variable: program
  63. */
  64. static void usage(void);
  65.  
  66. /**
  67. * @brief free resources
  68. * @details removes shared memory segment, destroys event counter/sequencer
  69. */
  70. void free_resources(void);
  71.  
  72. /**
  73. * @brief signal handling
  74. * @details when any of the two signals arrive (SIGINT or SIGQUIT), this function will be called
  75. * it frees resources and quits a program with EXIT_FAILURE return value
  76. * @param signum - not used
  77. */
  78. void sig_handler(int signum);
  79.  
  80.  
  81. /**
  82. * @brief create/get shared memory segment, output the string in memory segement, overwrite it with new string
  83. * @details creates a new shared memory segement. Its key can be specified with -i option, by default it is equal
  84. * to student id. If -c option is given, it creates a new shared memory segment and attaches structure 'myshm' to it.
  85. * If [Message] is specified it writes this string to shared memory segment, but before outputs whatever string that was
  86. * there before + new line character. If -d option is specified, it deattaches and removes memory segment and outputs
  87. * whatever string that was in there before. Main function uses declared structure with name 'flags'.
  88. */
  89. int main (int argc, char **argv)
  90. {  
  91.     /* if SIGINT or SIGQUIT signal arrives, call function 'sig_handler' */
  92.     signal(SIGINT, sig_handler);
  93.     signal(SIGQUIT, sig_handler);
  94.    
  95.     program = argv[0];
  96.    
  97.     /* keys for shared memory segment/event counter/sequencer */
  98.     key_t shm_id = DEFAULT_KEY;
  99.     key_t evn_id = DEFAULT_KEY+1;
  100.     key_t seq_id = DEFAULT_KEY+2;
  101.    
  102.     /* message to be written to shared memory segment*/
  103.     char message[MAX_DATA];
  104.    
  105.     /* for syncronization */
  106.     int ticket = -1;
  107.    
  108.    
  109.     /* for options/argument handling */
  110.     char c;
  111.     char *end;
  112.     bool create = false;
  113.     bool delete = false;
  114.    
  115.     /* options/argument handling */
  116.     while ((c = getopt (argc, argv, "i:cd")) != -1)
  117.     {
  118.         switch (c)
  119.         {
  120.             case 'i':
  121.                 shm_id = (key_t) strtol(optarg, &end, 10);
  122.                 evn_id = (key_t) (shm_id + 1);
  123.                 seq_id = (key_t) (evn_id + 1);
  124.                 if (*end)
  125.                 {
  126.                     (void)fprintf(stderr, "%s: error converting -i argument to long integer\n", program);
  127.                     return EXIT_FAILURE;
  128.                 }
  129.                 break;
  130.             case 'c':
  131.                 create = true;
  132.                 break;
  133.             case 'd':
  134.                 delete = true;
  135.                 break;
  136.             case '?':
  137.                 usage();
  138.                 return EXIT_FAILURE;
  139.             default:
  140.                 assert(0);
  141.         }
  142.     }
  143.    
  144.     if (create && delete)
  145.     {
  146.         usage();
  147.         return EXIT_FAILURE;
  148.     }
  149.    
  150.     /* on delete no message should be written to shared memory */
  151.     if (delete)
  152.     {
  153.         message[0] = '\0';
  154.     }
  155.     else if (optind != argc) /* if message was given, copy it to variable 'message'*/
  156.     {
  157.         strncpy(message, argv[optind], MAX_DATA-1);
  158.         if (strlen(argv[optind]) > MAX_DATA-1)
  159.             message[MAX_DATA] = '\0';
  160.     }
  161.    
  162.     if (!(create || delete) && message[0] == '\0')
  163.     {
  164.         usage();
  165.         return EXIT_FAILURE;
  166.     }
  167.    
  168.     /* get a shared memory region */
  169.     flags.keys.shmid = shmget (shm_id, sizeof(*flags.shared), IPC_CREAT | PERMISSION);
  170.     if (flags.keys.shmid == -1)
  171.     {
  172.         (void)fprintf(stderr, "%s: error creating shared memory segment\n", program);
  173.         return EXIT_FAILURE;
  174.     }
  175.    
  176.     /* attach shared memory segment to the address space of the calling process */
  177.     flags.shared = shmat(flags.keys.shmid, NULL, 0);
  178.     if (flags.shared == (struct myshm *)-1)
  179.     {
  180.         (void)fprintf(stderr, "%s: error attaching memory segment\n", program);
  181.         return EXIT_FAILURE;
  182.     }
  183.    
  184.     /* create event counter */
  185.     flags.keys.event = create_eventcounter(evn_id);
  186.     if (flags.keys.event == NULL)
  187.     {
  188.         (void)fprintf(stderr, "%s: error creating eventcounter\n", program);
  189.         return EXIT_FAILURE;
  190.     }
  191.    
  192.     /* create sequencer */ 
  193.     flags.keys.sequencer = create_sequencer(seq_id);
  194.     if (flags.keys.sequencer == NULL)
  195.     {
  196.         (void)fprintf(stderr,"%s: error creating sequencer\n", program);
  197.         return EXIT_FAILURE;
  198.     }
  199.    
  200.     /* get a ticket and wait if neccessary */
  201.     ticket = sticket(flags.keys.sequencer);
  202.     eawait(flags.keys.event, ticket);
  203.    
  204.     if (!create)
  205.     {
  206.         fflush(stdout);
  207.         (void)fprintf(stdout, "%s\n", flags.shared->data);
  208.     }
  209.    
  210.     if ((message[0] != '\0') && (!delete))
  211.         strcpy(flags.shared->data, message);
  212.    
  213.     /* critical section end */
  214.    
  215.     /* advance eventcounter, so that other concurrent process (that is currently waiting)
  216.      * can start execution of critical section
  217.      */
  218.     if (delete)
  219.     {
  220.         free_resources();
  221.         return EXIT_SUCCESS;
  222.     }
  223.     //(void) fprintf(stderr,"eventcounter=%ld ticket=%d message=%s\n\n", eread(flags.keys.event), ticket, message);
  224.     eadvance(flags.keys.event);
  225.    
  226.    
  227.    
  228.     return EXIT_SUCCESS;
  229. }
  230.  
  231.  
  232. static void usage(void)
  233. {
  234.     (void) fprintf(stderr, "Usage: %s [-i id] [-c|-d] [\"Message\"]\n", program);
  235. }
  236.  
  237. void free_resources(void)
  238. {  
  239.     /* detach from shared memory */
  240.     if (shmdt(flags.shared) == -1)
  241.     {
  242.         (void)fprintf(stderr, "%s: error detaching shared memory segment\n", program);
  243.         exit(EXIT_FAILURE);
  244.     }
  245.    
  246.     /* mark segment to be destroyed */
  247.     if (shmctl(flags.keys.shmid, IPC_RMID, NULL) == -1)
  248.     {
  249.         (void)fprintf(stderr, "%s: error removing shared memory segment\n", program);
  250.         exit(EXIT_FAILURE);
  251.     }
  252.    
  253.     /* remove event counter */ 
  254.     if (rm_eventcounter(flags.keys.event) == -1)
  255.     {
  256.         (void)fprintf(stderr, "%s: error removing event counter\n", program);
  257.         exit(EXIT_FAILURE);
  258.     }
  259.    
  260.     /* remove sequence counter*/
  261.     if (rm_sequencer(flags.keys.sequencer) == -1)
  262.     {
  263.         (void)fprintf(stderr, "%s: error removing sequencer\n", program);
  264.         exit(EXIT_FAILURE);
  265.     }
  266. }
  267.  
  268. void sig_handler(int signum)
  269. {
  270.     /* avoid race conditions */
  271.     if (flags.shared->state) return;
  272.     flags.shared->state = true;
  273.    
  274.     /* free resources and exit with error */
  275.     free_resources();
  276.     (void) fprintf(stderr, "%s:signal caught...terminating\n", program);
  277.     exit(EXIT_FAILURE);
  278. }
Advertisement
Add Comment
Please, Sign In to add comment