Signals - 시스템프로그래밍

Signals - 시스템프로그래밍

Tag
Computer Science Engineering
System Programming

Basic signal concept

  • signal은 어떤 이벤트가 발생했을 때 알려주는 용도로 프로세스에게 전달되는 software notification이다
  • signal의 lifetime은 해당 이벤트가 발생되었을 때 생성되며, 전달이 되어 수신을 하여 처리를 마치게 되면 해당 signal은 삭제가 된다.
  • pending signal: 아직 타겟 프로젝트에게 시그널이 전달되지 않은 경우 ( 지금 안받을거야! )
    • 바로 삭제 되는 것이 아니라, pending signal list에 유지된다.
  • signal이 도착했을 때 수행해야 하는 task가 정의된 signal handler는 프로세스가 signal을 받았을 때 실행된다.
    • 별도로 signal handler 역할을 수행하는 함수를 정의하지 않았다면 default signal handler가 실행된다.
    • 프로그램에서 특정 시그널이 왔을 때 다른 task를 수행할 거야! 라는 함수를 정의할 수 있다는 것이다.
  • sigaction function
    • 특정 signal이 도착했을 때 특정한 task를 수행하게 끔 개발자가 설정한 signal handler 를 등록하는 함수.
    • 사용자가 정의한 signal handler function을 등록할 수도 있지만, constant 값을 설정할 수도 있다.
      • SIG_DFL: default action
      • SIG_IGN: ignore the signal
  • Process signal mask
    • block시키고 싶은 signal 번호들의 목록
    • block이 되면, pending시키며 ( pending signal ), pending signal list에 대기하게 된다.
      • ignore된 signal (SIG_IGN)는 대기하지 않고 바로 삭제된다.
    • sigprocmask function ( 넣을 수도, 뺄 수도 )
      • 프로세스들은 기본적으로 signal이 발생했을 때 그 signal을 받지 않겠다는 객체인 signal mask를 가지고 있다.
      • signal mask에 signal 번호를 등록하여 막도록 해줌.
 

Generating signals

  • 모든 signal은 symbolic name ( SIG~~~ )을 가지고 있으며, signal 번호도 가지고 있다.
    • defined in signal.h
  • command line으로 시그널 생성
    • kill command
      • 시그널을 전송하는 명령어. 꼭 죽이는 것은 아님..
    • 두개의 parameter를 넣을 수 있다.
      • 어떤 시그널 / pid
      • signal_name로 지정할 때에는 SIG를 빼고 전송한다.
        • kill -s USR1 1234 (signal name: SIGUSR1 / -s: 이름을 쓰겠다)
      • signal_number로 지정할 때에는 -{value} 형태로 사용한다.
        • kill -9 1234
    • -l 옵션으로 symbolic signal name들 리스트를 볼 수 있다.
 

kill

#include <signal.h> int kill(pid_t pid, int sig);
  • pid parameter
    • target process id이다.
    • 만약 0이라면 호출한 프로세스와 같은 프로세스 그룹에 속한 모든 프로세스에게 이 시그널을 전달하겠다.
      • 하나의 프로세스에만 시그널을 전달하는 것이 아니다.
    • 만약 -1 이라면, 보낼 수 있는 권한이 있는 모든 프로세스에게 시그널을 전달하겠다.
    • 또다른 음수라면, 절대값을 취한 값인 프로세스 그룹 아이디에 속한 모든 프로세스에게 시그널을 전달하겠다.
      • ex) -10이라면, group id가 10인 프로세스 그룹에 속한 모든 프로세스들
  • return value
    • 성공했을 시 0 / 실패했을 시 -1
 

raise

#include <signal.h> int raise(int sig)
  • 타겟 프로세스는 나 자신이다.
  • return value
    • 0일 경우 성공 / 실패했을 경우 0이 아님
 

alarm

