Linux 커널에서 I/O 채널은 어떻게 구현됩니까?

Linux 커널에서 I/O 채널은 어떻게 구현됩니까?

stdin, stdout, stderr은 프로세스가 사용할 I/O 채널을 "알고 있는" 데이터 구조로 색인화되는 정수입니다. 나는 이 데이터 구조가 각 프로세스마다 고유하다는 것을 알고 있습니다. I/O 채널은 동적 메모리 할당이 포함된 일부 데이터 배열 구조입니까?

답변1

Unix 계열 운영 체제에서 표준 입력, 출력 및 오류 스트림은 파일 설명자 0, 및 로 1식별됩니다 2. Linux에서는 이러한 파일 proc이 에 있습니다 /proc/[pid]/fs/{0,1,2}. 이 파일은 실제로 다음을 가리킵니다.의사 터미널디렉토리에 있는 장치 /dev/pts.

PTY(Pseudo Terminal)는 한 쌍의 가상 장치입니다.의사 터미널 호스트(PTM) 및의사 터미널 슬레이브(PTS)(통칭하여 ASA라고 함)가짜 터미널 쌍)는 프로그램에 연결하려는 프로그램 간의 양방향 파이프와 유사한 IPC 채널을 제공합니다.단말 장비, 의사 터미널을 사용하여 이전 프로그램과 입력을 주고받는 드라이버입니다.

중요한 점은 의사 터미널 슬레이브가 일반 터미널처럼 보인다는 것입니다.비표준 및 표준 패턴(기본값), SIGINT다음 과 같은 특정 입력 문자를 해석합니다.방해하다문자(보통 +를 눌러 Ctrl생성됨 C)는 의사 터미널 호스트에 기록되거나, 파일 끝 문자(보통 +로 생성됨)가 발견되면 다음 반환을 발생시킵니다 read(). 터미널에서 지원하는 다른 작업에는 에코 켜기 또는 끄기, 포그라운드 프로세스 그룹 설정 등이 포함됩니다.0CtrlD

의사 터미널은 다양한 용도로 사용됩니다.

  • 이를 통해 프로그램은 ssh네트워크를 통해 연결된 다른 호스트에서 터미널 지향 프로그램을 실행할 수 있습니다. 터미널 지향 프로그램은 일반적으로 대화형 터미널 세션에서 실행되는 모든 프로그램이 될 수 있습니다. 이러한 프로그램의 표준 입력, 출력 및 오류는 소켓이 위에서 설명한 터미널 관련 기능을 지원하지 않기 때문에 소켓에 ​​직접 연결할 수 없습니다.

  • 이를 통해 프로그램은 expect스크립트에서 대화형 터미널 지향 프로그램을 구동할 수 있습니다.

  • xterm예를 들어 터미널 관련 기능을 제공하기 위해 터미널 에뮬레이터에서 사용됩니다 .

  • screen예를 들어 여러 프로세스 간에 단일 물리적 터미널을 재사용하기 위해 프로그램에서 사용됩니다 .

  • 이는 script쉘 세션 중에 발생하는 모든 입력 및 출력을 기록하는 등의 프로그램에서 사용됩니다.

Unix98 스타일 PTY, Linux에서 사용되는 경우 설정은 다음과 같습니다.

  • 드라이버는 마스터 멀티플렉서에서 의사 터미널을 열고 dev/ptmxPTM의 파일 설명자를 수신하고 /dev/pts디렉터리에 PTS 장치를 만듭니다. 열린 각 파일 설명자는 /dev/ptmx자체 관련 PTS가 있는 독립적인 PTM입니다.

  • 드라이버 호출은 fork()다음 단계를 순서대로 수행하는 하위 프로세스를 생성합니다.

    • 새 세션을 시작하기 위해 어린이가 호출한 setsid()어린이는 세션 리더입니다. 이로 인해 아이도 졌다.제어 터미널.

    • 하위 프로세스는 드라이버가 생성한 PTM에 해당하는 PTS 장치를 엽니다. 하위 프로세스는 세션 리더이지만 제어 터미널이 없기 때문에 PTS는 하위 프로세스의 제어 터미널이 됩니다.

    • 자식은 dup()표준 입력, 출력 및 오류에 대한 슬레이브 장치의 파일 설명자를 복사하는 데 사용됩니다.

    • 마지막으로 하위 프로세스 호출은 exec()의사 터미널 장치에 연결하기 위해 터미널 지향 프로그램을 시작합니다.

이 시점에서 드라이버가 PTM에 쓰는 모든 내용은 PTS의 터미널 지향 프로그램에 대한 입력으로 나타나며 그 반대의 경우도 마찬가지입니다.

