Mmap 함수 예제 - Mmap hamsu yeje

개념

#include <sys/mman.h>

#defineFND_SIZE(0x1000)

#define FND_PHYS_ADDR (0x14000000)   // physical 주소

void fnd_write(int val) 

{

*((unsigned char *)fnd_addr) = fnd_val[val];

*((unsigned char *)fnd_addr+1) = fnd_val[val];

printf("FND_Write : %d done!!\n", val);

}

...

fd = open("/dev/mem", O_RDWR|O_SYNC);

fnd_addr = mmap((void *)0,FND_SIZE,PROT_WRITE|PROT_READ,MAP_SHARED,fd,FND_PHYS_ADDR);

printf("FND I/O Address : %p\n", fnd_addr);

fnd_write(val);

munmap(fnd_addr, FND_SIZE);

close(fd);

...


(void *)0 : 가상주소는 알아서 해줘.

fnd_addr: 가상주소

코드

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <fcntl.h>

#include <sys/mman.h>

#define FND_PHYS_ADDR0 (0x14000000) 

#define FND_PHYS_ADDR1 (0x14100000) 

#define FND_PHYS_ADDR2 (0x14200000) 

#define FND_PHYS_ADDR3 (0x14300000) 

#defineFND_SIZE(0x1000)

//#define FND (*((volatile unsigned short *)0xF1000000)) 

void * fnd_addr;

static char fnd_val[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x27,0x7f,0x67};

void fnd_write(int val) 

{

*((unsigned char *)fnd_addr) = fnd_val[val];

*((unsigned char *)fnd_addr+1) = fnd_val[val];

printf("FND_Write(%d) done!!\n", val);

}

int main(void)

{

    int retn;

    int fd;

    int flag = 0;

    int type;

int val=0;

int i;

off_t addr[] = {FND_PHYS_ADDR0, FND_PHYS_ADDR1,

FND_PHYS_ADDR2, FND_PHYS_ADDR3};

off_t FND_PHYS_ADDR;

    while(1)

    {

        printf("\n\n===== FND Test Program ====\n");

        printf(" 0. FND0 Test\n");

        printf(" 1. FND1 Test\n");

        printf(" 2. FND2 Test\n");

        printf(" 3. FND3 Test\n");

        printf(" 4. Program Quit\n");

        do {

            printf(" Select Menu => ");

            scanf("%d", &type);

        } while(type<0 || type>4);

        if(type == 4) break;

        while(1)

        {

            printf("\nFND_%02d Test...\n", type-1);

            do {

                printf("Select FND Write Value(0~9,10.Quit) => ");

                scanf("%d", &val);

            } while(val<0 || val>10);

            if(val == 10) break;

            //fd = open("/dev/FND", O_RDWR);

            fd = open("/dev/mem", O_RDWR|O_SYNC);

            if (fd<0) {

                perror("/dev/mem");

                exit(-1);

            }

            else printf("/dev/mem detected(fd:%d)...\n", fd);

FND_PHYS_ADDR = (off_t)addr[type];

fnd_addr = mmap((void *)0,

FND_SIZE,

PROT_WRITE|PROT_READ,

MAP_SHARED,

fd,

FND_PHYS_ADDR);

if(fnd_addr == NULL) {

                perror("mmap fail!!");

exit(-2);

}

printf("FND I/O Address : %p\n", fnd_addr);

            fnd_write(val);

munmap(fnd_addr, FND_SIZE);

            close(fd);

        }

    }

    return 0;

}

사용 헤더 파일

  • sys/mman.h

사용 함수

  • mmapvoid *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); 파라미터 * void *addr: 매핑될 주소 * size_t length: 매핑할 길이 * int prot: 파일에 대응되는 메모리 영역의 보호 특성을 결정하기 위한 값 - PROT_EXEC: 실행 가능한 페이지 - PROT_READ: 읽기 가능한 페이지 - PROT_WRITE: 쓰기 가능한 페이지 - PROT_NONE: 접근 불가능한 페이지 * int flag: 매핑의 유형과 동작 구성 요소 결정 값 - MAP_FIXED: 기존 매핑과 겹칠 경우 중첩 페이지를 버리고 새 매핑으로 대체 - MAP_SHARED: 대응된 객체를 다른 모든 프로세스와 공유한다. - MAP_PRIVATE: 데이터의 변경 내용을 공유하지 않는다. - MAP_ANONYMOUS: anonymous 모드로 진행 * int fd: 파일 디스크립트 * off_t offset: 매핑할 때, 옮길 데이터의 시작점 지정 출력 값 * 성공: 매핑된 주소 * 실패: MAP_FAILED
  • munmapint munmap(void *addr, size_t length); 파라미터 * void *addr: 메모리 해제할 매핑 주소 * size_t length: 매핑한 메모리를 해제할 길이 출력값 * 성공: 0 * 실패: -1