#include <unistd.h> unsigned alarm(unsigned seconds)
  • 파라미터로 받은 초가 지나게 되면, 이 함수를 호출한 프로세스에게 SIGALARM signal을 보낸다.
    • 즉, 나 자신에게 보내는 signal 이다.
  • 만약 seconds: 0이라면, 기존에 요청했던 alarm을 취소해라.
  • SIGALARM signal을 받게되면, default action은 process를 종료한다.
  • return value
    • 타이머에 남아있는 초 값. ( 정상적으로 종료되었다면 0 )
    • 에러를 따로 return 하지 않는다.
 

Signal sets

#include <signal.h> // signal set에 signal number를 추가하겠다. int sigaddset(sigset_t* set, int signo); // signal set에서 signal number를 빼겠다. int sigdelset(sigset_t* set, int signo); // signal set 내용을 비우겠다. int sigemptyset(sigset_t* set); // signal set에 모든 signal을 세팅한다. int sigfillset(sigset_t* set); // signal set에 signal number가 포함되어있냐 int sigismember(const sigset_t* set, int signo);
  • Signal set
    • 여러개의 signal을 담을 수 있는 data structure ( integer type )
    • sigaddset, sigdelset을 통해 signal 번호를 넣거나 뺄 수 있다.
      • 성공했을 시 0 / 실패했을 시 -1
    • sigemptyset, sigfillset을 통해 initialize
      • 성공했을 시 0, 실패했을 시 -1
    • sigismember
      • true 1 / false 0
      •  

Signal masks

#include <signal.h> int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
  • signal mask는 특정 signal 들이 왔을 때, block하게 해줌
  • sigset_t 타입의 signal masks를 수정하기 위해서 sigprocmask 함수를 사용한다.
  • sigprocmask()
    • parameter
      • how
        • 추가할지, 삭제할지
        • SIG_BLOCK: 두번째 파라미터인 set을 signal mask에 추가하겠다.
        • SIG_UNBLOCK: signal mask에서 두번째 파라미터인 set을 삭제하겠다. ( 있는 것들만 )
        • SIG_SETMASK: signal mask를 두번째 파라미터인 set으로 설정해버리겠다. ( 기존값들 없어짐 )
      • oset
        • output parameter.
        • 수정되기 이전의 signal mask 값을 세팅함.
        • 잠깐 signal mask를 수정하여 중요한 일을 했다가, 끝나면 기존 signal mask로 설정하려고 쓰는 용도
    • return: 성공했을 시 0 / 실패했을 시 -1
    • single thread process에만 사용해야 한다.
      • 어느 스레드로 갈지 애매해질 수 있기 때문이다.
      • 스레드 레벨에서 signal mask를 조절하려면, pthread_sigmask()를 호출해야 한다.
    • SIGSTOP, SIGKILL은 signal mask로 막을 수 없다.
 

Signal masks and sets example

  • signal set에 SIGINT 추가
