Definition
파일이나 장치를 메모리에 대응 or 해제 시킴
#include <unistd.h>
#include <sys/mman.h>
void * mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *start, size_t length);
Description
mmap() 함수는 fd로 지정된 파일에서 offset을 기점으로 시작해서 length byte만큼 start 주소로 대응시키는 함수
offset과 length는 PAGE_SIZE의 단위여야 함(대개 start 주소를 0으로 지정)
지정된 영역이 mapping된 실제 시작위치를 반환
* PAGE_SIZE?
Page는 MMU에서 메모리 관리 시 사용하는 최소 단위
prot: 메모리 보호 모드 설정
- PROT_EXEC: 페이지는 실행가능하다.
- PROT_READ: 페이지는 읽을 수 있다.
- PROT_WRITE: 페이지는 쓰여질 수 있다.
- PROT_NONE: 페이지는 접근할 수 없다.
flag: 대응된 객체 타입, mapping 옵션, 공유 여부 등 설정
- MAP_FIXED: 지정된 주소 이외의 다른 주소를 선택하지 않는다. 지정된 주소가 사용될 수 없다면 mmap()는 실패한다. 만일 MAP_FIXED가 지정되면, start는 페이지 크기의 배수이어야 한다. 이 옵션은 사용하지 않는 것이 좋다.
- MAP_SHARED: 대응된 객체를 다른 모든 프로세스와 공유한다.
- MAP_PRIVATE: 개별적인 copy-on-write(:12) 대응을 만든다.(다른 프로세스와 대응 영역을 공유하지 않는다).
Return
mmap()
성공 시 mapping된 영역의 포인터를 반환
에러가 발생하면 MAP_FAILED(-1)이 반환되며, errno는 적당한 값으로 설정된다.
mummap()
성공 시 0 리턴, 실패시 -1 리턴
Error
- EBADF: fd가 유효한 파일 기술자가 아니다.
- EACCES: MAP_PRIVATE가 설정되어 있지만 fd가 읽을 수 있도록 열려 있지 않다. 또는 MAP_SHARED와 RPOT_WRITE가 설정되어 있지만 fd가 쓸 수 있도록 열려있지 않다.
- EINVAL: start나 length나 offset이 적당하지 않다. 보통 너무 크거나 PAGESIZE 경계로 정렬되어 있지 않을 경우.
- ETXTBUSY: MAP_DENYWRITE가 설정되어 있으나 fd로 지정된 객체가 쓰기 위해 열려있다.
- EAGAIN: 파일이 잠겨 있다.
- ENOMEM: 사용할 수 있는 메모리가 없다.
Example
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int fd;
char *file = NULL;
struct stat stat_buf;
long page_size;
int flag = PROT_WRITE | PROT_READ;
if (argc < 2) {
fprintf(stderr, "Usage: input\n");
exit(1);
}
if ((fd = open(argv[1], O_RDWR|O_CREAT)) < 0) {
perror("File Open Error");
exit(1);
}
// fstat으로 가져온 파일의 상태 및 정보를 알수 있음
if (fstat(fd, &stat_buf) < 0) {
perror("fstat error");
exit(1);
}
printf("%s %ld bytes\n", argv[1], stat_buf.st_size);
// sysconf함수를 통해 시스템의 page size 얻어옴
page_size = sysconf(_SC_PAGESIZE);
printf("Page Size : %ld\n",page_size);
file = (char *) mmap(0, 40, flag, MAP_SHARED, fd, 0);
if (file == -1) {
perror("mmap error");
exit(1);
}
printf("%s\n", file);
memset(file, 0x00, 40);
mnumap(file);
close(fd);
}
장단점
장점
- 메모리에 맵핑된 파일을 읽거나 쓰면 read() 나 write() 시스템 콜을 사용할 때 발생하는 불필요한 복사를 방지(추가적인 복사는 사용자 영역의 버퍼로 데이터를 읽고 써야 하기 때문에 발생)
- Page Fault 가능성을 제외하면 메모리에 맵핑된 파일을 읽고 쓰는 데 다른 시스템 콜 호출이나 컨텍스트 스위칭 같은 오버헤드가 발생하지 않음.
- 여러 개의 프로세스가 같은 객체를 메모리에 맵핑한다면 데이터는 모든 프로세스에서 공유가능 읽기전용이나 MAP_SHARED 모드로 쓰기가 가능하게 맵핑된 객체는 전체가 다 공유된다.
- lseek() 같은 시스템 콜을 사용하지 않고도 간단한 포인터 조작만으로 맵핑 영역을 탐색
단점
- 메모리 맵핑은 항상 PAGE_SIZE의 정수배만 가능하다. 따라서 맵핑하려는 파일 크기가 페이지 크기의 정수배 차이 만큼의 공간이 낭비될 수 있음
- 32bit 에서 다양한 크기의 수많은 맵핑을 사용하게 되면 주소 공간의 파편화를 초래
- 메모리 맵핑과 관련 자료구조를 커널 내부에서 생성, 유지하는 데 오버헤드가 발생한다.
300x250
'Linux System > Linux' 카테고리의 다른 글
[cmd] sed (0) | 2022.03.15 |
---|---|
Console, Terminal, TTY (0) | 2022.03.10 |
[cmd] install 명령어 (0) | 2020.08.05 |
[func] poll (0) | 2020.04.07 |
[func] fcntl (0) | 2020.04.07 |