2012-02-17 10 views
7

Các writev chức năng phải mất một mảng của struct iovec như là đối số đầu vàoLàm thế nào để danh sách I/O writev nội bộ làm việc?

writev(int fd, const struct iovec *iov, int iovcnt);

Đầu vào là một danh sách các bộ đệm bộ nhớ mà cần phải được ghi vào một tập tin (ví dụ). Những gì tôi muốn biết là:

Liệu writev nội làm điều này:

for (each element in iov) write(element)

mà mọi phần tử của iov được ghi vào tập tin trong một tôi riêng biệt/O gọi? Hoặc không writev viết mọi thứ để nộp trong số Cuộc gọi I/O?

Trả lời

6

mỗi tiêu chuẩn, các vòng lặp for mà bạn đề cập không phải là một việc thực hiện hợp lệ của writev, vì nhiều lý do:

  1. Vòng lặp có thể thất bại trong việc hoàn thành viết một IOV trước khi tiến hành tiếp theo, trong trường hợp viết ngắn - nhưng điều này có thể được làm việc xung quanh bằng cách làm cho vòng lặp phức tạp hơn.
  2. Vòng lặp có thể có hành vi không đúng đối với nguyên tử đối với đường ống: nếu tổng chiều dài ghi nhỏ hơn PIPE_BUF, viết ống được yêu cầu là nguyên tử, nhưng vòng lặp sẽ phá vỡ yêu cầu nguyên tử. Vấn đề này không thể được làm việc xung quanh ngoại trừ bằng cách di chuyển tất cả các mục nhập iov vào một bộ đệm đơn trước khi viết khi tổng chiều dài tối đa là PIPE_BUF.
  3. Vòng lặp có thể có trường hợp có thể dẫn đến chặn, trong đó yêu cầu writev đơn lẻ để thực hiện viết một phần mà không bị chặn. Theo như tôi biết, vấn đề này sẽ không thể làm việc xung quanh trong trường hợp chung.
  4. Có thể là các lý do khác mà tôi chưa từng nghĩ đến.

Tôi không chắc chắn về điểm số 3, nhưng nó chắc chắn tồn tại theo hướng ngược lại, khi đọc. Gọi read trong một vòng lặp có thể chặn nếu một thiết bị đầu cuối có một số dữ liệu (ngắn hơn tổng chiều dài iov) có sẵn theo sau là một chỉ số EOF; gọi số readvnên trả về ngay lập tức với một phần được đọc trong trường hợp này. Tuy nhiên, do lỗi trong Linux, readv trên các thiết bị đầu cuối thực sự được triển khai dưới dạng vòng lặp read trong kernelspace và nó hiển thị lỗi chặn này. Tôi đã phải làm việc xung quanh lỗi này trong việc thực hiện stdio musl của:

http://git.etalabs.net/cgi-bin/gitweb.cgi?p=musl;a=commit;h=2cff36a84f268c09f4c9dc5a1340652c8e298dc0

Để trả lời phần cuối của câu hỏi của bạn:

Hay writev viết tất cả mọi thứ để nộp trong một I/O cuộc gọi duy nhất ?

Trong mọi trường hợp, việc triển khai thực hiện writev sẽ là một syscall duy nhất. Tìm hiểu cách nó được triển khai trên Linux: đối với các tệp thông thường và cho hầu hết các thiết bị, trình điều khiển tệp cơ bản có các phương thức thực hiện trực tiếp io kiểu iov, không có bất kỳ loại vòng lặp nội bộ nào.Nhưng trình điều khiển thiết bị đầu cuối trên Linux rất lỗi thời và thiếu các phương pháp io hiện đại, khiến hạt nhân quay trở lại vòng ghi/đọc cho writev/readv khi hoạt động trên thiết bị đầu cuối.

+0

Tôi không hiểu dòng cuối cùng "khi hoạt động trên thiết bị đầu cuối". Ngoài ra, nơi chính xác trong src linux để bạn kiểm tra việc thực hiện writev? – jitihsk

+0

"Khi hoạt động trên thiết bị đầu cuối" có nghĩa là khi bộ mô tả tập tin đề cập đến thiết bị đầu cuối. Đối với nơi trong nguồn, http://lxr.linux.no/#linux+v3.2.6/fs/read_write.c#L809 –

3
Or does writev write everything to file in a single I/O call? 

Tôi không quan tâm đến mọi thứ, mặc dù sys_writev cố gắng hết sức để viết mọi thứ trong một cuộc gọi. nó phụ thuộc vào thực hiện của vfs, nếu vfs không cung cấp cho một thực hiện của writev, sau đó kenerl sẽ gọi vfs 'write() trong một vòng lặp. tốt hơn là kiểm tra giá trị trả về của writev/readv để xem có bao nhiêu byte bị ghi như bạn làm trong write().

bạn có thể tìm mã của writev trong kernel, fs/read_write.c: do_readv_writev.

5

Cách trực tiếp để biết mã hoạt động như thế nào là đọc mã nguồn.

thấy http://www.oschina.net/code/explore/glibc-2.9/sysdeps/posix/writev.c

Nó simplely alloca() hoặc malloc() một bộ đệm, sao chép tất cả các vectơ vào nó, và gọi write() một lần.

Cách hoạt động. Không có gì bí ẩn.

+0

Đó là glibc writev, không phải là linux kernel writev. – Eloff

+0

Chỉ cần tìm hiểu về mempcpy từ liên kết đó là một chiến thắng hoành tráng. – RishiD