Operating Systems 2 EN -- Laboratory 5 -- 2006-2007 -- info.uvt.ro

Operating Systems 2 EN -- 2006-2007 -- info.uvt.ro


Memory mapped file

edit
edit

Memory Mapped Files Memory mapped file -- Wikipedia article

Advantages

edit
  • Increased input / output performance
  • Cached data
  • Small data is read at once
  • Minimizes the system calls
  • Avoids memory copying
  • Memory sharing


Disadvantages

edit
  • Increases the page faults ration


Suitable for

edit
  • Small but often input / output operations
  • Random access
  • Sharing data between processes
  • Executable / library loading


Unsuitable for

edit
  • Sequential reading (streaming)


System call

edit
#include <sys/mman.h>
void * mmap (
    void * address,
    size_t size,
    int protection,
    int flags,
    int file_descriptor,
    off_t file_offset);
int munmap (
    void * address,
    size_t size);
  • address is a desired starting address for the mapped data. Usually it takes the value 0 and the operating system decides the actual address. It should be a multiple of the page size system parameter, obtained by getpagesize.
  • size is the number of bytes to map from the file in memory. It should be a multiple of the page size system parameter.
  • file_description is used to specify the backing file.
  • file_offset the starting position inside the file. It should be a multiple of the page size system parameter.
  • protection is a set of flags that mark the memory protection:
    • PROT_NONE -- page can not be accessed;
    • PROT_READ -- page can be read;
    • PROT_WRITE -- page can be written;
    • PROT_EXEC -- page can be executed.
  • flags is a set of miscellaneous flags:
    • MAP_FIXED -- makes the file system use only the desired address, or give an error;
    • MAP_SHARED -- if a process modifies the mapped memory, all processes could see the modification;
    • MAP_PRIVATE -- if a process modifies the mapped memory, the modification is only visible to the process;
    • MAP_LOCKED -- the mapped pages are locked by using mlock;
    • MAP_ANONYMOUS -- the mapped memory is not backed by a file, thus file descriptor and file offset are ignored;
  • return value for mmap
    • MAP_FAILED -- in case of error;
    • a valid address -- in case of success.
  • return value for munmap
    • 0 -- in case of success;
    • -1 -- in case of error;


Example

edit
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

void terminate (char * message)
{
	printf ("[EE] %s\n", message);
	exit (1);
}

void terminate_if (int condition, char * message)
{
	if (condition)
		terminate (message);
}

int main (int argc, char * * args)
{
	char * file_name;
	int file_descriptor;
	void * file_address;
	size_t file_size;
	struct stat file_stat;
	int outcome;
	int page_size;
	int page_count;
	int page_index;
	char * page;
	
	terminate_if (argc != 2, "Invalid number of arguments");
	
	file_name = args[1];
	
	file_descriptor = open (file_name, O_RDONLY);
	terminate_if (file_descriptor == -1, "Can not open the file.");
	
	outcome = fstat (file_descriptor, &file_stat);
	terminate_if (outcome == -1, "Can not stat the file.");
	
	file_size = file_stat.st_size;
	
	file_address = mmap (0, file_size, PROT_READ, MAP_PRIVATE, file_descriptor, 0);
	terminate_if (file_address == MAP_FAILED, "Can not map the file.");
	
	page_size = 16;
	page_count = file_size / page_size;
	for (page_index = 0; page_index < page_count; page_index++) {
		page = ((char *) file_address) + (page_index * page_size);
		int i;
		printf ("%8x |", page_index * page_size);
		for (i = 0; i < page_size; i++)
			printf (" %02x", (unsigned char) page[i]);
		printf (" | |");
		for (i = 0; i < page_size; i++)
			printf ("%c", ((page[i] >= 32) && (page[i] < 127) ? page[i] : ' '));
		printf ("|\n");
	}
	
	outcome = munmap (file_address, file_size);
	terminate_if (outcome != 0, "Can not unmap the file.");
	
	outcome = close (file_descriptor);
	terminate_if (outcome != 0, "Can not close the file.");
}


Non blocking streams

edit

When using non blocking operations, a read or write operation immediately returns when there is no data to be read / written.

For more information consult the man pages for:

  • open
  • read


Example

edit
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

void terminate (char * message)
{
	printf ("[EE] %s\n", message);
	exit (1);
}

void terminate_if (int condition, char * message)
{
	if (condition)
		terminate (message);
}

int main (int argc, char * * args)
{
	char * file_name;
	int file_descriptor;
	struct stat file_stat;
	int loop;
	int outcome;
	char buffer[1024];
	
	terminate_if (argc != 2, "Invalid number of arguments");
	
	file_name = args[1];
	
	file_descriptor = open (file_name, O_RDONLY | O_NONBLOCK);
	terminate_if (file_descriptor == -1, "Can not open the file.");
	
	loop = 1;
	while (loop) {
		printf ("[II] Reading...\n");
		outcome = read (file_descriptor, buffer, sizeof (buffer));
		if (outcome > 0) {
			int i;
			printf ("[>>] ");
			for (i = 0; i < outcome; i++)
				printf ("%c", buffer[i]);
			printf ("\n");
		} else {
			if ((outcome == 0) || (errno == EAGAIN)) {
				printf ("[II] Sleeping...\n");
				sleep (1);
			} else
				terminate ("Can not read from file.");
		}
	}
	
	outcome = close (file_descriptor);
	terminate_if (outcome != 0, "Can not close the file.");
}