문자 사이의 간격을 줄이기 위해 tty termios API에서 100ms 미만의 VTIME을 얻으려면 커널 패치를 찾는 데 도움이 필요합니다. VTIME 시간이 초과될 때까지 읽기 시스템 호출을 차단합니다.
n_tty_read() 함수는 패치 진입점입니다: https://elixir.bootlin.com/linux/latest/source/drivers/tty/n_tty.c#L2131
누구든지 나에게 조언을 해줄 수 있나요? 비정규 모드(프레임 프로토콜 없음, ASCII 없음, 인터럽트 없음)를 사용해야 합니다. 모든 메시지 길이가 가변적이므로 VMIN 매개변수는 비어 있습니다. 모든 문자를 폴링하는 솔루션은 여러 uart 시스템에 비해 너무 비싸며 여러 프로세스 컨텍스트 전환을 의미합니다.
용어 추출 설명서: VTIME 시간 초과10분의 1초비정규 읽기의 경우(시간).https://man7.org/linux/man-pages/man3/termios.3.html
리눅스 커널 패치가 필요한데.. HZ를 더 큰 값으로 나누는 것이 좋을까요? 아니면 전역 HZ를 더 작은 값으로 설정하시겠습니까?
Microsoft Windows 직렬 API는 1ms로 구성할 수 있지만 Linux는 구성할 수 없습니다. 따라서 Windows는 원시 직렬 포트 처리에 더 적합합니다. 읽기 간격 시간 초과:https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddser/ns-ntddser-_serial_timeouts
리뷰에서 발췌 "비표준 모드에서...4095자만 허용됩니다.", 제 생각에는 여기에 문제가 있는 것 같습니다. 아마도 read_wait 대기열이 깨어나지 않는 이유일 것입니다.
https://elixir.bootlin.com/linux/latest/source/drivers/tty/n_tty.c#L1667
답변1
tty termios API에서 100ms 미만의 VTIME을 얻으려면 커널 패치를 찾는 데 도움이 필요합니다...
리눅스 커널 패치가 필요합니다...
이러한 커널 패치는 사용자 공간 API를 변경하므로 현명하지 않습니다. Linux는 일관된 API를 유지하려고 노력하며, 요청한 패치로 인해 기존 애플리케이션이 중단될 수 있습니다.
이러한 커널 패치가 API를 변경하지 않더라도 안정성이 낮고 명시되지 않은 목표를 달성할 가능성이 없습니다. 시간으로 구분된 메시지를 탐지하기 위해 VMIN 및 VTIME 설정에만 의존할 수도 없고 의존해서도 안 됩니다.
UART가 FIFO를 사용하여 들어오는 데이터를 버퍼링하는 경우 하드웨어 버퍼는 소프트웨어가 감지할 수 있는 문자 간격을 마스크합니다. 마찬가지로 UART 드라이버가 DMA를 사용하여 수신된 데이터를 저장하는 경우 문자 간 타이밍이 마스크됩니다.
termios는 UART 장치 드라이버 위의 최소한 전체 레이어를 처리합니다. termios 레이어는 UART 및 해당 드라이버가 바이트를 처리/버퍼한 후 라인에서 동일한 타이밍 정보를 볼 수 없습니다.
Microsoft Windows 직렬 API는 1ms로 구성할 수 있지만 Linux는 구성할 수 없습니다. 따라서 Windows는 원시 직렬 포트 처리에 더 적합합니다.
Windows가 귀하의 응용 프로그램에 더 적합하다고 생각되면 Windows를 사용해야 합니다. 그러나 광고된 내용이 반드시 귀하가 얻게 되는 내용은 아니라는 점에 유의하십시오. Windows API는 단지공시 하다시간 초과 사양(밀리초)정확한. 그렇다고 해서 실제로 이와 같은 것을 얻게 된다는 의미는 아닙니다.정확성. 예를 들어 다음과 같은 경고가 있습니다.
시간 초과 간격은 시스템 시계를 기준으로 측정됩니다.시간 초과 측정의 정확성은 시스템 시계의 세분성에 의해 제한됩니다.. 그러므로,지정된 시간 초과 간격보다 빠른 한 시스템 클록 주기와 한 시스템 클록 주기 사이에 시간 초과가 발생할 수 있습니다., 시스템 클록 사이클 사이에서 간격의 시작 및 종료 시간이 정확히 어디에 속하는지에 따라 달라집니다.나중에 시간 초과가 발생할 수 있습니다.다른 장치의 인터럽트 처리로 인해 시스템 클록 인터럽트 처리가 지연되는 경우. 지정된 시간 초과 간격이 시스템 시계 틱 사이의 기간에 가깝거나 짧은 경우시간 초과는 지연 없이 즉시 발생할 수 있습니다..
내 생각에 문제는 여기에 있는 것 같습니다. 아마도 이것이 read_wait 대기열이 깨어나지 않는 이유일 것입니다.
아니요, 당신은 잘못된 곳을 찾으려고 고집합니다.
제가 예전에 말씀드리려고 했던 것처럼 (참고로이 게시물), 안정적인 솔루션에는 유휴 UART 수신기를 감지하는 타이머가 필요합니다. 그러나 UART 하드웨어가 수신기 시간 초과를 구현하더라도(내가 검토한 두 개의 Linux 드라이버에서) 이 기능은 현재/활성 DMA 작업을 중단하는 데만 사용됩니다.
수신기 시간 초과는 시간 분리 메시지의 끝을 감지할 수 있으므로 UART 드라이버가 수신된 데이터를 전달할 때 이 이벤트/정보를 termios 계층으로 전달해야 합니다. 이것은 VMIN > 0
원래 모드의 새로운 변형에 대해 termios에 필요한 누락된 정보 입니다 VTIME > 0
. 이 새로운 변형에서 UART 드라이버는 termios가 문자 간 시간 초과를 확인하도록 하는 대신 수신된 데이터로 시간 초과 이벤트를 표시해야 합니다.
이것은 단순한 커널 패치가 아닙니다.
답변2
다행히도 나는 몇 가지 설명을 찾았고 우리가 다음과 같은 상황에 직면했다고 결론을 내렸습니다.API가 더 이상 사용되지 않음이는 과도한 CPU 소비로 인해 우회될 수 있음을 의미합니다.
VTIME 시간 초과 세분성은 다음과 같습니다.역사적으로 정의된바이트 간 간격의 단위입니다(POSIX에서는 VTIME=100ms를 정의함). 현재 Linux에서 사용하는 바이트 간격은 여전히 직렬 회선에 해당합니다.110 전송 속도(110). 그러나 오늘날 115200보드 직렬 회선을 사용하는 경우 1바이트의 TX 기간은 약 100μs(마이크로초)입니다.
Alan Cox: RE: termios VMIN ANDVTIME 행동
매우 명확하게 정의되어 있습니다. 블록 직렬 연산(uucp 등)을 최적화하도록 설계되었습니다.
VMIN - 이 패킷에 대해 예상되는 바이트 수 VTIME - 대기를 포기해야 하는 시기
형식 0, VTIME은 선택/폴링이 없는 이전 SYSV를 폴링하는 데에도 사용됩니다.
POSIX 2007 6월 §11.1.7 비정규 모드 입력 처리
비정규 모드 입력 처리에서는 입력 바이트가 라인으로 어셈블되지 않으며 삭제 및 종료 처리가 발생하지 않습니다. c_cc 배열의 MIN 및 TIME 멤버 값은 수신된 바이트를 처리하는 방법을 결정하는 데 사용됩니다. POSIX.1-200x는 O_NONBLOCK 설정이 MIN 또는 TIME 설정보다 우선하는지 여부를 지정하지 않습니다. 따라서 O_NONBLOCK이 설정된 경우 MIN 또는 TIME 설정에 관계없이 read()가 즉시 반환될 수 있습니다. 또한, read()는 사용 가능한 데이터가 없으면 0을 반환하거나 errno가 [EAGAIN]으로 설정된 경우 -1을 반환할 수 있습니다. MIN은 read() 함수가 성공적으로 반환될 때 수신되어야 하는 최소 바이트 수를 나타냅니다.TIME은 0.1초 단위의 타이머로, 버스트 및 단기 데이터 전송의 타임아웃에 사용됩니다.MIN이 {MAX_INPUT}보다 크면 요청에 대한 응답이 정의되지 않습니다.
GNU C 라이브러리 참조 매뉴얼, 버전 2.37, §17.4.10비표준 입력
매크로: int VTIME 이것은 c_cc 배열의 TIME 슬롯 인덱스입니다. 따라서 termios.c_cc[VTIME]은 값 자체입니다.
TIME 슬롯은 비표준 입력 모드에서만 의미가 있습니다.반환 전 입력을 기다리는 시간을 0.1초 단위로 지정합니다.[...]
MIN은 0이지만 TIME은 0이 아닌 값을 갖습니다. 이 경우 읽기는 입력이 사용 가능해질 때까지 TIME 동안 기다립니다. 단일 바이트의 가용성만으로도 읽기 요청을 만족하고 읽기가 반환될 수 있습니다. 반환되면 요청된 수까지 사용 가능한 만큼의 문자를 반환합니다. 타이머가 만료되기 전에 사용할 수 있는 입력이 없으면 읽기는 0 값을 반환합니다.
- (최소값>0, 시간>0).
TIME>0이기 때문에인터바이트 타이머첫 번째 데이터 바이트가 수신되면 활성화되고 각 데이터 바이트가 수신되면 재설정됩니다. MIN과 TIME은 다음과 같이 상호 작용합니다.
- 한 바이트의 데이터가 수신되면,인터바이트 타이머가 시작됩니다.(타이머는 각 바이트가 수신된 후에 재설정된다는 점을 기억하십시오.)
- 이전에 MIN바이트의 데이터를 수신한 경우인터바이트 타이머가 만료됨, 읽기가 성공적으로 완료되었습니다.
- 만약에인터바이트 타이머가 만료됨읽기는 MIN바이트의 데이터가 수신될 때까지 수신된 모든 바이트를 전송합니다.
TIME이 만료되면 읽기는 최소 1바이트의 데이터를 전송합니다.인터바이트 타이머가 활성화되었습니다.1바이트의 데이터가 수신되는 경우에만 해당됩니다. 이 상황을 사용하는 프로그램은 계속하기 전에 적어도 1바이트의 데이터를 읽을 때까지 기다려야 합니다. (MIN>0, TIME>0)인 경우 MIN 및 TIME을 활성화하기 위해 데이터 바이트가 수신되거나 신호가 읽기를 중단할 때까지 읽기가 차단됩니다. 따라서 읽기는 최소한 1바이트의 데이터를 전송합니다.
[...]
- (최소=0, 시간>0).
MIN=0이므로,TIME은 더 이상 바이트 간 타이머 역할을 하지 않습니다., 그러나 이제는 읽기가 처리될 때 활성화되는 읽기 타이머(Canon에서)로 사용됩니다. 데이터 바이트가 수신되거나 읽기 타이머가 만료되는 즉시 읽기가 성공적으로 완료됩니다. 읽기 타이머가 만료되면 읽기는 데이터 바이트를 전송하지 않습니다. 읽기 타이머가 만료되지 않은 경우 일부 데이터 바이트가 수신된 경우에만 읽기가 성공적으로 완료됩니다. (MIN=0, TIME>0)인 경우 읽기는 데이터 바이트를 기다리면서 무기한 차단되지 않습니다. 읽기 시작 후 TIME*0.10초 이내에 바이트 데이터가 수신되지 않으면 0을 반환하여 읽은 데이터가 없음을 나타냅니다. 읽기가 시작될 때 버퍼에 데이터가 보관되어 있으면 즉시 데이터를 받은 것처럼 읽기 타이머가 시작됩니다. MIN 및 TIME은 프로그램이 TIME 간격 후에 데이터를 사용할 수 없다고 가정하고 데이터를 사용할 수 있기 전에 다른 처리를 완료할 수 있는 경우에 유용합니다.
답변3
커널 API 호환성을 유지하는 패치를 제안하기 위해서는 주로 가능한 오프로드 솔루션이 있다고 생각합니다. 즉, CANON 모드의 VEOF 매개변수 값(사용되지 않은 unsigned char 값)을 사용하여 VTIME을 조정하는 것입니다(앞에 타임아웃 값을 추가). 비 CANON 모드 읽기 기능의 경우, Schedule_timeout 기능 분할 요소) )를 적용합니다.
Canon 이외의 모드에서 사용되지 않는 VEOF 값을 사용하십시오. https://elixir.bootlin.com/linux/latest/source/include/linux/tty.h#L39
여기에는 나누기가 적용됩니다. 예를 들어 VEOF 값이 기본값과 다른 경우 VTIME 시간 초과 감소가 적용됩니다. https://elixir.bootlin.com/linux/latest/source/drivers/tty/n_tty.c#L2196