What is POSIX error handling?
int ret = some_system_call() if(ret == ERROR_CODE){ switch(errno){ // Do different stuff based on the errno number. }
커널에서 goto는 어플리케이션의 다른 파트를 정리하기 위해 주로 사용됩니다. goto는 코드를 더 읽기 어렵게 만들기 때문에 사용하지 않는 것이 좋습니다.
What is errno and when is it set?
What about multiple threads?
When is errno reset to zero?
What are the gotchas and best practices of using errno?
// Unsafe - the first fprintf may change the value of errno before we use it! if (-1 == sem_wait(&s)) { fprintf(stderr, "An error occurred!"); fprintf(stderr, "The error value is %d\n", errno); } // Better, copy the value before making more system and library calls if (-1 == sem_wait(&s)) { int errno_saved = errno; fprintf(stderr, "An error occurred!"); fprintf(stderr, "The error value is %d\n", errno_saved); }
비슷한 맥락으로, Signal handler가 system call이나 library call을 했을 때, errno의 원래 값을 저장했다가 함수들이 반환된 이후에 복구하는 것은 좋은 습관입니다.
void handler(int signal) { int errno_saved = errno; // make system calls that might change errno errno = errno_saved; }
How can you print out the string message associated with a particular error number?
char *mesg = strerror(errno); fprintf(stderr, "An error occurred (errno=%d): %s", errno, mesg);
How are perror and strerror related?
void perror(char *what) { fprintf(stderr, "%s: %s\n", what, strerror(errno)); }
What are the gotchas of using strerror?
pthread_mutex_lock(&m); char *result = strerror(errno); char *message = malloc(strlen(result) + 1); strcpy(message, result); pthread_mutex_unlock(&m); fprintf(stderr, "An error occurred (errno=%d): %s", errno, message); free(message);
다른 대안으로는 포터블하지는 않지만 Thread-safe 인 strerror_r을 사용하는 것입니다. perror은 thread-safe이므로 가능하다면 perror를 사용하는 것이 multithread 환경에서 선호되어집니다.
What is EINTR? What does it mean for sem_wait? read? write?
일부 시스템 콜은 프로세스에 전달되는 signal에 의해 interrupted될 수 있습니다. 이 때 시스템 콜은 아무런 작업도 하지 않고 리턴될 수도 있습니다. 예를 들면 bytes는 아무것도 읽거나 쓰지 않을 수도 있고, semaphore wait은 wait하지 않을 수도 있습니다.
이러한 interruption은 errno의 값이 EINTER인지 체크해 확인할 수 있습니다. 이러한 경우 system call은 다시 시도되어야 합니다. System call(sem_wait같은) 을 감싸고 있는 아래와 같은 반복문이 일반적입니다.
while ((-1 == systemcall(...)) && (errno == EINTR)) { /* repeat! */}
= EINTR이 아닌== EINTR 로 쓴다는 것에 주의하세요.
또는, system call의 반환값이 나중에 사용된다면 아래와 같이 사용합니다.
while ((-1 == (result = systemcall(...))) && (errno == EINTR)) { /* repeat! */}
리눅스에서 local disk에 read와 write를 호출하는 것은 일반적으로 EINTR로 반환되지 않습니다.(대신 자동적으로 재시작됩니다.) 하지만 network stream에 대응하는 File Descriptor에 read와 write를 호출할 때에는 EINTR을 리턴할 수 있습니다.
Which system call may be interrupted and need to be wrapped?
리눅스 signal 7 man page에 의하면
System call이나 library function이 블록되었을 때 signal hanndler가 동작하면,
- signal handler가 반환 된 후 자동적으로 재시작
- error EINTR로 실패.
- Read(2), readv(2), write(2), wirtev(2), ioctl(2) 호출이 "Slow" device에 이루어질 때. Slow device는 I/O 호출이 명확하지 않은 시간동안 블록되는 것입니다. 예를 들면, 터미널, pipe, 또는 socket같은 것입니다. (이 정의에서 disk는 느린 디바이스가 아닙니다) 만약 느린 디바이스에서 I/O 호출이이미 데이터를 조금이라도 전송한 상태에서 signal handler에 의해 interrupt되었다면 그 system call은 성공한 status를 반환할 것입니다(일반적으로 전송된 바이트 수).
Errno exceptions?
'Angrave System Programming > Networking' 카테고리의 다른 글
Networking: Nonboloking IO, select(), and epoll (0) | 2019.04.16 |
---|---|
Networking: Creating a UDP server (0) | 2019.04.16 |
Networking: Shutting down ports, reusing ports and other tricks (0) | 2019.04.11 |
Networking: Building a simple TCP Server (0) | 2019.04.10 |
Networking: Building a simple TCP Client (0) | 2019.04.10 |