I. Poll and Select
Các ứng dụng(user-app) sử dụng nonblocking I/O sẽ thường sử dụng thêm poll, select và epull
system call. poll, select, epoll có cùng 1 chức năng: cho phép một process xác định xem nó có thể đọc hoặc ghi từ một hoặc nhiều open file mà không bị block hay không. Những lời gọi hàm này cũng có thể block một process đến khi có một tập file descriptors(fd) trở nên khả dụng cho việc đọc hoặc ghi. Bởi thế, chúng thường được sử dụng trong các user-app cần phải sử dụng nhiều luồng đọc/ghi cùng lúc mà không có bất kỳ luồng nào bị stuck(V/d: network).
Những system call kể trên được hỗ trợ bởi một driver method duy nhất là poll
:
unsigned int (*poll) (struct file *filp, poll_table *wait);
Driver method được gọi mỗi khi một user-app thực hiện lời gọi đến một trong các system call poll, select, epoll
trên một file descriptor được liên kết với driver. Nhiệm vụ của driver method có 2 bước:
- Gọi hàm
poll_wait
trên một hoặc nhiều hàng đợi, hàng đợi này được yêu cầu là phải có thể chỉ ra được sự thay đổi của poll status. Nếu không có file descriptor nào khả dụng cho I/O ở thời điểm hiện tại, thì kernel sẽ đẩy process vào hàng đợi để đợi đến khi tất cả các file descriptors được truyền đến system call. - Trả về một bit mask miêu tả operation nào (nếu có) có thể được thực hiện ngay lập tức mà không bị block.
Driver có thể thêm một wait queue vàopoll_table
bằng cách sử dụng lời gọi hàm:
void poll_wait(struct file *, wait_queue_head_t *, poll_table *);
Các bitmask có thể được trả về ở bước 2 gồm có:
POLLIN
Bit này được set nếu như device có thể đọc mà không bị block
POLLRDNORM
Bit này được set nếu như “normal” data là khả dụng cho việc đọc. Một readable device sẽ trả về (POLLIN|POLLRDNORM)
POLLRDBAND
out-of-band data is available for reading from the device
POLLPRI
High-priority data(out-of-band) có thể được đọc mà không bị blocking. Nếu bit này được set, lời gọiselect
sẽ thông báo rằng một exception condition đã diễn ra trong file, bời vìselect
report out-of-band data như một exception condition
POLLHUP
Khi một process đọc đến EOF, driver phải set bit POLLHUP(hang-up). Một process gọiselect
sẽ được nói rằng device là có thể đọc, vì được yêu cầu bởi chức năng của hàm này.
POLLERR
Một error condition đã xảy ra trong thiết bị. Khipoll
được gọi, thiết bị được báo cáo là có thể đọc và cũng có thể ghi được, vì cả read và write đều trả về 1 error code without blocking
POLLOUT
Device cÓ thể được ghi mà không bị block
POLLWRNORM
Giống với POLLOUT
POLLWRBAND
Nonzero-priority data có thể được ghi vào device
Out of band data là gì? Data truyền qua socket.
II. Interaction with read and write.
Mục đích của việc gọi poll
và select
là để xác định trước xem một I/O operation sẽ bị block hay không. Poll và select rất hữu dụng, bởi vì chúng cho phép user-app chờ đợi nhiều data stream một cách đồng thời. (Sẽ tìm ví dụ sau).
Để 3 system call (poll, select, epoll) hoạt động đúng, chúng ta cần lưu ý đến một số luật sau.
1. Đọc dữ liệu từ device.
a,Nếu có dữ liệu trong input buffer, read
call sẽ return ngay tức thì, với độ trễ không đáng kể, kể cả khi như lượng dữ liệu trong input buffer ít hơn lượng dữ liệu được yêu cầu bởi user-app nhưng driver đảm bảo là lượng dữ liệu còn lại sẽ được chuyển đến input buffer sớm. Trong trường hợp này, poll
nên trả về POLLIN|POLLRDNORM.
b,Nếu không có data trong input buffer, mặc định, read
phải block đến khi có ít nhất 1 byte data ở trong input buffer. Ngược lại, nếu như O_NONBLOCK được set, read
sẽ return ngay lập tức với giá trị trả về là -EAGAIN. Trong trường hợp này, poll
phải report rằng device hiện tại là unreadable cho đến khi có ít nhất 1 byte data đc truyền đến. Ngay khi data đc truyền đến buffer, chúng ta sẽ quay lại case a.
c, Nếu đang ở EOF, read
sẽ return ngay lập tức với giá trị trả về là 0. poll
trả về POLLUP.
2. Ghi vào device.
a,Nếu output buffer không đủ không gian trống, write
sẽ return ngay lập tức. Nó có thể cấp nhận ít data hơn request, nhưng nó không chấp nhận việc không có bất cứ một byte dữ liệu nào. Trong trường hợp này, poll
sẽ trả về POLLOUT|POLLWRNORM.
b,Nếu output buffer đầy, mặc định, write
sẽ block đến khi có không gian trống. Nếu O_NONBLOCK được set, write
sẽ ngay lập tức trả về giá trị -EAGAIN. Trong trường hợp này, poll
sẽ thông báo là không thể ghi vào file được. Ngược lại, nếu device không thể tiếp nhận them dữ liệu, write
sẽ trả về -ENOSPC (always)
c, Kể cả O_NONBLOCK không được set, thì write
cũng không bao giờ đợi data transsmission trước khi return. Điều này là bởi vì nhiều ứng dụng sử dụng select
để tìm xem write
có bị block không? Nếu device là có thể ghi, system call phải bị block. Nếu như user-app đang sử dụng device muốn đảm bảo rằng data trong hàng đợi để vào output buffer đã được truyền đi thực sự, driver phải cung cấp fsync
method.
3. Flushing pending output
Như đã đề cập ở trên, write
không có phương pháp nào để tính toán lượng output data. Để làm điều này driver phải cung cấp fsync:
int(*fsync)(struct file *filp, struct detry *dentry, int datasync);
Khi user-app gọi đến fsync, lời gọi này chỉ nên được return khi device đã hoàn thành việc flush data (đẩy hết data trong output buffer sang device), bất kể việc làm này mất bao nhiêu thời gian đi chăng nữa thì nó cũng k nên đợi.
Leave a Comment