Linux Programmer

정오표 : Advanced 리눅스 시스템 네트워크 프로그래밍 3판 본문

저술 관련/리눅스 시스템 네트워크

정오표 : Advanced 리눅스 시스템 네트워크 프로그래밍 3판

sunyzero 2016. 8. 19. 03:07

Advanced 리눅스 시스템 네트워크 프로그래밍 3판 오탈자 정오표 (2019.09.09 버전)

* 최근 업데이트 목록은 맨 아래의 history를 참고해 주시기 바랍니다.

* 변경점에 대해서 쉽게 찾아보실 수 있도록 글자 배경색을 오렌지 색으로 표시해두었습니다.

* 최신의 예제 소스 코드는 http://sunyzero.tistory.com/242 에서 다운받으시기 바랍니다.

 

Chapter 2. 파일 처리

 

* p.80 코드 2.2의 13행 : 오타

 수정전  dprintf(fd, "PID[%d] Low lovel file handle\n", getpid());
수정후  dprintf(fd, "PID[%d] Low level file handle\n", getpid());

 

 

 

 

 

 

Chapter 4. 메모리

 

* P.112 표 4.2 : 오타

수정전

[표 4.2] 전역변수들의 형태에 따른 메모리 위치

 

int num;
bss에 위치
int num=1;
data에 위치
char str[] = "hello";
data에 위치 (읽기/쓰기 가능)
char *p_str = "hello";
문자열 hello .rodata, p_str 포인터 변수는 data에 위치
const char str[] = "hello";
문자열 hello .rodata, str 변수는 data에 위치
static int i_val;
bss에 위치

 

수정후

[표 4.2] 전역변수들의 형태에 따른 메모리 위치

 

int num; bss에 위치
int num=1; data에 위치
char str[] = "hello"; data에 위치 (읽기/쓰기 가능)
char *p_str = "hello"; 문자열 hello .rodata, p_str 포인터 변수는 data에 위치
const char str[] = "hello"; 문자열 hello .rodata, str 변수는 .rodata에 위치
static int i_val; bss에 위치

 

 

Chapter 5. IPC (Inter-Process Communication)

 

* p.162 코드 5.9의 39행 : 오타

 수정전  printf("size(%d) # of attach(%ld)\n", shm_ds.shm_segsz, shm_ds.shm_nattch);
수정후  printf("size(%zd) # of attach(%zd)\n", shm_ds.shm_segsz, shm_ds.shm_nattch);

설명 : x86 리눅스에서는 zd 대신에 ld를 사용해도 된다.

 

* p.162 코드 5.9의 44행 : 오류는 아님. 출력을 예쁘게 하기 위해 개행 문자를 없애는 코드 추가

 수정전  memcpy(shm_ptr, p_input, n_read);    /* 공유 메모리에 입력 텍스트 복사 */
수정후  p_input[n_read - 1] = 0;   /* 개행문자를 제거 */
 memcpy(shm_ptr, p_input, n_read - 1);    /* 공유 메모리에 입력 텍스트 복사 */

 

 

* p.168 코드 5.10의 27, 39행 : 오류는 아님. 출력을 예쁘게 하기 위한 코드 수정 및 추가

 수정전  printf("'*' PRint current shm.\n'.' Exit.\n"); /* 27행 */
 ....생략
 memcpy(shm_ptr, p_input, n_read); /* 공유 메모리에 텍스트 복사 */ /* 39행 */
수정후  printf("'*' Print current shm.\n'.' Exit.\n"); /* 27행 */
 ...생략
 p_input[n_read - 1] = 0; /* 개행문자를 제거 */ /* 39~40행 */
 memcpy(shm_ptr, p_input, n_read - 1); /* 공유 메모리에 텍스트 복사 */
 

 

 

* p.176 첫문단 및 표 5.16 : 오타

수정전

