사용 헤더 파일
사용 함수
- mmap
void *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
- munmap
int 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
#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"
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");
}
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));
}
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;
}
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;
}
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);
}
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;
}
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){
} else if (pid == 0){
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':
do_anon();
break;
default:
goto main_err;
}
return 0;
main_err:
print_help(argv[0]);
return -1;
}