By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
431,871 Members | 2,418 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 431,871 IT Pros & Developers. It's quick & easy.

Memory mapped, forks and unnamed semaphores- doesn't always give the same output

P: n/a
Hi there,

I have an assignment to invert a ppm image, with a header of 4 lines (P6\nwidth\nheight\ndepth\n),and we have to do a shared memory version and a memory mapped file (MMF) too.
This version is basically equal to the SM version, whick worker, but with mmf, but the final image although is inverted it shows a small black line and a grey two, in the end, even the file has the same size ...
The more stranger is that yesterdar the output was correct and now I run and it's not. I think it's a problem with children not actually exit from their function, but I've tried so many changes and no success.

I'll leave you the code instead of the links, perhaps it's easier to see:

Expand|Select|Wrap|Line Numbers
  1. //###################################### MMF_INVERTER.C (main) #########################################
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <sys/ipc.h>
  7. #include <sys/shm.h>
  8. #include <sys/fcntl.h>
  9. #include <semaphore.h>
  10. #include <sys/types.h>
  11. #include <sys/wait.h>
  12. #include <sys/mman.h>
  13. #include <sys/stat.h>
  14. #include <errno.h>
  15. #include <signal.h>
  16.  
  17. #include "timeprofiler.h"
  18. #include "ppmtools.h"
  19.  
  20. #define    FILE_MODE    (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
  21.  
  22. //Global vars:
  23. int shmids[2];
  24. //################# On shared memory goes #####################
  25. //To share unnamed semaphores between processes, they must be allocated in a shared memory.
  26. mem_struct *sh_mm;
  27. int *total_lines, *processed_lines, *next_line, *buf_vars;
  28. //###################################################################
  29. //unnamed semaphores
  30. sem_t *mutex1, *mutex2, *mutex3, *sem_remaining_lines;
  31. pid_t *workersPID;
  32. header *h;
  33. char *data; //mmf that will hold the image
  34. int last_index;
  35.  
  36. int main(int argc, char *argv[]) {
  37.     int i, fdout,id;
  38.     pixel *row;
  39.     double start, stop, startms, stopms;
  40.     struct stat sbuf;
  41.  
  42.     if (argc < 3) {
  43.         printf("Incorrect usage.\nPlease use \"./invert input_filename.ppm output_filename.ppm\"\n");
  44.         return -1;
  45.     }
  46.  
  47.  
  48.     printf("Opening input file [%s]\n", argv[1]);
  49.     FILE *fpin = fopen(argv[1], "r");
  50.     if (fpin == NULL) {
  51.         printf("Could not open input file\n");
  52.         return -1;
  53.     }
  54.  
  55.     printf("Opening output file [%s]\n", argv[2]);
  56.     FILE *fpout = fopen(argv[2], "w");
  57.     if (fpout == NULL) {
  58.         printf("Could not open output file\n");
  59.         return -1;
  60.     }
  61.  
  62.     printf("Getting header\n");
  63.     h = getImageHeader(fpin);
  64.     if (h == NULL) {
  65.         printf("Error getting header from file\n");
  66.         return -1;
  67.     }
  68.     printf("Got file Header: %s - %u x %u - %u\n", h->type, h->width, h->height, h->depth);
  69.  
  70.     init();
  71.  
  72.     //start timer
  73.     start = getCurrentTimeMicro();
  74.     startms = getCurrentTimeMili();
  75.     printf("Saving header to output file\n");
  76.     if (writeImageHeader(h, fpout) == -1) {
  77.         printf("Could not write to output file\n");
  78.         return -1;
  79.     }
  80.  
  81.     last_index = (int)ftell(fpout);
  82.     //printf("offset after header= %d\n",last_index);
  83.  
  84.     //alloc mem space for one row (width * size of one pixel struct)
  85.     row = malloc(h->width * sizeof (pixel));
  86.  
  87.     /*Create a copy of the original image to the output file, which will be inverted*/
  88.     printf("Starting work\n");
  89.     for (i = 0; i < h->height; i++) {
  90.         printf("Reading row... ");
  91.         if (getImageRow(h->width, row, fpin) == -1) {
  92.             printf("Error while reading row\n");
  93.         }
  94.         printf("Got row %d || ", (i + 1));
  95.  
  96.         printf("Saving row... ");
  97.         if (writeRow(h->width, row, fpout) == -1) {
  98.             printf("Error while reading row\n");
  99.         }
  100.         printf("Done\n");
  101.     }
  102.  
  103.     /*Open file descriptor of the ouput file.
  104.      * O_RDWR -  Read and Write operations both permitted
  105.      * O_CREAT - Create file if it doesn't already exist
  106.      * O_TRUNC - Delete existing contents of file*/
  107.     if ((fdout = open(argv[2], O_RDWR, FILE_MODE)) < 0) {
  108.         fprintf(stderr, "Can't create %s for writing\n", argv[2]);
  109.         exit(1);
  110.     }
  111.  
  112.     /*Get size of the output file*/
  113.     if (fstat(fdout, &sbuf) == -1) {
  114.         perror("Stat error ---------->\n");
  115.         exit(1);
  116.     }
  117.     //printf("Size of output file: %d\n",(int)sbuf.st_size);
  118.  
  119.     /*Maps output file to memory*/
  120.     if ((data = mmap((caddr_t) 0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0)) == (caddr_t) (-1)) {
  121.         perror("Error mmaping");
  122.         exit(EXIT_FAILURE);
  123.     }
  124.     //printf("header last index: %u\n",last_index);
  125.  
  126.     sem_wait(mutex1);
  127.     *total_lines = h->height;
  128.     *next_line = last_index;
  129.     sem_post(mutex1);
  130.  
  131.     //Creates workers
  132.     workersPID = (pid_t*) malloc(sizeof (pid_t) *((NUM_WORKERS)));
  133.     for (i = 0; i < NUM_WORKERS; i++) {
  134.         id = fork();
  135.         if (id == -1) {
  136.             printf("Error creating worker number %d\n", i);
  137.             exit(EXIT_FAILURE);
  138.         } else if (id == 0) {
  139.             workersPID[i] = getpid();
  140.             worker(i);
  141.         }
  142.     }
  143.     sem_wait(mutex2); //if unblocks, it means the inversion is finished
  144.  
  145.     printf("Cleaning up...\n");
  146.     //clean up row
  147.     free(row);
  148.     //clean up header
  149.     free(h);
  150.  
  151.     printf("Closing file pointers.\n");
  152.     fclose(fpin);
  153.     fclose(fpout);
  154.     //stop timer
  155.     stop = getCurrentTimeMicro();
  156.     stopms = getCurrentTimeMili();
  157.  
  158.     for (i = 0; i < NUM_WORKERS; i++) {
  159.         if (workersPID[i]) {
  160.             kill(workersPID[i], SIGTERM); //TODO: sigkill or sigterm?
  161.             waitpid(workersPID[i], NULL, 0);
  162.         }
  163.     }
  164.  
  165.     //unmmaps output file from memory
  166.     if((munmap(data, sbuf.st_size)==-1))
  167.     printf("munmap failed! Errno returned: %s\n",strerror(errno));
  168.     close(fdout);
  169.     terminate();
  170.  
  171.     printTimeElapsed(start, stop, "microseconds");
  172.     printTimeElapsed(startms, stopms, "miliseconds");
  173.     printf("Done!\n");
  174.  
  175.     return 0;
  176. }
  177.  
  178. void init() {
  179.  
  180.     //unnamed semaphores go, in this case, to shared memory (is it REALLY necessary or as globlal vars it'll work?)
  181.     if ((shmids[0] = shmget(IPC_PRIVATE, sizeof (mem_struct), IPC_CREAT | 0700)) == -1) {
  182.         printf("shmget to allocate mem_Struct for semaphores failed. Errno returned %s\n", strerror(errno));
  183.         exit(EXIT_FAILURE);
  184.     }
  185.     sh_mm = (mem_struct*) shmat(shmids[0], NULL, 0);
  186.     if (sem_init(&sh_mm->mutex1, 1, 1) == -1) {
  187.         printf("Error initializing semaphore mutex1.Errno returned: %s\n", strerror(errno));
  188.         exit(EXIT_FAILURE);
  189.     }
  190.     mutex1 = &sh_mm->mutex1;
  191.  
  192.     if (sem_init(&sh_mm->mutex2, 1, 0) == -1) {
  193.         printf("Error initializing semaphore mutex2.Errno returned: %s\n", strerror(errno));
  194.         exit(EXIT_FAILURE);
  195.     }
  196.     mutex2 = &sh_mm->mutex2;
  197.  
  198.     if (sem_init(&sh_mm->mutex3, 1, 1) == -1) {
  199.         printf("Error initializing semaphore mutex3.Errno returned: %s\n", strerror(errno));
  200.         exit(EXIT_FAILURE);
  201.     }
  202.     mutex3 = &sh_mm->mutex3;
  203.  
  204.     if (sem_init(&sh_mm->sem_remaining_lines, 1, h->height) == -1) {
  205.         printf("Error initializing semaphore sem_remaining_lines.Errno returned: %s\n", strerror(errno));
  206.         exit(EXIT_FAILURE);
  207.     }
  208.     sem_remaining_lines = &sh_mm->sem_remaining_lines;
  209.  
  210.  
  211.     /*Shared Memory segment for 3 integers -  MUST be like this*/
  212.     if ((shmids[1] = shmget(IPC_PRIVATE, 3 * sizeof (int), IPC_CREAT | 0700)) == -1) {
  213.         printf("shmget to allocate the 3 integers failed. Errno returned;  %s\n", strerror(errno));
  214.         exit(EXIT_FAILURE);
  215.     }
  216.     buf_vars = (int*) shmat(shmids[1], NULL, 0);
  217.     total_lines = &buf_vars[0];
  218.     processed_lines = &buf_vars[1];
  219.     next_line = &buf_vars[2];
  220.  
  221.  
  222. }
  223.  
  224. /*Worker process*/
  225. void worker(int i) {
  226.     int cur_index = 0;
  227.     //pixel *row;
  228.     //Block all signals, except SIGINT and SIGKILL which are handled
  229.     sigset_t block_ctrlc;
  230.     sigfillset(&block_ctrlc);
  231.     sigdelset(&block_ctrlc, SIGINT);
  232.     sigdelset(&block_ctrlc, SIGTERM);
  233.     sigprocmask(SIG_BLOCK, &block_ctrlc, NULL);
  234.     signal(SIGINT, handle_signal);
  235.     signal(SIGTERM, handle_signal);
  236.  
  237.     while (sem_wait(sem_remaining_lines) != -1) { //if there are still lines to read, go on
  238.         sem_wait(mutex3);
  239.         cur_index = *next_line; //current image's line
  240.         *next_line += 3 * h->width; //refreshs line for the next worker
  241.         sem_post(mutex3);
  242.         printf("WORKER %d Inverting row... \n",i);
  243.         invertRowOnMMF(3*h->width,data,cur_index);
  244.         printf("Done || \n");
  245.         sem_wait(mutex1);
  246.         *processed_lines += 1; //increases the number of inverted lines
  247.         if (*processed_lines == *total_lines) { //check if it reaches last line
  248.             sem_post(mutex2); //if so, wakes the master telling that is ready
  249.         }
  250.         sem_post(mutex1);
  251.     }
  252. }
  253.  
  254. void handle_signal(int signum) {
  255.     if (signum == SIGINT)
  256.         signal(SIGINT, handle_signal);
  257.     else
  258.         signal(SIGTERM, handle_signal);
  259.     exit(0);
  260. }
  261.  
  262. void terminate() {
  263.     int i;
  264.     /*An unnamed semaphore should be destroyed with sem_destroy()
  265.     before  the memory  in  which it is located is deallocated*/
  266.     sem_destroy(mutex1);
  267.     sem_destroy(mutex2);
  268.     sem_destroy(mutex3);
  269.     sem_destroy(sem_remaining_lines);
  270.  
  271.     //cleans up shared memory = removes shared memory segments
  272.     for (i = 0; i < 2 ;i++) {
  273.         shmctl(shmids[i], IPC_RMID, NULL);
  274.     }
  275.  
  276. }
  277.  
  278.  
