Level/Edge trigger
trigger: 어떤 사건의 반응, 사건을 유발한 계기나 도화선
시스템에서 특정 이벤트를 감시하기위해 트리거라는 개념을 사용한다.
트리거는 크게 "레벨 트리거"와 "엣지 트리거"로 나뉜다.

level trigger
레벨트리거는 1일때만 이벤트를 발생시킨다. 즉, 현재상황을 기준으로 1인경우에만 이벤트를 발생!
그렇기때문에, 1인상태가 지속된다면 몇번이고 이벤트가 발생시킨다.

edge trigger
엣지트리거는 0에서 1로(상승엣지, rising edge) 또는 1에서 0으로(하강엣지, falling edge)
변하는 "순간" 이벤트를 발생시킨다.

select / epoll
select와 epoll은 둘다 디폴트값이 "레벨트리거"이다.
그러나 epoll은 "엣지트리거"로 구현할수있다.
select는 "엣지트리거"로 구현할수없다.
socket에서의 level/edge trigger
socket에 1000바이트의 데이터가 도착했다고 가정하자.
- 소켓의 상태는 0에서 1로 변경된다.
- level trigger는 상태가 1이 되었으므로 이벤트발생 / edge trigger는 0 에서 1로 변경되는순간 이벤트발생
- 이 소켓과 연결되어있는 어플리케이션이 데이터를 500읽었다고 가정하자. 소켓버퍼에는 아직 500 바이트의 데이터가 존재.
다음과같은 상황에서,
- level trigger: 다시 레벨트리거를 한다면, 소켓의 상태가 1이므로, 계속해서 이벤트발생.
그러므로, 소켓 버퍼가 비기전까지 계속해서 상태 1로서 이벤트 발생!
문제없이 모든 버퍼를받지만, 이때도 non blocking을 설정해준다면, wait_poll함수를 호출하는 수가 줄어
최적화가 가능해진다.
- edge trigger: 다시 엣지트리거를 한다면, 소켓의 상태가 1임에도, 이벤트가 발생하지않음.
그 이유는, edge trigger는 0에서 1, 1에서 0으로 변화하는 순간에만 이벤트가 발생하기때문이다.
소켓버퍼에있는 데이터를 모두 읽지않고, 다음 wait_poll함수를 호출할경우, wait_poll함수에서 "교착상태"가 되는 경우가있다. (서버는 클라이언트로부터 남은 데이터를 기다리며, 클라이언트는 서버의 응답을 기다리게되기 때문)
또한, read, write와 같은 시스템콜 함수들은 block함수이기때문에, 함수가 동작하는동안 어플리케이션이 block상태가 된다.
그렇기때문에! epoll + edge trigger 일때는, non blocking을 해야한다.
read, write, recv, send등의 함수가 읽을 데이터가 없을때에는 바로 -1을 반환한다.
그렇기에 실패의 유형은 오류코드(errno)로 구분한다.
일반적으로, EAGAIN 또는 EWOULDBLOCK을 반환한다.
- EAGAIN: 일시적 리소스 부족으로 작업불가, 잠시후 다시 시도부탁함.
-EWOULDBLOCK: 작업이 덜끝나서 블록.
이때에만, epoll_wait를 호출 한다.

출처: developer.ibm.com
epoll + edge trigger 구현
- 엣지트리거 설정
struct epoll_event;
event.events = EPOLLIN | EPOLLOUT | EPOLLET;
- 소켓 속성 변경
fcntl(fd, F_SETFL, .... | NONBLOCK);