활용 용도

  • 다른 프로세스간 데이터의 교환 용도로 이용 가능
  • 파일 디스크립트를 직접 얻어서 하는 방식 (open, read 등)이 아닌 직접 메모리에 접근하여 데이터를 가져오는 방식으로 성능 향상을 기대할 수 있음.

anonymous 를 이용할 경우

  • mmap 함수에서 MAP_ANONYMOUS 플래그를 사용할 경우 특정 파일을 지정하지 않고 익명의 파일에 메모리를 매핑할 수 있다.
    • 이는 결국 FILE I/O 가 일어나지 않아 성능에서 이득을 볼 수 있다.
  • 이는 malloc 과는 다르게 fork()로 생성된 자식 프로세스들에게 해당 파일 디스크립터를 공유할 수 있다.
  • 사용 할 때 유의사항은 다음과 같다.
    • mmap 호출시 MAP_SHARED 와 같이 사용
    • mmap 호출 시 fd 값은 -1로 셋팅
    • mmap 호출시 offset argument 값은 무시된다.
    • “/dev/zero” 파일에 대해 mmap 하는 것은 anonymous mapping 과 같다.

예제 프로그램 1

  • 소스코드 (main.c)
/** * @file main.c * @author Yoon Yeoung Jin () * @brief * @version 0.1 * @date 2022-06-18 * * @copyright Copyright (c) 2022 * */ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<errno.h> #include<sys/types.h> #include<sys/stat.h> #include<sys/mman.h> #include<fcntl.h> typedef struct mmap_test_struct { char name[20]; int age; char hobby[30]; }MMAP_TEST_STRUCT; #define FILE_PATH "/home/alwns28/mmap_example/mmap_test" /** * @brief MMAP_TEST_STRUCT 구조체 출력 함수 * * @param in 출력할 MMAP_TEST_STRUCT 구조체 */ void yj_print_struct(MMAP_TEST_STRUCT in) { printf("SETTING DATA:\n"); printf(" * name: %s\n", in.name); printf(" * age: %d\n", in.age); printf(" * hobby: %s\n", in.hobby); printf("================================\n"); } /** * @brief MMAP_TEST_STRUCT 구조체 셋팅 함수 * * @param in_name 이름 * @param in_age 나이 * @param in_hobby 취미 * @param out 셋팅된 MMAP_TEST_STRUCT 구조체 */ void yj_setting_struct(const char *in_name, const int in_age, const char *in_hobby, MMAP_TEST_STRUCT *out) { strncpy(out->name, in_name, sizeof(out->name)); out->age = in_age; strncpy(out->hobby, in_hobby, sizeof(out->hobby)); } /** * @brief 파일 생성 함수 * * @param message 입력할 MMAP_TEST_STRUCT 구조체 * @return int 0: 성공, -1: 실패 */ int yj_create_file(const MMAP_TEST_STRUCT *message) { int fd = 0; fd = open((const char *)FILE_PATH, O_CREAT|O_WRONLY, 0644); if(fd == -1){ printf("open fail: %s\n", strerror(errno)); return -1; } if(write(fd, (const void *)message, sizeof(*message)) == -1){ printf("write fail: %s\n",strerror(errno)); return -1; } close(fd); return 0; } /** * @brief 파일 읽는 함수 * * @return int 0: 성공, -1: 실패 */ int yj_read_file() { MMAP_TEST_STRUCT out; int fd = 0; int out_bytes; fd = open((const char *)FILE_PATH, O_RDONLY); if(fd == -1){ printf("open fail: %s\n", strerror(errno)); return -1; } if((out_bytes = read(fd, (void *)&out, sizeof(out))) == -1){ printf("read fail: %s\n", strerror(errno)); return -1; } yj_print_struct(out); close(fd); return 0; } /** * @brief 파일에 있는 데이터를 mmap을 사용하여 메모리에 쓰는 함수 * */ void yj_write_mmap() { int fd = 0; off_t mmap_offset = 0; struct stat buf; fd = open((const char *)FILE_PATH, O_RDWR); if(fd == -1){ printf("open fail: %s\n", strerror(errno)); return ; } fstat(fd, &buf); if(mmap((void *)NULL, (size_t)buf.st_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED,fd, mmap_offset) == MAP_FAILED){ printf("mmap fail : %s\n", strerror(errno)); return ; } close(fd); } /** * @brief mmap에서 데이터를 읽어와서 출력하는 함수 * * @param out mmap에서 읽어올 MMAP_TEST_STRUCT 구조체 */ void yj_read_mmap(MMAP_TEST_STRUCT *out) { int fd = 0; off_t mmap_offset = 0; struct stat buf; fd = open((const char *)FILE_PATH, O_RDWR); if(fd == -1){ printf("open fail: %s\n", strerror(errno)); return ; } fstat(fd, &buf); out = (MMAP_TEST_STRUCT *)mmap((void *)NULL, (size_t)buf.st_size, PROT_READ, MAP_SHARED, fd, mmap_offset); if(out == MAP_FAILED){ printf("mmap fail : %s\n", strerror(errno)); return ; } yj_print_struct(*out); if(munmap((void *)out, sizeof(out)) == -1){ printf("munmap() fail: %s\n", strerror(errno)); } close(fd); } int main(int argc, char **argv) { MMAP_TEST_STRUCT in; MMAP_TEST_STRUCT out; printf("= STEP 1: Setting struct data \n"); yj_setting_struct("YOON YEOUNG JIN", 26, "Play Room Escape game", &in); yj_print_struct(in); printf("= STEP 2: Write file \n"); if(yj_create_file((const MMAP_TEST_STRUCT *)&in) == 0){ printf(" ==> SUCCESS\n"); } else { printf(" ==> FAIL\n"); } yj_read_file(); printf("= STEP 3: Write memory to use mmap() \n"); yj_write_mmap(); printf("================================\n"); printf("= STEP 4: Read memory to use mmap() and other MMAP_TEST_STRUCT \n"); yj_read_mmap(&out); return 0; }
  • Makefile
