Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * @file lastmsg.c
- * @author Ivan Pryakin
- * @date 10.12.2013
- *
- * @brief Main file
- *
- * @details This program takes creates a new shared memory segement. Its key can be specified with -i option, by default it is equal
- * to student id. If -c option is given, it creates a new shared memory segment and attaches structure 'myshm' to it.
- * If [Message] is specified it writes this string to shared memory segment, but before outputs whatever string that was
- * there before + new line character. If -d option is specified, it deattaches and removes memory segment and outputs
- * whatever string that was in there before.
- **/
- #include <stdio.h>
- #include <sys/shm.h>
- #include <seqev.h>
- #include <assert.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <string.h>
- #include <signal.h>
- #define MAX_DATA (50) /**< maximum length of a message */
- #define PERMISSION (0600) /**< permissions for shared memory segment */
- #define DEFAULT_KEY (1028223) /**< default key for shared memory segment */
- static char* program; /**< program name (used only for usage() function) */
- struct myshm {
- /* state:
- * false = OK
- * true = TERMINATING
- *
- * Its purpose is to avoid 'race conditions', i.e. when two cuncurrent processes receive SIGINT/SIGQUIT signal,
- * only one of them has to free resources.
- */
- bool state;
- char data[MAX_DATA];
- };
- /* holds identifiers for sharedmemory segment/event counter/sequencer */
- struct shm_keys
- {
- int shmid;
- eventcounter_t *event;
- sequencer_t *sequencer;
- };
- /* has two structures - one that holds data and one that holds IDs */
- struct t_sharedmemory
- {
- struct myshm *shared;
- struct shm_keys keys;
- };
- struct t_sharedmemory flags;
- /**
- * @brief this function writes how to use this program.
- * @details it is executed when an unknown option is given or no <cmd> is given. Global variable: program
- */
- static void usage(void);
- /**
- * @brief free resources
- * @details removes shared memory segment, destroys event counter/sequencer
- */
- void free_resources(void);
- /**
- * @brief signal handling
- * @details when any of the two signals arrive (SIGINT or SIGQUIT), this function will be called
- * it frees resources and quits a program with EXIT_FAILURE return value
- * @param signum - not used
- */
- void sig_handler(int signum);
- /**
- * @brief create/get shared memory segment, output the string in memory segement, overwrite it with new string
- * @details creates a new shared memory segement. Its key can be specified with -i option, by default it is equal
- * to student id. If -c option is given, it creates a new shared memory segment and attaches structure 'myshm' to it.
- * If [Message] is specified it writes this string to shared memory segment, but before outputs whatever string that was
- * there before + new line character. If -d option is specified, it deattaches and removes memory segment and outputs
- * whatever string that was in there before. Main function uses declared structure with name 'flags'.
- */
- int main (int argc, char **argv)
- {
- /* if SIGINT or SIGQUIT signal arrives, call function 'sig_handler' */
- signal(SIGINT, sig_handler);
- signal(SIGQUIT, sig_handler);
- program = argv[0];
- /* keys for shared memory segment/event counter/sequencer */
- key_t shm_id = DEFAULT_KEY;
- key_t evn_id = DEFAULT_KEY+1;
- key_t seq_id = DEFAULT_KEY+2;
- /* message to be written to shared memory segment*/
- char message[MAX_DATA];
- /* for syncronization */
- int ticket = -1;
- /* for options/argument handling */
- char c;
- char *end;
- bool create = false;
- bool delete = false;
- /* options/argument handling */
- while ((c = getopt (argc, argv, "i:cd")) != -1)
- {
- switch (c)
- {
- case 'i':
- shm_id = (key_t) strtol(optarg, &end, 10);
- evn_id = (key_t) (shm_id + 1);
- seq_id = (key_t) (evn_id + 1);
- if (*end)
- {
- (void)fprintf(stderr, "%s: error converting -i argument to long integer\n", program);
- return EXIT_FAILURE;
- }
- break;
- case 'c':
- create = true;
- break;
- case 'd':
- delete = true;
- break;
- case '?':
- usage();
- return EXIT_FAILURE;
- default:
- assert(0);
- }
- }
- if (create && delete)
- {
- usage();
- return EXIT_FAILURE;
- }
- /* on delete no message should be written to shared memory */
- if (delete)
- {
- message[0] = '\0';
- }
- else if (optind != argc) /* if message was given, copy it to variable 'message'*/
- {
- strncpy(message, argv[optind], MAX_DATA-1);
- if (strlen(argv[optind]) > MAX_DATA-1)
- message[MAX_DATA] = '\0';
- }
- if (!(create || delete) && message[0] == '\0')
- {
- usage();
- return EXIT_FAILURE;
- }
- /* get a shared memory region */
- flags.keys.shmid = shmget (shm_id, sizeof(*flags.shared), IPC_CREAT | PERMISSION);
- if (flags.keys.shmid == -1)
- {
- (void)fprintf(stderr, "%s: error creating shared memory segment\n", program);
- return EXIT_FAILURE;
- }
- /* attach shared memory segment to the address space of the calling process */
- flags.shared = shmat(flags.keys.shmid, NULL, 0);
- if (flags.shared == (struct myshm *)-1)
- {
- (void)fprintf(stderr, "%s: error attaching memory segment\n", program);
- return EXIT_FAILURE;
- }
- /* create event counter */
- flags.keys.event = create_eventcounter(evn_id);
- if (flags.keys.event == NULL)
- {
- (void)fprintf(stderr, "%s: error creating eventcounter\n", program);
- return EXIT_FAILURE;
- }
- /* create sequencer */
- flags.keys.sequencer = create_sequencer(seq_id);
- if (flags.keys.sequencer == NULL)
- {
- (void)fprintf(stderr,"%s: error creating sequencer\n", program);
- return EXIT_FAILURE;
- }
- /* get a ticket and wait if neccessary */
- ticket = sticket(flags.keys.sequencer);
- eawait(flags.keys.event, ticket);
- if (!create)
- {
- fflush(stdout);
- (void)fprintf(stdout, "%s\n", flags.shared->data);
- }
- if ((message[0] != '\0') && (!delete))
- strcpy(flags.shared->data, message);
- /* critical section end */
- /* advance eventcounter, so that other concurrent process (that is currently waiting)
- * can start execution of critical section
- */
- if (delete)
- {
- free_resources();
- return EXIT_SUCCESS;
- }
- //(void) fprintf(stderr,"eventcounter=%ld ticket=%d message=%s\n\n", eread(flags.keys.event), ticket, message);
- eadvance(flags.keys.event);
- return EXIT_SUCCESS;
- }
- static void usage(void)
- {
- (void) fprintf(stderr, "Usage: %s [-i id] [-c|-d] [\"Message\"]\n", program);
- }
- void free_resources(void)
- {
- /* detach from shared memory */
- if (shmdt(flags.shared) == -1)
- {
- (void)fprintf(stderr, "%s: error detaching shared memory segment\n", program);
- exit(EXIT_FAILURE);
- }
- /* mark segment to be destroyed */
- if (shmctl(flags.keys.shmid, IPC_RMID, NULL) == -1)
- {
- (void)fprintf(stderr, "%s: error removing shared memory segment\n", program);
- exit(EXIT_FAILURE);
- }
- /* remove event counter */
- if (rm_eventcounter(flags.keys.event) == -1)
- {
- (void)fprintf(stderr, "%s: error removing event counter\n", program);
- exit(EXIT_FAILURE);
- }
- /* remove sequence counter*/
- if (rm_sequencer(flags.keys.sequencer) == -1)
- {
- (void)fprintf(stderr, "%s: error removing sequencer\n", program);
- exit(EXIT_FAILURE);
- }
- }
- void sig_handler(int signum)
- {
- /* avoid race conditions */
- if (flags.shared->state) return;
- flags.shared->state = true;
- /* free resources and exit with error */
- free_resources();
- (void) fprintf(stderr, "%s:signal caught...terminating\n", program);
- exit(EXIT_FAILURE);
- }
Advertisement
Add Comment
Please, Sign In to add comment