개념
#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;
}
사용 헤더 파일
사용 함수
- 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
/**
* @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;
}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;
}