벡터 입출력
한 번의 호출로 배열 형태의 입출력용 자료구조에 데이터를 한 번에 읽고 쓰는 것이 가능하다.
벡터 입출력 readv(), writev()
#include <sys/uio.h>
ssize_t readv (int fd, const struct iovec *iov, int count);
ssize_t writev (int fd, const struct iovec *iov, int count);
파일 디스크립터 fd로 부터 입출력용 자료구조 iovec에 데이터를 읽어드리는 readv()
그리고 iovec의 데이터를 한 번에 쓰는 writev 함수가 있다.
호출이 성공했을 시 읽거나 쓴 바이트 수를 반환한다. 에러가 발생했을 시 -1을 반환.
벡터 입출력용 자료구조 iovec
iovec* 은 결국 여러 버퍼의 시작 주소와 길이 정보를 모아놓은 배열이라고 할 수 있다.
#include <sys/uio.h>
struct iovec
{
void* iov_base; // 버퍼의 시작 주소
size_t iov_len; // 버퍼의 길이
};
epoll
poll(), select()를 개선하기위해 등장한 epoll()이 경우 검사 부분과 파일 디스크립터 등록 부분을 분리한다.
epoll 인스턴스 생성
int epoll_create1(int flags);
// ex
int epfd = epoll_create1(0);
if (epfd == -1)
perror("epoll_create");
int epoll_create(int size); 보다 최신 함수로 flags로 옵션이 설정된 epoll 인스턴스를 반환한다. 실패시 -1을 반환.
epoll에 파일 디스크립터 추가 혹은 삭제 epoll_ctl
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll_event 구조체
struct epoll_event {
__u32 events;
union {
void* ptr;
int fd;
__u32 u32;
__u64 u64;
} data;
}
op 인자
- EPOLL_CTL_ADD : epfd와 연관된 epoll 인스턴스가 fd에 대해 정의된 event를 감시하도록 한다.
- EPOLL_CTL_DEL : epfd와 연관된 epoll 인스턴스에 fd를 감시하지 않도록 삭제한다.
- EPOLL_CTL_MOD : 기존에 감시하고 있던 fd에 대해 변경된 이벤트를 감시하도록 한다.
epoll_event의 events 필드에 설정하는 감시하는 이벤트 예시
- EPOLLERR : 에러 상황 (항상 감시)
- EPOLLET : 엣지 트리거로 감시 (기본 동작은 레벨 트리거)
- EPOLLIN : 읽기에 대한 감시
- EPOLLOUT : 쓰기에 대한 감시
epoll_ctl은 성공하면 0을 반환하고 실패하면 -1을 반환한다.
epoll 이벤트 기다리기 epoll_wait
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);
- timeout 밀리초 동안 epfd와 연관된 events중에 발생한 이벤트를 기다린다. events 배열의 최대 개수 maxevents 만큼 최대로 이벤트를 감지 가능하다.
- 이 때, 발생한 이벤트들은 epoll_event 배열에 data의 fd는 발생한 파일 디스크립터 그리고 events 필드를 통해 발생한 이벤트를 알 수 있다.
- 반환 값은 성공시 발생한 이벤트 개수를 반환하며 에러가 발생 했을 시 -1을 반환한다.
메모리에 파일 맵핑하기
mmap()
열어둔 파일의 메모리를 운영체제 프로세스 메모리에 맵핑하는 기능이다.
#include <sys/mman.h>
void* mmap (void* addr, size_t len, int prot, int flags, int fd, off_t offset);
원하는 주소 addr에 len 길이만큼 파일 디스크립터 fd의 오프셋 offset 주소에서 시작하는 메모리를 맵핑한 메모리를 반환한다. addr에 0을 전달하면 임의의 주소에 맵핑한 메모리를 반환한다.
- prot : PROT_NONE/READ/WRITE/EXEC와 같은 메모리 보호 정책
- flags : 할당하는 메모리 맵의 종류
- MAP_FIXED: addr 인자를 히트가 아니라 요구사항으로 취급하도록한다. 커널이 해당 주소를 확보하지 못하면 호출 실패로 이어진다.
- MAP_PRIVATE : 맵핑이 공유되지 않는다. copy-on-write로 맵핑되어 맵핑된 내용에 변경이 있어도 실제 파일이나 다른 프로세스에 반영하지 않는다.
- MAP_SHARED: 같은 파일을 맵핑한 모든 프로세스와 맵핑을 공유한다.
void* ptr = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
perror("mmap");
페이지 크기
mmap 시스템 호출은 len 길이 만큼 사용할 수 있는 메모리 청크를 가져오지만 실제로 할당되는 메모리의 크기는 페이지 크기의 배수만큼 할당된다. len이 페이지 배수 만큼 떨어지지 않는다면 나머지는 쓰지 않는 영역에 해당한다.
또한 addr은 항상 페이지 크기 단위로 정렬된 주소를 반환한다. 페이지 크기는 다음 함수로 알 수 있다.
long page_size = sysconf(_SC_PAGESIZE);
생성한 맵핑을 해제하는 함수 munmap()
#include <sys/mman.h>
int munmap(void* addr, size_t len);
addr에서 시작하여 len만큼 할당된 메모리 맵에 해당하는 페이지를 해제한다. 해당 메모리 영역은 더 이상 유효하지 않으며 이 주소로 접근을 시도하면 SIGSEGV 시그널이 발생한다.
성공 시 0을 반환하며 실패하면 -1을 반환한다.
맵핑한 크기 변경하기 mremap
void* mremap (void* addr, size_t old_size, size_t new_size, unsinged long flags);
addr 주소에 할당한 메모리 맵의 크기를 변경한다. flags의 인자는 MREMAP_MOVE를 전달하여 새로운 주소로 할당하는 것을 허락할 수 있다.
맵핑 보호 모드 변경하기
int mprotect (const void* addr, size_t len, int prot);
PROT_NONE, PROT_WRITE, PROT_READ, PROT_EXEC로 설정가능하다. 기존에 맵핑된 파일 디스크립터가 해당 권한이 있어야한다.
'C++ > linux' 카테고리의 다른 글
(6) Pthread 쓰레드 / PMutex 뮤텍스 (0) | 2022.05.12 |
---|---|
(5) 프로세스 관리 (0) | 2022.05.11 |
(3) 버퍼 입출력 (0) | 2022.05.10 |
(2) 다중 입출력 select와 poll (0) | 2022.05.10 |
(1) errno와 파일 입출력 (0) | 2022.05.10 |