2008-11-03 29 views
28

Nó chỉ ra toàn bộ sự hiểu lầm của mở() so với fopen() bắt nguồn từ trình điều khiển I2C lỗi trong hạt nhân Linux 2.6.14 trên ARM. Quay trở lại một trình điều khiển bit bashed làm việc giải quyết nguyên nhân gốc rễ của vấn đề tôi đã cố gắng để giải quyết ở đây.Làm thế nào bạn có thể xóa một ghi bằng cách sử dụng một bộ mô tả tập tin?

Tôi đang cố gắng tìm ra sự cố với trình điều khiển thiết bị nối tiếp trong Linux (I2C). Nó xuất hiện rằng bằng cách thêm tạm thời hệ điều hành tạm dừng (ngủ) giữa viết và đọc trên thiết bị những thứ làm việc ... (nhiều) tốt hơn.

Ngoài: Bản chất của I2C là mỗi byte đọc hoặc bằng văn bản của tổng thể được thừa nhận bởi các thiết bị ở đầu bên kia của dây (nô lệ) - tạm dừng việc cải thiện điều khuyến khích tôi phải suy nghĩ của tài xế làm việc không đồng bộ - thứ mà tôi không thể hòa giải với cách hoạt động của xe buýt. Anyhoo ...

tôi muốn hoặc như để tuôn write để chắc chắn (hơn là sử dụng tạm dừng thời gian cố định), hoặc bằng cách nào đó kiểm tra xem ghi/giao dịch đọc đã hoàn thành theo cách thân thiện với nhiều luồng.

Vấn đề với việc sử dụng fflush(fd); là nó đòi hỏi 'fd' là dòng con trỏ (không phải là một mô tả tập tin) tức là

FILE * fd = fopen("filename","r+"); 
... // do read and writes 
fflush(fd); 

Vấn đề của tôi là tôi yêu cầu sử dụng của ioctl(), mà không làm sử dụng một con trỏ dòng. tức là

int fd = open("filename",O_RDWR); 
ioctl(fd,...); 

Gợi ý?

+1

Trong mã vùng người dùng, hàm write() tự động không được đệm. Bạn không cần phải tuôn ra nó - nó là tự xả. Thật vậy, trừ khi bạn sử dụng các cuộc gọi hệ thống đặc biệt, nó cũng đồng bộ với trình điều khiển thiết bị. –

+0

Nếu bạn đang viết một mô-đun cấp hạt nhân, các quy tắc có thể hơi khác nhau, nhưng sau đó bạn có lẽ nên sử dụng mô tả tập tin i/o và không chuẩn (con trỏ tập tin) i/o. –

Trả lời

23

Bạn có hai lựa chọn:

  1. Sử dụng fileno() để có được những mô tả tập tin liên quan đến con trỏ stdio dòng

  2. Không sử dụng <stdio.h> ở tất cả, như vậy bạn không cần phải lo lắng về tuôn ra hoặc - tất cả các ghi sẽ đi đến thiết bị ngay lập tức, và cho các thiết bị ký tự, cuộc gọi write() thậm chí sẽ không trở lại cho đến khi mức IO thấp hơn đã hoàn thành (theo lý thuyết).

IO mức thiết bị Tôi cho rằng việc sử dụng stdio là điều không bình thường. Tôi rất muốn khuyên bạn sử dụng cấp thấp open(), read()write() chức năng thay vì (dựa trên câu trả lời sau đó của bạn):

int fd = open("/dev/i2c", O_RDWR); 
ioctl(fd, IOCTL_COMMAND, args); 
write(fd, buf, length); 
+0

Tránh là những gì tôi đã làm; "Bên cạnh" trong bài viết gốc của tôi đã khiến tôi nghĩ rằng các bộ mô tả tập tin _might_ đã được đệm. Cảm ơn bạn đã xác nhận rằng họ không phải là và rằng tôi nên tìm kiếm một lý do pummeling xe buýt I2C gây ra rắc rối. – Jamie

+1

Hãy làm cho thuật ngữ rõ ràng - một mô tả tập tin UNIX là một chỉ số nguyên và được cho là không bị chặn để cuộc gọi viết/đọc là ngay lập tức. Nó được cho là rất hiệu quả đối với "lớn" viết và không hiệu quả cho các byte ghi đơn. fopen cung cấp cho bạn đệm I/O. Sử dụng mở/đọc/ghi. – plinth

7

fflush() chỉ flushes đệm thêm bởi lớp stdio fopen(), như quản lý bởi đối tượng FILE * . Các tập tin cơ bản chính nó, như được nhìn thấy bởi hạt nhân, không phải là đệm ở cấp độ này. Điều này có nghĩa là viết rằng bỏ qua các lớp FILE *, sử dụng fileno()write() thô, cũng không được đệm theo cách mà fflush() sẽ tuôn ra.

Khi những người khác đã chỉ ra, hãy thử không phải trộn hai. Nếu bạn cần sử dụng các hàm I/O "thô", chẳng hạn như ioctl(), thì hãy tự mình open() tệp trực tiếp, mà không cần sử dụng fopen<() và bạn bè từ stdio.

1

Nếu bạn muốn đi theo chiều ngược lại (sư FILE * với mô tả tập tin hiện có), sử dụng fdopen():

              FDOPEN(P) 

NAME 

     fdopen - associate a stream with a file descriptor 

SYNOPSIS 

     #include <stdio.h> 

     FILE *fdopen(int fildes, const char *mode); 
2

Nghe có vẻ giống như những gì bạn đang tìm kiếm là fsync() chức năng (hoặc fdatasync()?), hoặc bạn có thể sử dụng cờ O_SYNC trong cuộc gọi mở() của bạn.

25

Tôi nghĩ rằng những gì bạn đang tìm kiếm có thể

int fsync(int fd); 

hoặc

int fdatasync(int fd); 

fsync sẽ tuôn ra những tập tin từ bộ đệm hạt nhân vào đĩa. fdatasync cũng sẽ làm ngoại trừ dữ liệu meta.

+1

OP cho biết đây là thiết bị ký tự i2c, không phải đĩa. – Alnitak

+1

Ok, các nút dev i2c không được đệm trang vì vậy nó không cần phải được flushed/sync'ed. Các fops trong trình điều khiển thiết bị xác định những gì đang thực sự thực hiện. –

+2

Mặc dù đây không phải là giải pháp cho câu hỏi của OP, nó rất hữu ích cho những người khác hỏi câu hỏi chính. Tôi ** đang ** ghi vào đĩa thông qua fd, vì vậy rất hữu ích khi xem cách xóa bộ đệm hạt nhân. – Eponymous

1

Bạn đã thử tắt tính năng lưu vào bộ đệm chưa?

setvbuf(fd, NULL, _IONBF, 0); 
+1

Điều này làm việc cho tôi. Tôi không chắc thiết lập của mình là gì, nhưng tôi đã sử dụng nó và "fsync" (sử dụng fileno để lấy int thay vì FILE *) và tôi có thể tìm kiếm và đọc từ tệp sau khi đóng và mở lại nó. – HappyPandaFace

Các vấn đề liên quan