정식 모드에서 실행할 때 PTS에 대한 입력은 한 줄씩 버퍼링됩니다. 즉, 일반 터미널과 마찬가지로 PTS에서 읽는 프로그램은 개행 문자가 PTM에 기록될 때만 입력 라인을 받습니다. 버퍼 용량이 소진되면 write()입력의 일부가 소비될 때까지 추가 블록 호출이 수행됩니다.

Linux 커널에서 파일 관련 시스템 호출은 사용자 공간 프로그램을 위한 통합 파일 시스템 인터페이스를 제공하는 가상 파일 시스템(VFS) 계층에서 구현 open()됩니다 . VFS를 사용하면 다양한 파일 시스템 구현이 커널에 공존할 수 있습니다. 사용자 공간 프로그램이 위의 시스템 호출을 호출하면 VFS는 해당 호출을 적절한 파일 시스템 구현으로 리디렉션합니다.read()write() stat()

다음 PTS 장치는 /dev/pts에 정의된 파일 시스템 구현에 의해 관리되며 Unix98 스타일 장치를 제공하는 TTY 드라이버는 에 정의되어 있습니다.devpts/fs/devpts/inode.cptmxdrivers/tty/pty.c

TTY 장치와 TTY 간 버퍼링산업 규율의사 터미널과 같은 는 다음에 정의된 각 tty 장치에 대해 유지되는 버퍼 구조를 제공합니다.include/linux/tty.h

커널 버전 3.7 이전에는 버퍼가플립 버퍼:

#define TTY_FLIPBUF_SIZE 512

struct tty_flip_buffer {
        struct tq_struct tqueue;
        struct semaphore pty_sem;
        char             *char_buf_ptr;
        unsigned char    *flag_buf_ptr;
        int              count;
        int              buf_num;
        unsigned char    char_buf[2*TTY_FLIPBUF_SIZE];
        char             flag_buf[2*TTY_FLIPBUF_SIZE];
        unsigned char    slop[4];
};

구조에는 두 개의 동일한 크기의 버퍼로 분할된 저장 공간이 포함되어 있습니다. 버퍼에는 번호가 매겨져 있습니다 0(전반 char_buf/flag_buf) 및 1(후반). 드라이버는 로 식별되는 버퍼에 데이터를 저장합니다 buf_num. 또 다른 버퍼를 라인 분야로 플러시할 수 있습니다.

buf_num0와 사이를 전환 하여 버퍼를 "뒤집습니다" 1. 변경 후에 buf_num는 와 로 식별되는 버퍼의 시작 부분으로 설정되고 char_buf_ptr로 설정됩니다 .flag_buf_ptrbuf_numcount0

커널 버전 3.7부터 시작kmalloc()TTY 롤오버 버퍼는 링 구성에 의해 할당된 개체 로 대체되었습니다.. 일반적인 상황에서 IRQ 기반 직렬 포트는 일반적인 속도에서 이전 플립 버퍼와 거의 동일하게 작동합니다. 두 버퍼는 결국 할당되고 커널은 이전과 같이 순환합니다. 그러나 대기 시간이 발생하거나 속도가 증가하면 버퍼 풀이 약간 커질 수 있으므로 새 버퍼 구현이 더 나은 성능을 발휘합니다.

답변2

이 세 가지 중 하나에 대한 매뉴얼 페이지에서 답변을 설명합니다.

   Under  normal circumstances every UNIX program has three streams opened
   for it when it starts up, one for input, one for output,  and  one  for
   printing diagnostic or error messages.  These are typically attached to
   the user's terminal but might instead  refer  to  files  or
   other  devices,  depending  on what the parent process chose to set up.

   The input stream is referred to as "standard input"; the output  stream
   is  referred  to as "standard output"; and the error stream is referred
   to as "standard error".  These terms are abbreviated to form  the  sym-
   bols used to refer to these files, namely stdin, stdout, and stderr.

   Each  of these symbols is a stdio(3) macro of type pointer to FILE, and
   can be used with functions like fprintf(3) or fread(3).

   Since FILEs are a buffering wrapper around UNIX file  descriptors,  the
   same  underlying  files  may  also  be accessed using the raw UNIX file
   interface, that is, the functions like read(2) and lseek(2).

   On program startup, the integer file descriptors  associated  with  the
   streams  stdin,  stdout, and stderr are 0, 1, and 2, respectively.  The
   preprocessor symbols STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO are
   defined  with  these values in <unistd.h>.

관련 정보