sigset_t newsigset; if((sigemptyset(&newsigset) == -1 || (sigaddset(&newsigset, SIGINT) == -1)) perror(“Failed to initialize the signal set”); else if( sigprocmask(SIG_BLOCK, &newsigset, NULL) == -1) perror(“Failed to block SIGINT”);
  • signal set을 수정하고 나서 원복
sigset_t blockmask; sigset_t oldmask; … //add signals to blockmask if( sigprocmask(SIG_SETMASK, &blockmask, &oldmask) == -1) return -1; … if( sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) return -1; …
 

Catching and ignoring signals

#include <signal.h> int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact); struct sigaction{ // 함수 포인터. signal handler 함수. // return type void. parameter는 int형 하나 ( signal 번호 ) // SIG_DFL, SIG_IGN를 설정할 수도 있다. void (*sa_handler)(int); // signal handler가 호출될 동안, block시킬 signal이 있다면, 세팅 sigset_t sa_mask; // 추가적으로 설정하고 싶은 flag / 옵션 // 설정함에 따라 첫번째 / 네번째 인자 중 어떤 것을 실행할 지 정할 수 있다. // SA_SIGINFO가 없으면 첫번째 인자 / 있다면 4번째인자. int sa_flags; // signal handler를 등록할 수 있는 함수. // 첫 번째 인자보다 parameter가 더 많음. // realtime handler void (*sa_sigaction) (int, siginfo_t *, void *); }
  • signal이 왔을 때 무엇을 할 것인가?
  • parameter
    • sig: 몇 번 시그널이 왔을 때 액션을 취할 것인가
    • act: 어떤 액션을 취할 것인지와 설정 정보
    • oact: 이전 액션 정보를 반환해주는 output parameter
  • signal handler
    • signal handler가 void return type / one integer parameter 이어야 한다.
      • 그렇기 때문에 특정한 값을 넘겨줄 수 없다..
    • POSIX Extension 버젼에서 sa_sigaction을 사용할 수 있게 하여 값을 넘길 수 있게 함
    • sa_handler의 특별한 값
      • SIG_DFL: default action을 수행해라
      • SIG_IGN: 무시해라.
      •  

Catching/ignoring signals examples

  • SIGINT가 도착했을 때 mysighand 함수를 signal handler로 세팅
struct sigaction newact; newact.sa_handler = mysighand; newact.sa_flags = 0; if(( sigemptyset(&newact.sa_mask) == -1) || ( sigaction(SIGINT, &newact, NULL) == -1)) perror(“Failed to install SIGINT signal handler”);
  • 만약 SIGINT의 액션이 default action 이라면 SIGINT를 무시하고 싶은 경우
struct sigaction act; if(sigaction(SIGINT, NULL, &act) == -1) perror(“Failed to get old handler for SIGINT”); else if( act.sa_handler == SIG_DFL ){ act.sa_handler = SIG_IGN; if( sigaction(SIGINT, &act, NULL) == -1) perror(“Failed to ignore SIGINT”);
 

Catching/ignoring signals examples

  • 반복문을 돌며 0과 1사이에 있는 sin(x)의 평균 값을 구하는 프로그램
  • 사용자가 ctrl+c를 누르게 되면, signal handler를 등록하여 gracefully terminate 하게 됨. ⇒ flag 값을 설정하여 반복문을 나가게 하도록
#include <math.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> static volatile sig_atomic_t doneflag = 0; /* ARGSUSED */ static void setdoneflag(int signo){ doneflag = 1; } int main(void){ struct sigaction act; int count = 0; double sum = 0; double x; // signal handler 등록 act.sa_handler = setdoneflag; act.sa_flags = 0; // signal handler가 작동 중에는 별다른 signal을 막지 않는다. // sigaction 함수 호출 if((sigemptyset(&act.sa_mask) == -1) || (sigaction(SIGINT, &act, NULL) == -1)){ perror("Failed to set SIGINT handler"); return 1; } while(!doneflag){ x = (rand() + 0.5)/(RAND_MAX + 1.0); sum += sin(x); count++; printf("Count is %d and average is %f\n", count, sum/count); } printf("Program terminating ...\n"); if(count == 0) printf("No values calculated yet\n"); else printf("Count is %d and average is %f\n", count, sum/count); return 0; }
  • 시그널이 도착하면, 실행이 jump하여 시그널 핸들러 함수가 실행된 뒤에 돌아오게 된다.
    • doneflag은 critical section으로 처리해야 한다.
    • 현재 단일 스레드 / 단일 프로세스 이지만, 반복문 접근하려는 중에 signal handler를 수행해버리면 뭐 문제가 될 수도 있다.. 뭐 크게 문제는 아니지만서도..
    • 메인프로그램이 접근하는 영역과 signal handler가 동시에 access 할 수도 있는 부분은 critical section으로 만들어야 한다.
    • 현재의 코드는 critical section을 만들었는데 어떻게 했는가?
      • doneflag를 sig_atomic_t로 만들었다는 점.
        • 해당 변수는 OS레벨에서 이 변수를 access를 하여 접근이 종료될 때 까지 다른 작업이 방해하는 것을 막아준다.
      • volatile qualifier
        • 변수의 값을 access할 때, c 컴파일러에게 비동기 작업으로 인해 값이 변경될 수도 있으니 항상 메모리에서 직접 참조하라는 말을 하는 것이다.
        • 레지스터에 load된 값을 읽는 것이 아님.
 

Catching/ignoring signals examples

  • 위의 예시와 비슷하게 작동한다
  • 10000번째 iteration마다 버퍼에 중간 계산 결과를 저장한다.
  • SIGUSR1 signal이 도착하면, signal handler가 버퍼의 내용을 화면에 출력해준다.
#include <errno.h> #include <limits.h> #include <math.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define BUFSIZE 100 static char buf[BUFSIZE]; static int buflen = 0; /* ARGSUSED */ static void handler(int signo){ int savederrno; savederrno = errno; // 버퍼에 쓰여진 값만큼 화면에 출력한다. // 왜 printf를 쓰지 않냐? => reentrant하게 작동하지 않기 때문에, write 함수를 사용한 것이다. // main에서도 printf를 쓰게 되면 꼬일 수 있어서. write(STDOUT_FILENO, buf, buflen); errno = savederrno; } // 메인 프로그램에서 10000번째 마다 결과를 버퍼에 쓰는 역할 static void results(int count, double sum){ double average; double calculated; double err; double errpercent; sigset_t oset; sigset_t sigset; if((sigemptyset(&sigset) == -1) || (sigaddset(&sigset, SIGUSR1) == -1) || (sigprocmask(SIG_BLOCK, &sigset, &oset) == -1)) perror("Failed to block signal in results"); if(count == 0) snprintf(buf, BUFSIZE, "No values calculated yet\n"); else{ calculated = 1.0 - cos(1.0); average = sum/count; err = average - calculated; errpercent = 100.0 * err / calculated; // 세번째 인자를 버퍼에 넣어주고 마지막에 NULL 추가 snprintf(buf, BUFSIZE, "Count = %d, sum = %f, average = %f, error = %f or %f%%\n", count, sum, average, err, errpercent); } buflen = strlen(buf); // 이전 상태로 되돌린다. 즉 USR1를 빼낸다 if(sigprocmask(SIG_SETMASK, &oset, NULL) == -1) perror("Failed to unblock signal in results"); } int main(void){ int count = 0; double sum = 0; double x; struct sigaction act; act.sa_handler = handler; act.sa_flags = 0; if((sigemptyset(&act.sa_mask) == -1) || (sigaction(SIGUSR1, &act, NULL) == -1)){ perror("Failed to set SIGUSR1 signal handler"); return 1; } fprintf(stderr, "Process %ld starting calculation\n", (long)getpid()); for(;;){ if((count % 10000) == 0) results(count, sum); x = (rand() + 0.5) / (RAND_MAX + 1.0); sum += sin(x); count++; if(count == INT_MAX) break; } results(count, sum); handler(0); return 0; }
  • Critical section
    • signal mask를 이용해서 block하게 된다. ( result 함수 내에 )
 

Waiting for signals

  • 다음 작업을 시작하기 위한 시그널로서 특정 시그널을 기다린다.
    • pause(), sigsuspend(), sigwait()
 

pause

#include <unistd.h> int pause(void);
  • 시그널이 전달될 때까지 호출한 스레드가 suspend된다.
    • user-defined handler가 호출될 수 있는 타겟 시그널이 오거나, 프로세스가 종료될 수 있는 시그널이 온다면 pause 함수가 return 된다.
    • 뭐라도 시그널이 온다면 pause함수가 return 된다.
  • 항상 -1을 return 한다.
  • 시그널이 오면 해당 시그널 핸들러가 실행되고, 그 이후에 리턴되는 것이다.

  • 내가 원하는 시그널이 왔다면 sigreceived를 1로 만든다.
static volatile sig_atomic_t sigreceived = 0; while(sigreceived == 0) pause();
  • 만약 시그널이 while(sigreceived == 0)임을 확인하고 pause 함수를 호출하기 이전에 타겟 시그널이 왔다면?
    • 타겟 시그널이 와도 씹히게 된다.
    • pause 함수에 영향을 주지 못한다.
    • 어떤 시그널이 추가로 와야 pause가 리턴 가능하다.
    • 막았던 signal을 unblocking하는 것과 pause를 시작하는 것은 한번에 해야한다.
      • ⇒ sigsuspend 함수가 이를 지원한다.
 

sigsuspend

#include <signal.h> int sigsuspend(const sigset_t* sigmask);
  • 전달받은 sigmask로 signal mask를 set한다. 그리고 프로세스를 suspend하는 작업을 동시에 진행한다.
    • signal이 도착할 때 까지 suspend
  • sigmask는 어떤 시그널로 unblock할지를 확인하는 용도 이다.
  • return 될 때, signal mask는 reset된다.
 

sigsuspend를 잘 사용한 예시

  • 다른 시그널도 다 막는 상황
static volatile sig_atomic_t sigreceived = 0; // maskall => 모든 시그널 // maskmost => 타겟 시그널을 제외한 모든 시그널 // maskold => 이전 시그널 셋을 저장하기 위함 sigset_t maskall, maskmost, maskold; int signum = SIGUSR1; sigfillset(&maskall); sigfillset(&maskmost); sigdelset(&maskmost, signum); sigprocmask(SIG_SETMASK, &maskall, &maskold); if(sigreceived == 0) sigsuspend(&maskmost); sigprocmask(SIG_SETMASK, &maskold, NULL);
  • 다른 시그널은 통과가 가능한 상황
static volatile sig_atmoic_t sigreceived = 0; // maskblocked => 막기 위해서 사용 // maskunblocked => sigsuspend 파라미터 sigset_t maskblocked, maskold, maskunblocked; int signum = SIGUSR1; sigprocmask(SIG_SETMASK, NULL, &maskblocked); sigprocmask(SIG_SETMASK, NULL, &maskunblocked); sigaddset(&maskblocked, signum); sigdelset(&maskunblocked, signum); // while문과 sigsuspend 사이를 막기 위해서 sigprocmask(SIG_BLOCK, &maskblocked, &maskold); while(sigreceived == 0) sigsuspend(&maskunblocked); // 기존의 상태는 maskblocked 상태였기 때문에 maskold를 세팅해주는 것이다. sigprocmask(SIG_SETMASK, &maskold, NULL);

sigwait

#include <signal.h> int sigwait(const sigset_t *restrict sigmask, int *restrict signo);
  • 호출할 시 suspend가 된다.
  • sigmask 중에 아무거나 하나 pending이 되면, 해당 시그널을 pending signal을 pending list에서 삭제하고 나서 return 한다.
    • 삭제한 signal number를 signo에 설정해준다.
  • 삭제된 signal의 signal handler는 호출되지 않는다.
  • 성공했을 시 0 / 실패했을 시 -1
  • sigsuspend와 다른 점
    • sigsuspend에는 원하는 타겟 시그널을 뺀 signal set을 파라미터로 넣는다.
    • sigwait은 파라미터에 원하는 signal number를 넣어야한다.
    • 일단 sigmask 중 하나가 pending 상태가 되어야 한다.
      • 직접 signal을 block하는 것이 아니다.
      • signal mask를 건드리는 일은 없다.
 
#include <signal.h> #include <stdio.h> #include <unistd.h> int main(void){ int signalcount = 0; int signo; int signum = SIGUSR1; sigset_t sigset; if((sigemptyset(&sigset) == -1) || (sigaddset(&sigset, signum) == -1) || (sigprocmask(SIG_BLOCK, &sigset, NULL) == -1 )) perror("Failed to block signals before sigwait"); fprintf(stderr, "This process has ID %ld\n", (long)getpid()); for(;;){ if(sigwait(&sigset, &signo) == -1){ perror("Failed to wait using sigwait"); return 1; } signalcount++; fprintf(stderr, "Number of signals so far: %d\n", signalcount); } }
 

Errors and Async-signal safety

  • 시스템 콜 함수가 signal로 인해 interrupt가 되는 경우는 다시 시작을 해야 하는가?
    • return 값이 -1이고, errno가 EINTR
    • error를 explicitly하게 핸들링하여 다시 시작하도록 구현
    • 내가 사용하는 함수가 interrupt될 수 있는 함수인지 확인해야한다.
  • signal handler가 nonreentrant function을 호출하는 경우
    • 함수의 동작이 중간에 멈추고 다시 실행하면 안되는 함수인 경우
    • signal handler 함수 내에서 호출하는 함수는 reentrant한 함수를 호출해라.
      • async-signal safe한 함수
  • errno변수를 다룰 때
    • main에서도 errno가 설정되고, signal handler 내에서도 errno가 설정되면 main의 errno가 없어질 수 있다.
      • temp 변수에 기존 errno를 저장해두고, 함수가 완료 되면 다시 errno에 설정해두어라
 

Useful rules for signal handling

  • 의심스러운 상황일때에는 ( 내가 호출했던 system call 함수가 signal에 의해 interrupt가 되었을 때에는 ), library 함수를 다시 시작을 하든지, restart library를 사용해라.
  • signal handler에서 사용하는 library function을 확인하여 async-signal safe한 함수인지 확인해라
  • signal handler와 main program code에서 동시에 access할 수 있는 변수, 코드 부분은 potential interactions를 확인해라
  • errno를 적절하게 저장하고 원복해라
 

Program control

  • 프로그램들은 때때로 signal을 이용해서 error handling이 가능하다
    • 긴 계산작업을 실행하는데, 중간에 중단되는 것을 피하기 위해 ctrl-c는 처음 부분으로 돌아가서 restart 하는 것으로 실행 시퀀스를 변경하는 예시
  • Indirect handling signals
    • ctrl-c에 대해 응답은 flag 변수를 설정하여 값에 따라 어떤 구문을 실행할 지 프로그램을 짜라.
    • 하지만 코드가 복잡해질 수 있다.
  • Direct approach
    • sigsetjmp, siglongjmp ( 특정 위치로 jump )
    •  

sigsetjmp and siglongjmp

#include <setjmp.h> void siglongjmp(sigjmp_buf env, int val); int sigsetjmp(sigjmp_buf env, int savemask);
  • sigsetjmp()
    • 호출을 하게 되면, 나중에 siglongjmp를 만나게 되면 sigsetjmp를 호출한 지점으로 jump하게 된다.
    • parameters
      • env: jump해서 왔을 때, 기존 함수를 실행했을 때 필요한 context들을 저장해놓는 변수
      • savemask: 0이 아니라면 signal mask 상태 또한 같이 저장을 한다.
    • return values
      • 다음에 jump했을 때 돌아올 위치를 지정했을 때 0
      • jump해서 돌아왔을 때 longjmp에서 지정한 값을 받음
  • siglongjmp()
    • env: 어디로 jump할 지 정한다.
    • val: sigsetjmp를 통해 return 할 값을 정한다.
 

Example of siglongjmp/sigsetjmp

#include <setjmp.h> #include <signal.h> #include <stdio.h> #include <unistd.h> static sigjmp_buf jmpbuf; // 1이어야 jump를 해도 된다. static volatile sig_atomic_t jumpok = 0; /* ARGSUSED */ static void handler(int signo){ if (jumpok == 0) return; siglongjmp(jmpbuf, 1); } int main(void){ struct sigaction act; act.sa_flags = 0; act.sa_handler = handler; if((sigemptyset(&act.sa_mask) == -1) || (sigaction(SIGINT, &act, NULL) == -1)){ perror("Failed to set up SIGINT handler"); return 1; } fprintf(stderr, "This is process %ld\n", (long)getpid()); if(sigsetjmp(jmpbuf, 1)) fprintf(stderr, "Returned to main loop due to ^c\n"); jumpok = 1; for(;;); }
 

Programming with asynchronous I/O

Asynchronous I/O

  • aio_read(), aio_write(), aio_return(), aio_error()
#include <aio.h> int aio_read(struct aiocb* aiocbp); int aio_write(struct aiocb* aiocbp);
  • aio_read()
    • 읽기 작업을 위한 요청을 queue에 넣어 background에서 진행 된다.
    • 성공했을 시 0 / 실패했을 시 -1
  • aio_write()
    • 쓰기 작업을 위한 요청을 queue에 넣어 background에서 진행 된다.
    • 성공했을 시 0 / 실패했을 시 -1

struct aiocb structure

  • 기존 fd, buf, nbytes의 역할과 같은 필드들
    • int aio_fildes;
    • volatile void *aio_buf;
    • size_t aio_nbytes;
  • off_t aio_offset;
    • I/O가 시작될 file offset
  • int aio_reqprio;
    • 요청의 우선순위를 변경 가능
  • struct sigevent aio_sigevent;
    • I/O가 완료되었을 때 OS가 signal을 보내줄 수 있다. 그 시그널을 받을 것인지
      • 시그널을 받는다면 몇번 시그널로 받을 것인지
    • aio_sigevent.sigev_notify가 SIGEV_NONE으로 설정한다면, signal로 통지받지 않는다.
    • SIGEV_SIGNAL로 설정한다면 signal로 통지를 받으며, aio_sigevent.sigev_signo 에 몇 번 signal로 통지받을 지 등록 가능
  • int aio_lio_opcode;
    • 여러개의 비동기 I/O 를 한번에 요청할 때
 

return and error

#include <aio.h> ssize_t aio_return(struct aiocb* aiocbp); int aio_error(const struct aiocb* aiocbp);
  • aio_return()
    • 기존 비동기 I/O가 완료된 return 값을 받을 수 있다.
  • aio_error()
    • 기존 비동기 I/O의 진행사항을 monitoring할 수 있다.
      • 0 ⇒ 완료
      • EINPROGRESS ⇒ 진행 중
      • error code ⇒ 에러
 

aio_suspend

#include <aio.h> int aio_suspend(const struct aiocb* const list[], int nent, const struct timespec* timeout);
  • I/O 비동기 작업을 완료될 때까지 기다리는 함수
    • 완료가 되면 return
  • parameters
    • list: 요청한 구조체의 array
    • nent: list의 element 개수
    • timeout: 해당 시간 까지만 기다린다. / NULL이면 계속 기다림
      • aio_error는 더이상 EINPROGRESS를 반환하지 않는다.
  • return values
    • 성공했을 시 0 / 실패했을 시 -1
    •  

aio_cancel

#include <aio.h> int aio_cancel(int fildes, struct aiocb* aiocbp);
  • I/O 비동기 요청을 취소하고 싶다.
  • parameter
    • aiocbp: 어떤 요청을 했었는지 사항 지정
      • NULL이라면, fildes에 해당하여 요청했던 모든 I/O 비동기 요청을 모두 취소해라
  • return values
    • AIO_CANCELED: 성공
    • AIO_NOTCANCELED: 요청한 I/O 중 하나라도 cancel되지 못한 요청이 있을 경우
    • AIO_ALLDONE: 이미 다 완료가 되었을 경우
    • -1: 실패했을 경우
    •