XSI 세마포어는 세마포어 세트라는 배열 단위로 할당된다세마포어 세트에는 최소 1 이상의 세마포어가 포함되어야하며  5.14 같은 정보를 가지고 있다하지만 세마포어는 커널 객체이므로  5.16 값들에 직접 접근할 수는 없고 관련 시스템 호출 함수로만 가능하며 관련 함수는  5.17 정리해두었다.

 

[ 5.16] XSI 세마포어의 중요 값들

semval 현재 세마포어 값
sempid 마지막으로 세마포어에 접근했던 프로세스의 PID
semcnt 세마포어 카운트(semval)이 양수가 되기를 대기하는 프로세스의 개수
semnzcnt 세마포어 카운트(semval) 0이 되기까지 대기하는 프로세스의 개수

 

 

수정후

XSI 세마포어는 세마포어 세트라는 배열 단위로 할당된다. 세마포어 세트에는 최소 1 이상의 세마포어가 포함되어야하며 5.16 같은 정보를 가지고 있다. 하지만 세마포어는 커널 객체이므로 5.16 값들에 직접 접근할 수는 없고 관련 시스템 호출 함수로만 가능하며 관련 함수는 5.17 정리해두었다.

 

[ 5.16] XSI 세마포어의 중요 값들

semval
현재 세마포어 값
sempid
마지막으로 세마포어에 접근했던 프로세스의 PID
semncnt
세마포어 카운트(semval)이 양수가 되기를 대기하는 프로세스의 개수
semzcnt
세마포어 카운트(semval) 0이 되기까지 대기하는 프로세스의 개수

 

 

 

* p.177 아래에서 6번째 행 : 오타

 수정전  semflg 플래그는 shmget을 설명할 때 사용했던 [표 5.7]의 플래그가 그대로 사용된
수정후  semflg 플래그는 shmget을 설명할 때 사용했던 [표 5.10]의 플래그가 그대로 사용된

 

 

* p.189 코드 20의 72행 : 오타

 수정전  sem_buf.sem_flg = 0;
수정후  sem_buf.sem_flg = SEM_UNDO;

설명 : SEM_UNDO 플래그가 빠져있었음

 

* p.202 본문 : 오타

 수정전 그러면 이제 교착상태에 빠지지 않도록 코드 5.24 55 행을 제거하여 정상 작동 시켜보자. 정상 작동시 서로 다른 프로세스가 세마포어를 공유하는지 확인도 해봐야 한다.
수정후 그러면 이제 교착상태에 빠지지 않도록 코드 5.26 55 행을 제거하여 정상 작동 시켜보자. 정상 작동시 서로 다른 프로세스가 세마포어를 공유하는지 확인도 해봐야 한다.

설명 : 코드 번호가 잘못되어있음

 

* p.204 코드 5.27의 17행 : 오타

 수정전  if (sem_init(&psem, 0, n_count) != -1) { /* 17행 */
    /* error */
 }
수정후  if (sem_init(&psem, 0, n_count) == -1) { /* error */
    return 1;
 }

 

 

* p.219 POSIX 메시지 큐 항목의 2번째 문단 : 매끄럽지 못한 글을 수정함

 수정전  과거 2000년도 초반만 하더라도 POSIX 메시지 큐는 지원되지 않는 플랫폼도 많았고 성능적인 면에서도 불이익이 많았는지 지금은 대부분의 시스템에서도 지원되고 있으며 성능적인 면에서도 불이익이 거의 없어졌다. 
수정후  과거 2000년도 초반만 하더라도 POSIX 메시지 큐는 지원되지 않는 플랫폼도 많았고 성능적인 면에서도 불이익이 많았다. 하지만 지금은 대부분의 시스템에서 지원되고 있으며 성능적인 면에서도 불이익이 거의 없어졌다. 

 

 

Chapter 6. 네트워크 프로그래밍

 

* p.238 코드 6.4의 16~17행 : 오타

 수정전  if (p_buf[rc_getline - 1] == '\n') rc_getline--;  /* 개행 문자 제거 */
 if ((rc_write = write(fd, a_input, strlen(a_input))) == -1) {   /* error */  } /* 17행 */