and now the other .c e .h needed:

Expand|Select|Wrap|Line Numbers
  1. #include <sys/types.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <time.h>
  6. #include <sys/wait.h>
  7. #include <math.h>
  8.  
  9. #include "ppmtools.h"
  10.  
  11. #define READ_BUFFER_LEN 16
  12.  
  13. char* readType(FILE *fp) {
  14.     char buf[READ_BUFFER_LEN];
  15.     char *t;
  16.  
  17.     //get line of the file into read buffer -> type of ppm
  18.     t = fgets(buf, READ_BUFFER_LEN, fp);
  19.     //check if it reads something and if it is a P6 type
  20.     if (t == NULL) {
  21.         printf("could not read type from file\n");
  22.         return "";
  23.     }
  24.  
  25.     if (strncmp(buf, "P6\n", 3) != 0) {
  26.         printf("type is not P6\n");
  27.         return "";
  28.     } else {
  29.         printf("set type as P6\n");
  30.         //set type as P6
  31.         return "P6";
  32.     }
  33. }
  34.  
  35. unsigned int readNextHeaderValue(FILE *fp) {
  36.     char buf[READ_BUFFER_LEN];
  37.     char *t;
  38.     int r;
  39.     int value;
  40.  
  41.     printf("read next header value\n");
  42.     //load next line
  43.     t = fgets(buf, READ_BUFFER_LEN, fp);
  44.     if (t == NULL) {
  45.         printf("Error reading from file");
  46.         return 0;
  47.     }
  48.  
  49.     //read value as unsigned int
  50.     r = sscanf(buf, "%u", &value);
  51.  
  52.     //check if the read was successful
  53.     if (r != 1) {
  54.         printf("Could not read width value\n");
  55.         return 0;
  56.     } else {
  57.         return value;
  58.     }
  59. }
  60.  
  61. header* getImageHeader(FILE *fp) {
  62.     //alloc header
  63.     header* h = malloc(sizeof (header));
  64.  
  65.     //check if file pointer is null
  66.     if (fp == NULL) {
  67.         //file pointer is null
  68.         return NULL;
  69.     }
  70.  
  71.     //get type
  72.     char* type = readType(fp);
  73.     if (strcmp(type, "") != 0) {
  74.         //write type
  75.         strcpy(h->type, type);
  76.     } else {
  77.         //error reading type
  78.         return NULL;
  79.     }
  80.  
  81.     h->width = readNextHeaderValue(fp);
  82.     h->height = readNextHeaderValue(fp);
  83.     h->depth = readNextHeaderValue(fp);
  84.  
  85.     //check for successful read and valid color range
  86.     if (h->depth != 255 || h->width == 0 || h->height == 0) {
  87.         //printf("error reading values\n");
  88.         return NULL;
  89.     }
  90.  
  91.     return h;
  92. }
  93. //NOTE:
  94. // The program fails if the first byte of the image is equal to 32 (ascii for space char). because
  95. // the fscanf in eats the space (ascii 32) and the image is read with one byte less
  96.  
  97. int getImageRow(int pixelNo, pixel* row, FILE *fp) {
  98.  
  99.     int i;
  100.     byte b;
  101.     //reading line
  102.  
  103.     for (i = 0; i < pixelNo; i++) {
  104.         //set pixel values
  105.         if (fread(&row[i], sizeof (b), 3 * sizeof (b), fp) < 1)
  106.             return -1;
  107.     }
  108.  
  109.     return pixelNo;
  110. }
  111.  
  112. void invertRow(int pixelNo, pixel* row) {
  113.     pixel aux;
  114.     int i;
  115.  
  116.     //for each pixel
  117.     for (i = 0; i < pixelNo / 2; i++) {
  118.         //exchange pixel [i] with the pixel at the end minus [i]
  119.         aux = row[i];
  120.         row[i] = row[pixelNo - i - 1];
  121.         row[pixelNo - i - 1] = aux;
  122.     }
  123. }
  124.  
  125. void invertRowOnMMF(int width, char *data, int offset) {
  126.     char bytes1[3];
  127.     char bytes2[3];
  128.     int i, j, end_offset;
  129.  
  130.     //for each pixel
  131.     for (i = offset, j = 0; j < width / 2; i += 3, j += 3) {
  132.         end_offset= offset+width;
  133.         //exchange pixel [i] with the pixel at the end minus [i]
  134.         bytes1[0] = data[i]; //red
  135.         bytes1[1] = data[i + 1]; //green
  136.         bytes1[2] = data[i + 2]; //blue
  137.  
  138.         bytes2[0] = data[end_offset - j- 3]; //red
  139.         bytes2[1] = data[end_offset - j - 2]; //green
  140.         bytes2[2] = data[end_offset - j - 1]; //blue
  141.  
  142.         data[i] =     bytes2[0]; //red
  143.         data[i + 1] = bytes2[1]; //green
  144.         data[i + 2] = bytes2[2]; //blue
  145.  
  146.         data[end_offset - j - 3] = bytes1[0]; //red
  147.         data[end_offset - j - 2] = bytes1[1]; //green
  148.         data[end_offset - j - 1] = bytes1[2]; //blue
  149.     }
  150. }
  151.  
  152. int writeImageHeader(header* h, FILE* fp) {
  153.     //write header fields with newline between them
  154.     if (fprintf(fp, "%s\n%u\n%u\n%u\n", h->type, h->width, h->height, h->depth) < 1) {
  155.         return -1;
  156.     }
  157.  
  158.     return 0;
  159. }
  160.  
  161. int writeRow(int pixelNo, pixel* row, FILE* fp) {
  162.     int i, r;
  163.  
  164.     //for each pixel
  165.     for (i = 0; i < pixelNo; i++) {
  166.         //write one byte per RGB channel in pixel
  167.         r = fwrite(&row[i], sizeof (byte), 3 * sizeof (byte), fp);
  168.  
  169.         //check for errors
  170.         if (r < 1) {
  171.             return -1;
  172.         }
  173.     }
  174.  
  175.     return 0;
  176. }
  177.  
