Giải mã TTY: Từ máy điện báo đến hệ thống Terminal của Linux
Hệ thống TTY là một phần cốt lõi nhưng thường bị hiểu lầm trong kiến trúc Linux. Bài viết này sẽ đi sâu vào lịch sử hình thành, cơ chế hoạt động của driver TTY, line discipline và cách hệ điều hành quản lý tín hiệu, điều khiển công việc qua terminal.

Hệ thống TTY đóng vai trò trung tâm trong thiết kế của Linux và nói chung là các hệ điều hành UNIX. Tuy nhiên, tầm quan trọng của nó thường bị bỏ qua, và rất khó để tìm thấy những bài viết giới thiệu thực sự tốt về chủ đề này. Tôi tin rằng việc hiểu cơ bản về TTY trong Linux là điều cần thiết cho mọi nhà phát triển và người dùng nâng cao.
Cần lưu ý rằng: Những gì bạn sắp thấy không hề đẹp đẽ một cách lý tưởng. Thực tế, hệ thống TTY — dù khá hoàn hảo từ góc độ người dùng — là một mớ hỗn độn phức tạp đầy các trường hợp đặc biệt. Để hiểu tại sao nó lại như vậy, chúng ta cần quay ngược thời gian.
Máy điện báo cổ
Nguồn gốc lịch sử
Vào năm 1869, máy báo giá chứng khoán (stock ticker) được phát minh. Đây là một cỗ máy cơ-điện bao gồm một máy đánh chữ, một cặp dây dẫn dài và một máy in giấy băng, với mục đích phân phối giá chứng khoán theo thời gian thực trên khoảng cách xa. Khái niệm này dần dần phát triển thành teletype dựa trên ASCII nhanh hơn.
Teletypes từng được kết nối trên toàn thế giới trong một mạng lưới lớn gọi là Telex, được sử dụng để chuyển đổi các bức điện thương mại, nhưng lúc đó các teletypes chưa được kết nối với bất kỳ máy tính nào.
Trong khi đó, các máy tính — dù vẫn còn khá lớn và nguyên thủy, nhưng đã có khả năng đa nhiệm — trở nên đủ mạnh để tương tác với người dùng theo thời gian thực. Khi dòng lệnh (command line) cuối cùng thay thế cho mô hình xử lý hàng loạt (batch processing) cũ kỹ, teletypes được sử dụng làm thiết bị nhập và xuất dữ liệu vì chúng có sẵn trên thị trường.
Tuy nhiên, có vô số mô hình teletype khác nhau, tất cả đều hơi khác nhau một chút, do đó một lớp tương thích phần mềm là điều cần thiết. Trong thế giới UNIX, cách tiếp cận là để nhân hệ điều hành (kernel) xử lý tất cả các chi tiết cấp thấp, chẳng hạn như độ dài từ, tốc độ baud (baud rate), điều khiển luồng (flow control), bit chẵn lẻ (parity), các mã điều khiển để chỉnh sửa dòng cơ bản, v.v.
Các tính năng nâng cao như di chuyển con trỏ, đầu ra màu sắc và các tính năng khác có thể thực hiện vào cuối những năm 1970 bởi các terminal video trạng thái rắn như VT-100 được để lại cho các ứng dụng tự xử lý.
Ngày nay, chúng ta sống trong một thế giới nơi các teletype vật lý và terminal video thực tế gần như đã tuyệt chủng. Trừ khi bạn đến bảo tàng hoặc gặp một người đam mê phần cứng, tất cả các TTY bạn nhìn thấy sẽ là các terminal video giả lập — các mô phỏng phần mềm của vật thật. Nhưng như chúng ta sẽ thấy, di sản từ những cỗ máy sắt thép cũ kỹ đó vẫn ẩn nấp ngay bên bề mặt.
Kiến trúc của hệ thống TTY
Một người dùng gõ phím tại một terminal (một teletype vật lý). Terminal này được kết nối thông qua một cặp dây đến một UART (Bộ thu phát không đồng bộ phổ quát) trên máy tính. Hệ điều hành chứa driver UART quản lý việc truyền tải vật lý của các byte, bao gồm kiểm tra chẵn lẻ và điều khiển luồng.
Trong một hệ thống ngây thơ, driver UART sẽ chuyển các byte đến trực tiếp cho một quy trình ứng dụng. Nhưng cách tiếp cận này sẽ thiếu các tính năng thiết yếu sau:
Chỉnh sửa dòng (Line editing)
Hầu hết người dùng đều mắc lỗi khi gõ, vì vậy phím xóa lùi (backspace) thường rất hữu ích. Tất nhiên điều này có thể được thực hiện bởi chính các ứng dụng, nhưng phù hợp với triết lý thiết kế của UNIX, các ứng dụng nên được giữ càng đơn giản càng tốt.
Vì vậy, để thuận tiện, hệ điều hành cung cấp một bộ đệm chỉnh sửa và một số lệnh chỉnh sửa cơ bản (xóa lùi, xóa từ, xóa dòng, in lại), được bật theo mặc định bên trong line discipline. Các ứng dụng nâng cao có thể tắt các tính năng này bằng cách đưa line discipline vào chế độ thô (raw mode) thay vì chế độ nấu chín (cooked) hoặc chế độ chuẩn (canonical) mặc định.
Hầu hết các ứng dụng tương tác (trình soạn thảo, trình đọc mail, shell, tất cả các chương trình dựa vào curses hoặc readline) chạy ở chế độ thô và tự xử lý tất cả các lệnh chỉnh sửa dòng.
Quản lý phiên làm việc (Session management)
Người dùng có thể muốn chạy nhiều chương trình đồng thời và tương tác với chúng từng cái một. Nếu một chương trình rơi vào vòng lặp vô tận, người dùng có thể muốn giết hoặc tạm dừng nó. Các chương trình được khởi chạy ở nền sau (background) nên có thể thực thi cho đến khi chúng cố gắng ghi ra terminal, lúc đó chúng nên bị tạm dừng. Tương tự, đầu vào của người dùng chỉ nên được hướng đến chương trình nền trước (foreground).
Hệ điều hành triển khai các tính năng này trong driver TTY.
Pseudo Terminal (PTY)
Hãy chuyển sang một hệ thống máy tính để bàn điển hình. Đây là cách Linux console hoạt động:
Driver TTY và line discipline hoạt động chính xác như trong các ví dụ trước, nhưng không còn UART hay terminal vật lý nào liên quan nữa. Thay vào đó, một terminal video (một máy trạng thái phức tạp bao gồm bộ đệm khung ký tự và các thuộc tính ký tự đồ họa) được giả lập bằng phần mềm và hiển thị trên màn hình VGA.
Hệ thống console hơi cứng nhắc. Things trở nên linh hoạt hơn (và trừu tượng hơn) nếu chúng ta chuyển giả lập terminal vào không gian người dùng (userland). Đây là cách xterm(1) và các bản sao của nó hoạt động.
Để tạo điều kiện chuyển giả lập terminal vào userland, trong khi vẫn giữ hệ thống TTY (quản lý phiên và line discipline) nguyên vẹn, pseudo terminal hoặc pty đã được phát minh. Và như bạn có thể đoán, mọi thứ trở nên phức tạp hơn khi bạn bắt đầu chạy pseudo terminal bên trong pseudo terminal, kiểu như screen(1) hoặc ssh(1).
Tín hiệu và Điều khiển công việc (Job Control)
Trong UNIX, kernel giao tiếp với các tiến trình bằng cách gửi các tín hiệu (signals). Tín hiệu là một cơ chế thô sơ cho phép kernel giao tiếp không đồng bộ với một tiến trình. Các tín hiệu trong UNIX không sạch sẽ hay tổng quát; thay vào đó, mỗi tín hiệu là duy nhất và phải được nghiên cứu riêng lẻ.
Một số tín hiệu quan trọng liên quan đến TTY bao gồm:
- SIGINT: Được gửi bởi driver TTY đến công việc nền trước hiện tại khi ký tự chú ý tương tác (thường là
^C) xuất hiện trong luồng đầu vào. - SIGTSTP: Tương tự như SIGINT nhưng ký tự ma thuật thường là
^Zvà hành động mặc định là tạm dừng tiến trình. - SIGTTIN/SIGTTOU: Nếu một tiến trình trong công việc nền sau cố gắng đọc hoặc ghi vào thiết bị TTY, TTY sẽ gửi tín hiệu này để tạm dừng công việc đó.
- SIGWINCH: Được gửi khi kích thước cửa sổ terminal thay đổi, giúp các ứng dụng như trình soạn thảo văn bản vẽ lại giao diện.
Điều khiển công việc là những gì xảy ra khi bạn nhấn ^Z để tạm dừng một chương trình, hoặc khi bạn bắt đầu một chương trình ở nền sau bằng &. Một công việc (job) giống như một nhóm tiến trình (process group). Shell, với tư cách là người dẫn đầu phiên (session leader), hợp tác chặt chẽ với kernel bằng một giao thức phức tạp của các tín hiệu và lệnh gọi hệ thống.
Điều khiển luồng (Flow Control)
Hãy tưởng tượng bạn chạy lệnh yes trong một xterm. Tiến trình yes có thể tạo ra các dòng "y" nhanh hơn nhiều so với khả năng xterm phân tích và cập nhật khung hình. Làm thế nào để các chương trình này hợp tác?
Câu trả lời nằm trong I/O chặn (blocking I/O). Pseudo terminal chỉ có thể giữ một lượng dữ liệu nhất định trong bộ đệm kernel của nó. Khi bộ đệm đầy và yes cố gắng gọi write(2), lệnh gọi đó sẽ bị chặn.
Ngoài ra, còn có điều khiển luồng phần mềm. Nếu bạn vô tình nhấn ^S (XOFF), terminal sẽ gửi một byte yêu cầu dừng luồng dữ liệu. Kernel sẽ ngừng gửi dữ liệu đến terminal cho đến khi nhận được ^Q (XON). Đây là lý do tại sao xterm của bạn đôi khi có vẻ bị "đóng băng" khi bạn nhấn nhầm phím.
Cấu hình TTY với stty
Bạn có thể đọc hoặc sửa đổi cấu hình của thiết bị TTY đang mở bằng cách sử dụng ioctl(2). Tuy nhiên, có một công cụ dòng lệnh tiện lợi hơn gọi là stty(1) để thao tác với các thiết bị TTY.
Cờ -a báo cho stty hiển thị tất cả cài đặt. Một số cài đặt này đề cập đến tham số UART, một số ảnh hưởng đến line discipline và một số khác dành cho điều khiển công việc.
Ví dụ, icanon chuyển đổi chế độ chuẩn (dựa trên dòng). Nếu bạn tắt nó bằng lệnh stty -icanon, các ký tự chỉnh sửa dòng như backspace và ^U sẽ ngừng hoạt động và ứng dụng sẽ nhận dữ liệu từng ký tự một thay vì từng dòng một.
Hoặc tostop kiểm soát xem các công việc nền có được phép ghi ra terminal hay không. Nếu tostop được bật (stty tostop), các công việc nền cố gắng ghi ra terminal sẽ bị gửi tín hiệu SIGTTOU và tạm dừng.
Hy vọng bài viết này đã cung cấp cho bạn đủ thông tin để hiểu rõ về driver TTY và line discipline, cũng như mối liên hệ của chúng với terminal, chỉnh sửa dòng và điều khiển công việc. Các chi tiết sâu hơn có thể được tìm thấy trong các trang man (manual pages) như tty_ioctl(4), termios(3) và stty(1).
Bài viết liên quan

Công nghệ
Cerebras, đối tác thân thiết của OpenAI, sẵn sàng cho đợt IPO kỷ lục định giá tới 26,6 tỷ USD
04 tháng 5, 2026

Công nghệ
Microsoft giới thiệu Surface Pro 12 và Surface Laptop 8: Sức mạnh chip Intel, giá thành gây sốc
19 tháng 5, 2026

Công nghệ
Substrate (YC S24) tuyển dụng Technical Success Manager cho nền tảng AI chuyên xử lý thanh toán y tế
13 tháng 5, 2026