수정후
 if (p_buf[rc_getline - 1] == '\n') rc_getline--;  /* 마지막이 개행문자라면 rc_getline--로 개행문자 write를 하지 않도록 함 */
 if ((rc_write = write(fd, p_buf, rc_getline)) == -1) { /* error */ } /* 17행 */

 

* p.242 표 6.2의 16~17행 : 편집 중 오타/ 오류

수정후

[ 6.2] 데이터그램 소켓과 스트림 소켓의 비교

 

  데이터그램 소켓 스트림 소켓
데이터 경계 파일경로 보존 안됨
데이터 크기 제한 보존됨 없음
데이터 순서 보존 안됨 보존됨
연결 과정 필요 없음
(1:n 통신 가능)
필요함
(1:1 통신)
신뢰성 낮음
(데이터 유실시 복구 없음)
높음
(데이터 유실시 재전송)
 

 

수정후

[ 6.2] 데이터그램 소켓과 스트림 소켓의 비교

 

  데이터그램 소켓 스트림 소켓
데이터 경계 보존됨 보존 안됨
데이터 크기 제한 있음 없음
데이터 순서 보존 안됨 보존됨
연결 과정 필요 없음
(1:n 통신 가능)
필요함
(1:1 통신)
신뢰성 낮음
(데이터 유실시 복구 없음)
높음
(데이터 유실시 재전송)

 

 

* p.257 코드 6.8의 4행 : 오타

 수정전  saddr_s.sin_port = htons(listen_port); // 빅 엔디안으로 변환
수정후
 saddr_s.sin_port = htons(port_listen); // 빅 엔디안으로 변환

 

 

* p.271 코드 6.14의 78, 80행 : 오류는 아님. 출력을 예쁘게 하기 위해 개행 문자를 없애는 코드 추가

 수정전  break;; /* 78행 : 세미콜론이 2개가 타이핑 됨. 오류를 일으키지는 않으나 수정할 필요가 있음. */
 }
 pr_out("[Child:%d] RECV(%.*s)", idx, ret_len, buf); /* 80행 */
수정후  break;
 }
 pr_out("[Child:%d] RECV(%.*s)", idx, buf[ret_len-1] == '\n' ? ret_len-1 : ret_len, buf); /* 개행 문자를 출력하지 않도록 함 */

 

 

* p.274 그림 6.5 아래 문단 : 오타

 수정전  우선 TCP에서 연결 상태를 표시하는 용어에 대해 알아둬야 한다. 
일반적으로 TCP에서 사용하는 연결상태는 LISTEN, SYN_SENT, SYN_RCVD, ESTABLISHED, CLOSE_WAIT, FIN_WAIT1, FIN_WAIT2, LASK_ACK, TIME_WAIT, CLOSED 등등 여러가지가 있다. TCP 연결 상태를 보는 방법은 간단하게 netstat나 ss 명령으로 확인할 수 있다. 그림 6.5를 살펴보자. 
수정후  우선 TCP에서 연결 상태를 표시하는 용어에 대해 알아둬야 한다. 
일반적으로 TCP에서 사용하는 연결상태는 LISTEN, SYN_SENT, SYN_RCVD, ESTABLISHED, CLOSE_WAIT, FIN_WAIT1, FIN_WAIT2, LAST_ACK, TIME_WAIT, CLOSED 등등 여러가지가 있다. TCP 연결 상태를 보는 방법은 간단하게 netstat나 ss 명령으로 확인할 수 있다. 그림 6.5를 살펴보자. 

 

 

* p.285 아래에서 2번째 행 : 오타 (행 번호 오타)

 수정전  11행은 유닉스 타임을 포함한 문자열을 sbuf에 저장하고 12행에서 sendto를 이용해서 송신한다. 14~16행은 데이터를 수신하고 그것의 주소와 길이, 실제 내용을 출력한다.
수정후  12행은 유닉스 타임을 포함한 문자열을 sbuf에 저장하고 13행에서 sendto를 이용해서 송신한다. 15~17행은 데이터를 수신하고 그것의 주소와 길이, 실제 내용을 출력한다.

 

 

