[완료] Signal이 read() API를 interrupt하는 경우

lugi의 이미지

LINUX SYSTEM PROGRAMMING이란 책을 읽다가 의문이 생겨서 문의 드립니다.

read()함수설명을 보니 "signal이 interrupt한 경우에 요청한 byte를 다 읽기 전에 return될 수 있다" 라고 되어 있는데, 실제로 이런 경우가 발생하는 적을 본적이 없습니다.

책에는 아래와 같이 while문으로 read를 처리하도록 예시하고 있습니다.

ssize_t ret;

while(len=!0 (ret = read(fd,buf,len)) !=0){
if(ret == -1){
if(errno =- EINTR)
continue;
perror ("read");
break;
}
len -= ret;
buf += ret;
}

물론 SIGKILL이나 SIGSTOP이라면 프로세스가 아예 종료되거나 실행이 멈추어 버릴테니까 논외로 한다면 굳이 read를 while문에 넣어서 요청한 바이트를 모두 읽을 때까지 처리해 주는 것이 필요한지 의심이 듭니다.( local file system에 있는 regular file을 가정할때 말입니다.)
다시 말하면 어떤 SIGNAL이 read 실행시 이를 방해 할수 있을지, 실제로 이런 상황이 발생할 만한 경우에 대한 좋은 예가 있는지 궁금합니다. SIGKILL등은 프로세스가 죽어 버리므로, while문으로 처리해봐야 실행 안될 코드이므로 의미가 없어보입니다.

추가질문1. 이 책에서는 write는 (적어도 regular file에 대해서는) 이러한 partial write가 발생하지 않는다 라고 되어 있는데 왜 그런지도 궁금합니다.

추가질문2. 이러한 signal에 의한 return이 fopen/fread/fwrite/fclose.. 등에서도 동일하게 발생하나요? 즉 fxxxx 함수 사용시에도 이런 경우에 대한 대비 코드가 필요한가요?

감사합니다.

Necromancer의 이미지

시그널때문에 중단되었다면 에러코드에 EINTR이 리턴됩니다.

소켓에서 일정시간 이상 접속이 안 될 경우 이 시그널을 이용해서 탈출하죠.

Written By the Black Knight of Destruction

Written By the Black Knight of Destruction

prether의 이미지

시그널이 오면 되도록이면 시그널이 오자마자 handling해야 겠죠. 그런데 signal handling은 user land에서 해야 합니다.

read() systemcall을 부르면 kernel mode에서 I/O complete이 되기를 기다리며 blocking된 상태로 잠들 수 있습니다. 이때 시그널이 오면 kernel mode에서는 signal hanlder를 실행할 수 없으니 부득이하게 user mode로 돌아와서 실행하게 되는거죠. kernel mode에서 user mode로 돌아오자마자 시그널 handling하고 read() return후의 control flow를 타게 됩니다. read()가 일부 읽은 상태에서 signal을 받으면 읽은 크기만큼만 리턴하고 전혀 읽지 못한 상태에서 시그널 받으면 EINTR에러 코드와 함께 -1을 반환합니다.

/***************************************
Being the one is just like being in love.
***************************************/

/***************************************
Being the one is just like being in love.
***************************************/

lugi의 이미지

먼저 답변 감사드립니다.

제가 궁금한점은 네트웍등의 상황이 아닌 로컬 파일 시스템에서 작업시 실제로 이런 경우가 발생할 만한 signal이 존재하는지 입니다. 물론 유저등록 signal이 없을경우에..

감사합니다.

--------------------------------------------------------------------------------------
조금씩이라도 전진한다.

익명 사용자의 이미지

0)
시그널이 발생할 경우야 많습니다. 발생하지 않을 가능성을 찾는 것이 더 어렵습니다.
기본으로 보자면.
(공통적으로 read()를 열심히 하는 편인 프로세스라고 가정하겠습니다)
1) fork()했다. 나는 parent인데, read()를 열심히 하는 편이다. child()가 죽었다. ---> SIGCHLD
2) 시간관련 시스템호출을 했다. alarm()/sleep()/... 그 시간이 도래했다. ---> SIGALRM
3) 내 프로그램이 버그가 존재했다.(물론, 내가 있으라고 한적 없다) 포인터 연산문제로 엄한데를 액세스한다. 커널이 나를 죽여버린단다. -> SIGSEGV

...

시나리오가 적어도 시그널 개수만큼 존재하겠네요.
거듭 말씀드리지만, 시그널이 발생할 가능성에 대한 대처보다는 , 시그널이 발생하지 않을 가능성을 찾는 것이 더 어렵습니다.

1) partial write란, 100바이트를 쓰라고, 호출했는데, 0 < x < 100인 값을 리턴하는 경우를 말씀하시는듯합니다. non-blocking모드로 동작하는 일부 경우(로컬버퍼의 크기가 무한하지 않은 경우, 네트워크등) 외에는 partial write는 없다고 알고 있습니다. all or nothing이라는 얘기입니다.
2)아시다시피 f**()시리즈는 open(), read(), write()등을 이용하여 구현한 사용자레벨의 적어도 C언어의 경우에는 표준 라이브러리 입니다. 시그널은 라이브러리보다는 시스템(운영체제)과 밀접하며, 프레임워크 수준이 아닌 일개 라이브러리로 랩핑하기에는 무리가 있는 부분입니다. 당연히, f*()시리즈도 시그널처리해야 합니다.
한마디로는 유닉스/리눅스에서는 시그널처리는 필연이다라고 하겠습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.