CC = gcc -m64 CFLAGS += -Wall -O2 -pthread OBJS = main.o TARGET = main all = $(TARGET) $(TARGET) : $(OBJS) $(CC) $(CFLAGS) -o $@ $^ .c.o: $(CC) $(CFLAGS) -c $< clean: rm *.o rm $(TARGET) find -type f ! -name "*.c" ! -name "Makefile" ! -name "hello_world" -exec rm {} \;
  • 실행 화면

예제 프로그램 2

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<fcntl.h> #include<sys/types.h> #include<sys/wait.h> #include<sys/stat.h> #include<sys/mman.h> #define MAX_BUF_LEN 4096 #define SLEEP_UTIME 1000 #define FORK_NUM 5 typedef struct anon_info{ int pid; char Message[MAX_BUF_LEN]; } ANON_INFO; typedef struct data_info{ int size; char Message[MAX_BUF_LEN]; } DATA_INFO; static void print_help(const char *progname) { printf("Usage: %s [-fa] (monitor|send Message)\n", progname); printf(" options:\n"); printf(" -f (monitor|send Message) File_path \n"); printf(" -a\n"); } static int do_monitoring(const char *file_path) { int fd; DATA_INFO *buf; DATA_INFO *tmp_buf; fd = open(file_path, O_CREAT | O_RDWR, 0644); if(fd == -1){ perror("open()"); return -1; } if(ftruncate(fd, sizeof(DATA_INFO)) == -1){ /* 파일을 넣을 데이터 만큼 늘려놓는다. */ perror("ftruncate()"); close(fd); return -1; } buf = (DATA_INFO *)mmap(NULL, sizeof(DATA_INFO), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if(buf == MAP_FAILED){ perror("mmap()"); close(fd); return -1; } buf->size = 0; memset(buf->Message, 0, sizeof(char) * MAX_BUF_LEN); close(fd); tmp_buf = (DATA_INFO *)malloc(sizeof(DATA_INFO)); memset((void *)tmp_buf, 0, sizeof(DATA_INFO)); memcpy((void *)tmp_buf, (const void *)buf, sizeof(DATA_INFO)); printf("[monitor] client said [%s], Message size: %d\n", tmp_buf->Message, tmp_buf->size); while(1){ if(sizeof(tmp_buf) < sizeof(buf)){ free(tmp_buf); tmp_buf = (DATA_INFO *)malloc(sizeof(DATA_INFO)); memset((void *)tmp_buf, 0, sizeof(DATA_INFO)); memcpy((void *)tmp_buf, (const void *)buf, sizeof(DATA_INFO)); printf("[monitor] client said [%s], Message size: %d\n", tmp_buf->Message, tmp_buf->size); } else { if(memcmp((const void *)tmp_buf, (const void *)buf, sizeof(DATA_INFO))){ memcpy((void *)tmp_buf, (const void *)buf, sizeof(DATA_INFO)); printf("[monitor] client said [%s], Message size: %d\n", tmp_buf->Message, tmp_buf->size); } } usleep(SLEEP_UTIME); } free(tmp_buf); munmap(buf, sizeof(DATA_INFO)); return 0; } static int do_send_data(const char *file_path, const char *message) { int fd; fd = open(file_path, O_RDWR); DATA_INFO *buf; if(fd == -1){ perror("open()"); return -1; } buf = (DATA_INFO *)mmap(NULL, sizeof(DATA_INFO), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if(buf == MAP_FAILED){ close(fd); perror("mmap()"); return -1; } buf->size = sizeof(message); strncpy(buf->Message, message, sizeof(buf->Message)); munmap(buf, sizeof(DATA_INFO)); close(fd); return 0; } ANON_INFO *mmap_init(void) { ANON_INFO *info; info = mmap(NULL, sizeof(ANON_INFO), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if(info == MAP_FAILED){ perror("mmap()"); return NULL; } memset((void *)info, 0, sizeof(ANON_INFO)); return info; } static int anon_send_data(int index, ANON_INFO *info) { sleep(index + 2); info->pid = getpid(); snprintf(info->Message, sizeof(info->Message), "anonymous test %d", index); return 0; } static int anon_monitor(ANON_INFO *info) { int n = 0; ANON_INFO local; memset((void *)&local, 0, sizeof(local)); while(1){ if(memcmp((const void *)&local, (const void *)info, sizeof(local))){ printf(" * pid = %d, Message = %s\n", info->pid, info->Message); memcpy((void *)&local, (const void *)info, sizeof(local)); n ++; if(n == FORK_NUM) break; } usleep(SLEEP_UTIME); } munmap((void *)info, sizeof(ANON_INFO)); return 0; } static int do_anon(void) { int i; pid_t pid; ANON_INFO *info; printf("* START ANONYMOUS MODE \n"); info = mmap_init(); for(i=0; i<FORK_NUM; i++){ pid = fork(); if(pid > 0){ /* parent */ } else if (pid == 0){ /* child */ anon_send_data(i, info); munmap((void *)info, sizeof(ANON_INFO)); return 0; } else { perror("fork()"); return -1; } } anon_monitor(info); printf("* END ANONYMOUS MODE\n"); for(i=0; i<FORK_NUM; i++){ pid = wait(NULL); if(pid == -1){ perror("wait()"); return -1; } printf(" [PID: %d] Terminate\n", pid); } return 0; } int main(int argc, char **argv) { if(argc < 2){ goto main_err; } switch (argv[1][1]) { case 'f': if(argc < 4){ goto main_err; } if(!strcmp((const char *)argv[2], "monitor")){ do_monitoring((const char *)argv[3]); } else if(!strcmp((const char *)argv[2], "send")){ if(argc < 5){ goto main_err; } do_send_data((const char *)argv[4], (const char *)argv[3]); } else { goto main_err; } break; case 'a': /* anonymous mode */ do_anon(); break; default: goto main_err; } return 0; main_err: print_help(argv[0]); return -1; }

Toplist

최신 우편물

태그