* p.322 코드 6.23의 98행 : 오류는 아님. 출력을 예쁘게 하기 위해 개행 문자를 없애는 코드 추가

 수정전  pr_out("[Child:%d] RECV(%.*s)", idx, ret_len, buf);
수정후  pr_out("[Child:%d] RECV(%.*s)", idx, buf[ret_len-1] == '\n' ? ret_len-1 : ret_len, buf); /* 개행 문자를 출력하지 않도록 함 */

 

 

* p.333 코드 6.28의 48행 : 오타

 수정전  if (getsockname(fd, (struct sockaddr *)&sae_local, &len_sae_local) == -1) {
    pr_err("Fail: getpeername()");
    exit(EXIT_FAILURE);
 }
수정후  if (getsockname(fd, (struct sockaddr *)&sae_local, &len_sae_local) == -1) {
    pr_err("Fail: getsockname()");
    exit(EXIT_FAILURE);
 }

 

 

* p.347 위에서 3번째 행 : 오타

 수정전  이트 이상 버퍼에 쌓여야지만 recv가 리된다.
수정후  이트 이상 버퍼에 쌓여야지만 recv가 리된다.

 

 

* p.360 위에서 3번째 문단 : 오타 (코드 번호 오타)

 수정전  24~29번행은 select를 이용해서 쓰기 가능 상태인지 검사하는 코드이다. 그런데 코드 6.28은 간단하게 예제를 보여주고 넌블록킹 connect가 어떤 흐름으로 작성되는지를 보이는게 목적이므로 타임 아웃이라든지 에러 처리는 하지 않았다. 
수정후  24~29번행은 select를 이용해서 쓰기 가능 상태인지 검사하는 코드이다. 그런데 코드 6.29는 간단하게 예제를 보여주고 넌블록킹 connect가 어떤 흐름으로 작성되는지를 보이는게 목적이므로 타임 아웃이라든지 에러 처리는 하지 않았다. 

 

 

* p.371 코드 6.32의 3,5행 : 쓰이지 않은 변수 (rc_gai, addrstr, portstr)

 수정전  int cfd, rc_gai, ret_recv, cum_recv, ret_sockatmark;
 socklen_t len_saddr;
 char buf[0xff], addrstr[INET6_ADDRSTRLEN], portstr[8];
수정후  int cfd, ret_recv, cum_recv, ret_sockatmark;
 socklen_t len_saddr;
 char buf[0xff];

 

* p.372 코드 6.32의 30행 : 오타 (메시지 부분의 오타이므로 컴파일에는 문제가 없음)

 수정전  pr_out("ret_sockatmakr = %d", ret_sockatmark);
수정후  pr_out("ret_sockatmark = %d", ret_sockatmark);

 

 

Chapter 7. I/O 멀티플렉싱

 

