Mapping a file into memory

  • File을 프로세스의 가상 메모리 공간으로 매핑
  • File I/O system call 사용하지 않고 접근
#include <sys/mman.h>

void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset);
  • addr : 매핑할 메모리 주소 hint(일반적으로 NULL사용)
  • length : 매핑할 길이(byte단위)
  • prot : memory protection mode
    • PROT_NONE : 접근할 수 없음
    • PROT_READ
    • PROT_WRITE
    • PROT_EXEC
  • flags : 매핑 형태와 동작 방식 지정
    • MAP_FIXED : Mapping 할 주소를 지정
    • MAP_PRIVATE : 변경된 내용이 공유 및 반영되지 않음(사본에 작업) 
    • MAP_SHARED : Mapping도니 내용이 공유
  • fd : 매핑할 파일의 file descriptor
  • offset : 매핑할 시작 지점을 지정하는 offset(page size의 배수여야 함)
  • return : 할당된 메모리 주소, fail : MAP_FAILED
  • signal
    • SIGBUS : mapping region is invalid
    • SIGSEGV : try to write to a read-only mapping region
  • mapping은 page 단위로 이루어짐
    • page size = sysconf(_SC_PAGESIZE) or getpagesize()
  • 파일의 크기는 사용하려는 메모리 영역보다 커야 함
  • Copy-on-Write(CoW) : private mode로 write시, 복사본 생성을 미룸, 불필요한 복사를 피해서 부하를 줄임

removing a mapping

#include <sys/mman.h>

int munmap(void* addr, size_t length);
  • addr : mapping 시작 주소
  • length : mapping 길이
  • return
    • 0 : success
    • -1 : fail

Example

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define CHECK_MMAP_SUCCESS(_addr)       \
if (_addr == MAP_FAILED) {              \
        perror("mmap");                 \
        exit(1);                        \
}


#define printAddrs(msg)                 \
{                                       \
        printf("%s\n", msg);            \
        printf("addr1 = %s", addr1);    \
        printf("addr2 = %s", addr2);    \
}

int main(int argc, char* argv[]) {
        int fd;
        caddr_t addr1, addr2;
        char fileName[255] = "input.dat";

        if (argc > 1) strcpy(fileName, argv[1]);

        if ((fd = open(fileName, O_RDWR)) == -1) {
                perror("open");
                exit(1);
        }

        int pageSize = getpagesize();

        addr1 = mmap(NULL, pageSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0);
        CHECK_MMAP_SUCCESS(addr1);

        addr2 = mmap(NULL, pageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, (off_t)0);
        CHECK_MMAP_SUCCESS(addr2);

        close(fd);

        printf("%s", addr1);

        addr1[0] = '1'; printAddrs("After addr1[0]=1");
        addr2[0] = '2'; printAddrs("After addr2[0]=2");  // CoW
        addr1[0] = '3'; printAddrs("After addr1[0]=3");

        execlp("cat", "cat", fileName, NULL);

        return 0;
}

synchronizing a file with a mapping

#include <sys/mman.h>

int msync(void* addr, size_t length, int flags);
  • 강제로 page write-back 수행
    • memory의 내용과 disk에 있는 파일 내용 동기화
    • fflush()와 유사
  • flags
    • MS_SYNC : write-back이 끝날 때까지 대기
    • MS_ASYNC : write-back을 비동기적으로 수행(기다리지 않고 바로 return)
    • MS_INVALIDATE : 메모리에 변경된 내용 무효화

changing file size

#include <unistd.h>
#include <sys/types.h>

int truncate(const char* path, off_t length);
int ftruncate(int fd, off_t length);
  • 파일의 크기를 변경(늘어난 부분은 0으로 초기화)
  • 파일에 대한 쓰기 권한 필요

IPC with memory mapping

  • 같은 memory mapping region을 공유함으로써 프로세스들 사이의 통신(대화) 가능
  • 하지만, 프로세스들 간의 동기화를 잘 고려해서 사용해야 함
  • IPC
    • Pipe
    • Message Queue
    • Shared Meomory
    • Semaphore
    • Mutex

Example

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define CHECK_MMAP_SUCCESS(_addr)       \
if (_addr == MAP_FAILED) {              \
        perror("mmap");                 \
        exit(1);                        \
}

int main(int argc, char* argv[]) {
        int fd;
        caddr_t addr;
        char fileName[255] = "input.dat";

        if (argc > 1) strcpy(fileName, argv[1]);

        if ((fd = open(fileName, O_RDWR)) == -1) {
                perror("open");
                exit(1);
        }

        int pageSize = getpagesize();

        addr = mmap(NULL, pageSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0);
        CHECK_MMAP_SUCCESS(addr);

        close(fd);

        int pid = 0;

        switch (pid = fork()) {
                case -1:
                        perror("fork");
                        exit(1);
                        break;
                case 0:
                        printf("1. Child Process : addr=%s", addr);
                        sleep(1);
                        addr[0] = 'x';
                        printf("2. Child Process : addr=%s", addr);
                        sleep(2);
                        printf("3. Child Process : addr=%s", addr);
                        break;
                default:
                        printf("1. Parent Process : addr=%s", addr);
                        sleep(2);
                        printf("2. Parent Process : addr=%s", addr);
                        addr[1] = 'y';
                        printf("3. Parent Process : addr=%s", addr);
                        break;
        }

        return 0;
}

producer

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define CHECK_MMAP_SUCCESS(_addr)       \
if (_addr == MAP_FAILED) {              \
        perror("mmap");                 \
        exit(1);                        \
}

int main(int argc, char* argv[]) {
        int fd;
        char* addr;
        char fileName[255] = "map.dat";

        if (argc > 1) strcpy(fileName, argv[1]);
        if ((fd = open(fileName, O_RDWR)) == -1) { perror("open"); exit(1); }

        addr = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0);
        CHECK_MMAP_SUCCESS(addr);
        close(fd);

        char c = 'a';
        while (1) {
                sleep(2);
                addr[0] = c++;
                if (c > 'z') c = 'a';
        }

        return 0;
}

consumer

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define CHECK_MMAP_SUCCESS(_addr)       \
if (_addr == MAP_FAILED) {              \
        perror("mmap");                 \
        exit(1);                        \
}

int main(int argc, char* argv[]) {
        int fd;
        char* addr;
        char fileName[255] = "map.dat";

        if (argc > 1) strcpy(fileName, argv[1]);
        if ((fd = open(fileName, O_RDWR)) == -1) { perror("open"); exit(1); }

        addr = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0);
        CHECK_MMAP_SUCCESS(addr);
        close(fd);

        while (1) {
                sleep(2);
                printf("%c\n", addr[0]);
        }

        return 0;
}

'💻 Computer Science > System' 카테고리의 다른 글

[System] Shared Memory  (1) 2024.01.26
[System] Named Pipe  (1) 2024.01.26
[System] 시그널  (1) 2024.01.25
[System] 프로세스 관리  (1) 2024.01.25
[System] 프로세스  (0) 2024.01.25