Memory Mapped Files

Memory Mapped Files

  1. Memory Mapping

Write two small pieces of code that run as different processes, yet they share part of
their memory. The memory is shared by mapping it to the same file. Create a file 100
bytes in size which is big enough for this purpose. You can use dd if=/dev/zero
of=sharedfile count=10 bs=10 to create the file.
The one process, we call sender opens the file and memory maps it to an array. Thenmodifies it by reading user input and copying the user inputto the mapped array. After every modification it sends (with kill(2)) a SIGUSR signalto the other process. Repeats the cycle of reading, copying and sending a signal until themapped array is full and then exits after sending a kill signal SIGTERM to terminate theother processes. The program takes one argument, the pidof the other process.
The other process which we call receiver, prints out its pidto be used in the
command line of the other process, maps the same file and then sets up a signal handler
after which it blocks with sigsuspenduntil it receives the signal SIGUSR. All the new characters that were added to the mapped array are printed tothe standard output. Make sure that SIGUSR is blocked going into sigsuspendandunblocks in sigsuspend. The process catches the SIGTERM signal and exits gracefully.
Submit one tar file that includes as first target all that compiles both programs and
creates the shared file, appropriate targets to compile the components of the assignment, a
target clean to clean up, and a target tar to create the tar file.

It has to be pure C code running on gcc (GCC). Please make sure the program runs correctly on the VM provided.

 Solution

 receiver.c 

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <signal.h>

#include <sys/signal.h>

#include <sys/mman.h>

#include <sys/types.h>

#include <fcntl.h>

#include <errno.h>

#include <string.h>

/* the name of the shared file and the size */

#define SHARED_FILE “sharedfile”

#define FILE_SIZE   100

/* mark which signal has just happend.

* This is used to let the signal hander notify the main function

* to print the content in the mmap array or to terminate. */

static unsigned sigusr1 = 0;

static unsigned sigterm = 0;

voidsig_handler(intsigno) {

if (signo == SIGUSR1) {

sigusr1 = 1;

}

if (signo == SIGTERM) {

sigterm = 1;

}

}

int main() {

int fid;

char *arr; /* the array to map the file into */

unsigned count;

structsigaction act;

sigset_t mask, omask;

printf(“receiver pid=%d. receiving…\n\n”, getpid());

/* map the file in read mode into an array using mmap */

fid = open(SHARED_FILE, O_RDONLY);

if (fid < 0) {

fprintf(stderr, “could not open file %s to read [%d]\n”, SHARED_FILE, errno);

exit(errno);

}

arr = mmap(NULL, FILE_SIZE, PROT_READ, MAP_SHARED, fid, 0);

if (arr == MAP_FAILED) {

fprintf(stderr, “could not map file %s [%d]\n”, SHARED_FILE, errno);

exit(errno);

}

close(fid);

/* setup the SIGUSR1 and SIGTERM handler to receive notification

* from the sender and terminate gracefully */

memset(&act, 0, sizeof(act));

act.sa_handler = sig_handler;

if (sigaction(SIGUSR1, &act, NULL) < 0 || sigaction(SIGTERM, &act, NULL) < 0) {

fprintf(stderr, “could not create signal handler [%d]\n”, errno);

exit(errno);

}

/* read until the reader send SIGTERM */

count = 0;

sigemptyset(&mask);

sigaddset(&mask, SIGUSR1);

sigaddset(&mask, SIGTERM);

sigprocmask(SIG_BLOCK, &mask, &omask);

while (1) {

if(sigusr1 > 0) {

/* print the characters added into the array */

while (count < FILE_SIZE &&arr[count] != 0) {

printf(“%c”, arr[count]);

count ++;

}

sigusr1 = 0;

}

if (sigterm> 0) {

/* the user wants to quit the program, quit gracefully */

sigterm = 0;

break;

}

sigsuspend(&omask);

}

/* quit the program gracefully */

fflush(stdout);

printf(“\n\nsender is done. quitting gracefully..\n”);

munmap(arr, FILE_SIZE);

sigprocmask(SIG_UNBLOCK, &mask, NULL);

return 0;

}

  sender.c 

#include <unistd.h>

#include <stdio.h>

#include <sys/signal.h>

#include <sys/mman.h>

#include <sys/types.h>

#include <signal.h>

#include <stdlib.h>

#include <fcntl.h>

#include <errno.h>

#include <string.h>

/* the name of the shared file and the size */

#define SHARED_FILE “sharedfile”

#define FILE_SIZE   100

int main(intargc, char *argv[]) {

pid_t receiver;

int fid;

char *arr; /* the array to map the file into */

unsigned count;

/* get the PID of the receiver from the argument */

if (argc != 2) {

fprintf(stderr, “Usage: %s receiver_pid\n”, argv[0]);

exit(-1);

}

receiver = (pid_t) atoi(argv[1]);

/* open the shared file and mapped into an array using mmap */

fid = open(SHARED_FILE, O_RDWR);

if (fid < 0) {

fprintf(stderr, “could not open file %s to write [%d]\n”, SHARED_FILE, errno);

exit(errno);

}

arr = mmap(NULL, FILE_SIZE, PROT_WRITE, MAP_SHARED, fid, 0);

if (arr == MAP_FAILED) {

fprintf(stderr, “could not map file %s [%d]\n”, SHARED_FILE, errno);

exit(errno);

}

close(fid);

/* clean the file before sending anything */

memset(arr, 0, FILE_SIZE);

/* read user’s input and send it to the array.

* send SIGUSR1 to receiver every time.

* When the array is full, send SIGTERM to the receiver. */

count = 0;

printf(“Enter up to %d characters (including \\n):\n”, FILE_SIZE);

while (count < FILE_SIZE) {

intch = fgetc(stdin);

if (ch == EOF) { /* user terminates the input before the limit */

break;

}

/* save the character in the array and notify the receiver */

arr[count] = ch;

count ++;

if (kill(receiver, SIGUSR1) < 0) {

fprintf(stderr, “could not send SIGUSR1 to receiver %d [%d]\n”, receiver, errno);

break;

}

}

/* the array is full, terminate after cleanning up the mapping */

kill(receiver, SIGTERM);

munmap(arr, FILE_SIZE);

return 0;

}