* p.391 코드 7.2 65~70행 : 특정 행 및 변수가 누락됨 (이 오류는 배포되는 소스코드에는 정상적으로 되어있으므로 수정하기 힘들다면, 배포되는 소스코드를 참고한다)

 수정전         if ((ret_select = select(fd_biggest+1, &fds_read, NULL, NULL, NULL)) == -1) {
            /* error */
        }
        if (FD_ISSET(fd_listener, &fds_read)) { /* 리스너 소켓에 이벤트가 있는가? */
          /* 현재 리스너 소켓은 블록킹 모드이므로 accept를 한번씩만 호출하여 접속을 받아들인다.
             백로그에 복수의 접속 요청이 있어도 매번 루프를 돌면서 접속을 받는다. 
            이는 비효율적이므로 리스너 소켓을 넌블럭킹으로 하고 루프를 돌면서 처리하는 것이 좋다. */
            struct sockaddr_storage saddr_c;
            len_saddr = sizeof(saddr_c);
            fd = accept(fd_listener, (struct sockaddr *)&saddr_c, &len_saddr);
수정후         if ((ret_select = select(fd_biggest+1, &fds_read, NULL, NULL, NULL)) == -1) {
            /* error */
        }
        pr_out("\tselect = (%d)", ret_select);
        if (FD_ISSET(fd_listener, &fds_read)) { /* 리스너 소켓에 이벤트가 있는가? */
          /* 현재 리스너 소켓은 블록킹 모드이므로 accept를 한번씩만 호출하여 접속을 받아들인다.
             백로그에 복수의 접속 요청이 있어도 매번 루프를 돌면서 접속을 받는다. 
            이는 비효율적이므로 리스너 소켓을 넌블럭킹으로 하고 루프를 돌면서 처리하는 것이 좋다. */
            struct sockaddr_storage saddr_c;
            len_saddr = sizeof(saddr_c);
            fd = accept(fd_listener, (struct sockaddr *)&saddr_c, &len_saddr);

 

 

* p.398 코드 7.4의 9행 : 쓰이지 않은 변수 (ret_ionread)

 수정전  int     i, fd, fd_listener, ret_recv, ret_ionread, ret_poll;
수정후  int     i, fd, fd_listener, ret_recv, ret_poll;

 

 

* p.417 코드 7.7의 5행 : 오타

 수정전 struct epoll_event  ev;
ev.events = EPOLLIN ;   /* 입력을 감지한다. poll의 POLLIN과 흡사하다. */
ev.data.fd = 0;         /* 0 번 파일기술자는 표준 입력을 의미한다. */
    /* efd는 epoll_create()에 의해 생성된 epoll 파일기술자라고 가정하자. */
if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev) == -1) {
    /* 에러 처리 */
}
수정후 struct epoll_event  ev;
ev.events = EPOLLIN ;   /* 입력을 감지한다. poll의 POLLIN과 흡사하다. */
ev.data.fd = 0;         /* 0 번 파일기술자는 표준 입력을 의미한다. STDIN_FILENO (0)와 같다. */
    /* efd는 epoll_create()에 의해 생성된 epoll 파일기술자라고 가정하자. */