the header file:
Expand|Select|Wrap|Line Numbers
  1. //###################################### PPMTOOLS.H #######################################
  2. #include <semaphore.h>
  3.  
  4. #define NUM_WORKERS 2
  5.  
  6.  
  7. //this is a convenient typedef to better read the code.
  8. //it defines "byte" as a unsigned 8bit int.
  9. typedef u_int8_t  byte;
  10.  
  11. //this struct represents each pixel.
  12. //should be used to handle each pixel and maintain their correct colors.
  13. typedef struct pixel_t {
  14.     byte red;
  15.     byte green;
  16.     byte blue;
  17. }pixel;
  18.  
  19. //this is the structure used do allocate the SH_MM to the image file
  20. typedef struct {
  21.     pixel *pixel_data;
  22. } image_struct;
  23.  
  24.  
  25. typedef struct{
  26.     sem_t mutex1, mutex2, mutex3, sem_remaining_lines;
  27. }mem_struct;
  28. //this struct represents the ppm file header.
  29. //it stores the file info and will be copied to the output file.
  30. typedef struct header_t {
  31.     char type[3];
  32.     unsigned int width;
  33.     unsigned int height;
  34.     unsigned int depth;
  35. }header;
  36.  
  37. //reads a line and extracts the type of ppm file.
  38. //returns "P6" on success or "" on fail or other type of ppm file.
  39. char* readType(FILE *fp);
  40.  
  41. //reads a line and extracts the unsigned int value of that line.
  42. //returns 0 on fail and a value greater than 0 ond success.
  43. //used to read width, height and depth from the ppm file.
  44. unsigned int readNextHeaderValue(FILE *fp);
  45.  
  46. //reads file and extracts the header.
  47. //returns a header struct on success or NULL on failure.
  48. header* getImageHeader(FILE *fp);
  49.  
  50. //reads a complete row of the image based on the number of pixels given.
  51. //user should give an initialized pixel array to be filled.
  52. //returns number of pixels read on success and -1 on failure.
  53. int getImageRow(int pixelNo, pixel* row, FILE *fp);
  54.  
  55. //inverts the pixels in the given row.
  56. void invertRow(int pixelNo, pixel* row);
  57.  
  58. //writes the image header to file.
  59. //returns 0 on success and -1 on failure.
  60. int writeImageHeader(header* h, FILE* fp);
  61.  
  62. //writes a row of pixels to a file.
  63. //returns 0 on success and -1 on failure
  64. int writeRow(int pixelNo, pixel* row, FILE* fp);
  65.  
  66. //initiates sems and allocates shared memory
  67. void init();
  68. void worker(int i);
  69. void handle_signal(int signum);
  70. //cleans everything
  71. void terminate();
  72. void invertRowOnMMF(int width, char *data, int offset);
  73.  
and the makefile:
Expand|Select|Wrap|Line Numbers
  1. FLAGS = -Wall -g -lrt
  2. CC = gcc
  3. EXEC2 = MMF_inverter
  4. OBJS2 = ppmtools.o MMF_inverter.o
  5.  
  6. all: ${EXEC2} clean
  7.  
  8. clean:
  9.     rm *o
  10.  
  11. ${EXEC2}:    ${OBJS2}
  12.     ${CC} ${FLAGS} ${OBJS2} -o $@    
  13.  
  14. .c.o:
  15.     ${CC} ${FLAGS} $< -c
  16.  
  17.  
  18. # # # # # # # # #
  19.  
  20. ppmtools.o: ppmtools.c
  21. MMF_inverter.o: MMF_inverter.c
  22.  
Nov 23 '10 #1
Share this question for a faster answer!
Share on Google+

Post your reply

Sign in to post your reply or Sign up for a free account.