if (epoll_ctl(efd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) {
    /* 에러 처리 */
}

 

 

* p.421 코드 7.8의 50행 : 변수명 오타(max_open_files)

 수정전 if ((ret_poll = epoll_wait(epollfd, ep_events, max_open_files, -1)) == -1) {
    /* error */
}
수정후 if ((ret_poll = epoll_wait(epollfd, ep_events, max_ep_events, -1)) == -1) {
    /* error */
}

 

 

Chapter 8. 스레드 프로그래밍

 

* p.429 2번째 문단 : 오타

 수정전  POSIX 스레드는 약어로 pthread라고 불리며 책의 맨 앞에서 설명했던 IEEE std. 1003.1b-1995 표준으로 승인되었다. 이 후 2001년도에 확장되어 몇 가지 기능이 추가되었다. pthread의 특징으로는 C 언어의 API로 되어있으며 POSIX 계열의 운영체제 대부분에서 지원된다는 점이다. POSIX를 지원하는 윈도 계열에도 포팅되어 있다. 다만 윈도의 경우에는 비표준인 윈도 네이티브 스레드의 성능이 뛰어나기 때문에 범용성이 중요한 경우를 제외하고는 pthread를 거의 사용하지 않는다.
수정후  POSIX 스레드는 약어로 pthread라고 불리며 책의 맨 앞에서 설명했던 IEEE std. 1003.1c-1995 표준으로 승인되었다. 이 후 2001년도에 확장되어 몇 가지 기능이 추가되었다. pthread의 특징으로는 C 언어의 API로 되어있으며 POSIX 계열의 운영체제 대부분에서 지원된다는 점이다. POSIX를 지원하는 윈도 계열에도 포팅되어 있다. 다만 윈도의 경우에는 비표준인 윈도 네이티브 스레드의 성능이 뛰어나기 때문에 범용성이 중요한 경우를 제외하고는 pthread를 거의 사용하지 않는다.

 

* p.471 표 8.6

수정전

 

[표 8.6] pthread 조건 변수 관련 함수 및 매크로

 

 

 

pthread_cond_init 조건 변수 구조체를 초기화 한다.
pthread_cond_wait 조건 변수에서 대기(블록킹)한다. 시그널을 받을 때까지 대기한다.
pthread_cond_timedwait 조건 변수에서 대기한다. 지정된 타임 아웃 시간이 되면 깨어난다.
pthread_cond_signal 조건 변수에서 대기하는 스레드 1개에 시그널을 전송하여 깨운다.
pthread_cond_signal 조건 변수에서 대기하는 모든 스레드에 시그널을 전송하여 깨운다.
pthread_cond_destroy 조건 변수를 파괴한다.
PTHREAD_COND_INITIALIZER pthread_cond_t 조건 변수를 초기화하는 매크로

 

수정후

 

[표 8.6] pthread 조건 변수 관련 함수 및 매크로

 

 

 

pthread_cond_init 조건 변수 구조체를 초기화 한다.
pthread_cond_wait 조건 변수에서 대기(블록킹)한다. 시그널을 받을 때까지 대기한다.
pthread_cond_timedwait 조건 변수에서 대기한다. 지정된 타임 아웃 시간이 되면 깨어난다.
pthread_cond_signal 조건 변수에서 대기하는 스레드 1개에 시그널을 전송하여 깨운다.
pthread_cond_broadcast 조건 변수에서 대기하는 모든 스레드에 시그널을 전송하여 깨운다.
pthread_cond_destroy 조건 변수를 파괴한다.
PTHREAD_COND_INITIALIZER pthread_cond_t 조건 변수를 초기화하는 매크로

 

 

* p.480 코드 8.11의 107행 : wq-cnt 뒤에 콤마(comma)가 누락됨

 수정전 pr_out("[B] pop(%d,%d) item(%c) (tid=%ld)", 
    wq->idx, wq->cnt (char)*item, pthread_self());
수정후 pr_out("[B] pop(%d,%d) item(%c) (tid=%ld)", 
    wq->idx, wq->cnt, (char)*item, pthread_self());

 

 

* p.484 코드 8.13의 26행 : ftruncate 부분이 2번째 실행부터 작동되는 문제

 수정전

if ( (shm_fd = shm_open(shm_path, O_CREAT|O_RDWR|O_EXCL, 0660)) == -1) { if (errno == EEXIST) { shm_fd = shm_open(shm_path, O_RDWR, 0660); } else { /* error */ exit(EXIT_FAILURE); } ftruncate(shm_fd, SHM_SEGMENT); }

수정후

if ( (shm_fd = shm_open(shm_path, O_CREAT|O_RDWR|O_EXCL, 0660)) == -1) { if (errno == EEXIST) { shm_fd = shm_open(shm_path, O_RDWR, 0660); } else { /* error */ exit(EXIT_FAILURE); } } struct stat statbuf = {}; if (fstat(shm_fd, &statbuf) == -1) { exit(EXIT_FAILURE); } if (statbuf.st_size < SHM_SEGMENT) { ftruncate(shm_fd, SHM_SEGMENT); }

ftruncate의 위치가 잘못되어, 프로세스를 첫 번째 실행할 때는 Bus error로 프로세스가 강제종료된다. 그리고 두 번째부터 제대로 실행되는 문제가 있었다. 따라서 수정한 코드에는 fstat로 shared memory의 크기를 먼저 검사하고, 크기가 작다면 ftruncate 함수를 호출하는 구조로 변경하였다.

 

 

* p.514 두 번째 문단 : 오타 (s가 누락됨)

 수정전 첫 번째 방법은 num_thread(#) 지시어를 추가하는 방법으로 #pragma omp parallel num_threads(2)처럼 지시하면 2개의 스레드를 생성하게 된다. 
수정후 첫 번째 방법은 num_threads(#) 지시어를 추가하는 방법으로 #pragma omp parallel num_threads(2)처럼 지시하면 2개의 스레드를 생성하게 된다. 

 

 

Chapter 9. 시그널

 

* p.580 다섯 번째 문단 : 맞춤법 오류

 수정전 프로세스의 경우도 프로세스의 이미지 부분과 프로세스의 PID, 실행 권한, 생성 시간 등은 메타 데이터는 분리되어있다.
수정후 프로세스의 경우도 프로세스의 이미지 부분과 프로세스의 PID, 실행 권한, 생성 시간 등의 메타 데이터는 분리되어있다.

 

* p.600 첫번째 문단 : 오타

 수정전  앞서 sigaction으로 시그널 핸들러를 설치할 때 시그널 블록 매스크인 sa_mask 멤버에 대해 살펴보았다. 
그런데 sigaction의 sa_mask는 시그널 핸들러가 실행되는 동안에 임시적으로 블록할 시그널 리스트를 설정하는 기능인데 
이번에는 임시가 아닌 시스템 전역에서 영구적으로 사용 가능한 시그널 블록 매스크를 설정하고 해제하는 방법을 살펴보도록 할 것이다.
수정후  앞서 sigaction으로 시그널 핸들러를 설치할 때 시그널 블록 매스크인 sa_mask 멤버에 대해 살펴보았다. 
그런데 sigaction의 sa_mask는 시그널 핸들러가 실행되는 동안에 임시적으로 블록할 시그널 리스트를 설정하는 기능인데 
이번에는 임시가 아닌 프로세스 전역에서 영구적으로 사용 가능한 시그널 블록 매스크를 설정하고 해제하는 방법을 살펴보도록 할 것이다.

 

* p.605 네 번째 문단의 2번째 행 : 행번호 오류

 수정전 백업받은 sigset_oldmask는 시그널 블록 구간이 끝나고 복원하는 25행에서 사용된다.
수정후 백업받은 sigset_oldmask는 시그널 블록 구간이 끝나고 복원하는 33행에서 사용된다.

 

 

* p.615 코드 9.11의 33,34행 : 오타

 수정전 snprintf(g_ss.ss_sp, g_ss.ss_size, 
  "SEGV: Time(%02d:%02d:%02d)",
  tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec); /* 대체 스택에 기록할 정보 */
수정후 snprintf(g_ss.ss_sp, g_ss.ss_size, 
  "SEGV: SigNo(%d) Time(%02d:%02d:%02d)",
  signum, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec); /* 대체 스택에 기록할 정보 */

 

 

Chapter 10. 리얼타임 확장

 

* p.652 페이지 가장 하단의 문단

 수정전 특징으로는 read, write는 소켓이나 파이프에도 모두 사용할 수 있지만 AIO는 디스크 및 블록 장치로의 입출력에만 사용 가능한 기법이다. 따라서 네트워킹에서는 사용 할 수 없다.
수정후 리눅스에 AIO가 처음 도입되던 시기에는 디스크 및 블록 장치만 지원했으나, 커널 3.x 이후로는 네트워크 소켓에서도 사용할 수 있게 되었다.

 

(참고) 주로 사용되는 레드햇 리눅스 7 (CentOS 7) , 우분투 14 이상은 모두 커널 3.x 이후를 사용하므로 AIO의 네트워크 소켓 통신을 지원한다.

 

 

* p.655 페이지 가장 하단에서 3번째 문단

 수정전 동기적 입출력 기법에서도 스레드와 같은 비동기적 실행 기법을 사용하면 pread, pwrite를 사용하는 것을 생각하면 된다. 오프셋을 이용하여 파일 입출력을 하므로 기존의 파일 커서 위치를 변경하지는 않는다.
수정후 동기적 입출력 기법에서도 스레드와 같은 비동기적 실행 기법을 사용하면 pread, pwrite를 사용하는 것을 생각하면 된다. 오프셋을 이용하여 파일 입출력을 하므로 기존의 파일 커서 위치를 변경하지는 않는다.
하지만 네트워크 소켓에서 사용할 때는 aio_offset의 값은 무시되고, 항상 버퍼(aio_buf)의 시작 위치, 즉 0번 오프셋으로 고정된다.

 

 

* p.660 코드 10.17의 2,5,15행 : 오타

 수정전 #ifdef ASYNCHRONIZED_IO
#include <pthread.h>
void  start_sigev_aio(sigval_t   arg);  /* 리얼타임 시그널 이벤트, 쓰레드 함수 */
pthread_attr_t   pt_attr;
#endif
int main(int argc, char *argv[]) {
    int     fd_rd, fd_wr;  /* 읽기용 파일 기술자, 쓰기용 파일 기술자 */
    int     i =0, tot_len = 0, ret;
    char    ofname[0xff], rbuf[NUM_AIOCB_ARRAY][1024 * 256];
    struct  aiocb  aio_blk[NUM_AIOCB_ARRAY];
    struct  aiocb  *aiolist[] = {
          &aio_blk[0],  &aio_blk[1],
          &aio_blk[2],  &aio_blk[3],  &aio_blk[4]  };  /* lio_listio에서 사용할 구조체 */
#ifdef ASYNCHRONIZED_IO
    struct sigevent sigev = { .sigev_notify=SIGEV_THREAD };/* I/O 완료시 쓰레드 생성 */
#endif
수정후 #ifdef ASYNCHRONIZED_LIO
#include <pthread.h>
void  start_sigev_aio(sigval_t   arg);  /* 리얼타임 시그널 이벤트, 쓰레드 함수 */
pthread_attr_t   pt_attr;
pthread_barrier_t pt_barrier;
#endif
int main(int argc, char *argv[]) {
    int     fd_rd, fd_wr;  /* 읽기용 파일 기술자, 쓰기용 파일 기술자 */
    int     i =0, tot_len = 0, ret;
    char    ofname[0xff], rbuf[NUM_AIOCB_ARRAY][1024 * 256];
    struct  aiocb  aio_blk[NUM_AIOCB_ARRAY];
    struct  aiocb  *aiolist[] = {
          &aio_blk[0],  &aio_blk[1],
          &aio_blk[2],  &aio_blk[3],  &aio_blk[4]  };  /* lio_listio에서 사용할 구조체 */
#ifdef ASYNCHRONIZED_LIO
    struct sigevent sigev = { .sigev_notify=SIGEV_THREAD };/* I/O 완료시 쓰레드 생성 */
#endif

 

 

Chapter 11. 리눅스 비표준 기능

 

* p.680 코드 11.5의 25행 : for문의 초기화 부분 누락

 수정전 for(int i; i<MAX_POOL; i++)
        start_child(sfd_child, sigmask_child);
수정후 for(int i=0; i<MAX_POOL; i++)
        start_child(sfd_child, sigmask_child);

 

* p.690 코드 11.6의 164행 : 닫는 중괄호(right brace) 1개 누락

 수정전     if (epoll_ctl(efd, EPOLL_CTL_ADD, ret_fds->timerfd, &ev) == -1) {
        pr_err("fd(%d) EPOLL_CTL_ADD  Error(%d:%s)", fd, errno, strerror(errno));
        return -1;
    }
return 0;
수정후     if (epoll_ctl(efd, EPOLL_CTL_ADD, ret_fds->timerfd, &ev) == -1) {
        pr_err("fd(%d) EPOLL_CTL_ADD  Error(%d:%s)", fd, errno, strerror(errno));
        return -1;
    }
} /* 누락되었던 괄호 */
return 0;

 


* History

2022.07.09 p202. 본문 코드 번호 오타 (익명의 제보자님 감사합니다)

2019.09.09 p.391, p.655 정오표 재수정 (제보해주신 Emacs유저님 감사합니다.)

2018.02.07 p.484

2017.10.11 p.652 , p.655

2016.11.20 p.347 (hkskyp유저님 감사합니다)

2016.09.23 p.242 , p.274 , p.429 , p.600

2016.08.19 첫 판 올림 (오타 제보를 해주시고, 좀 더 예쁘게 편집할 수 있도록 조언을 주신 박강민님께 감사드립니다.)

 

반응형
Comments