深入了解Python的读/写/查找操作

Tal*_*als 4 c python linux linux-device-driver python-2.7

在Linux系统上创建字符设备时,我使用Python及其基本文件操作与其进行了交互。

经历几次崩溃后,我开始打印调试消息并注意到一个奇怪的行为:Python似乎在“优化”文件操作方面产生了怪异的感觉。

让我们看一个例子。这是交互的基本代码和输出:

内核模块

// Several includes and kernel module initialization

static ssize_t dev_read(struct file *filep, char *buffer, size_t len, long long *offset){
    printk(KERN_INFO "[DEBUGGER] - dev_read with len: %d, offset: 0x%llx.\n", len, offset[0]);
    return len;
}

static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, long long *offset){
    printk(KERN_INFO "[DEBUGGER] - dev_write with len: %d, offset: 0x%llx.\n", len, offset[0]);
    return len;
}

static long long dev_llseek(struct file *filep, long long offset, int orig){
    printk(KERN_INFO "[DEBUGGER] - dev_llseek with offset: 0x%llx, orig: %d\n", offset, orig);
    return offset;
}

static int dev_release(struct inode *inodep, struct file *filep){
    return 0; // Success
}

static int dev_open(struct inode *inodep, struct file *filep){
    return 0; // Success
}

static struct file_operations fops =
{
   .open = dev_open,
   .read = dev_read,
   .write = dev_write,
   .release = dev_release,
   .llseek = dev_llseek,
};

int init_module(void){
   // Code to create character device
   return 0;
}

void cleanup_module(void){
   // Code to delete character device
}
Run Code Online (Sandbox Code Playgroud)

蟒蛇

// Several includes and kernel module initialization

static ssize_t dev_read(struct file *filep, char *buffer, size_t len, long long *offset){
    printk(KERN_INFO "[DEBUGGER] - dev_read with len: %d, offset: 0x%llx.\n", len, offset[0]);
    return len;
}

static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, long long *offset){
    printk(KERN_INFO "[DEBUGGER] - dev_write with len: %d, offset: 0x%llx.\n", len, offset[0]);
    return len;
}

static long long dev_llseek(struct file *filep, long long offset, int orig){
    printk(KERN_INFO "[DEBUGGER] - dev_llseek with offset: 0x%llx, orig: %d\n", offset, orig);
    return offset;
}

static int dev_release(struct inode *inodep, struct file *filep){
    return 0; // Success
}

static int dev_open(struct inode *inodep, struct file *filep){
    return 0; // Success
}

static struct file_operations fops =
{
   .open = dev_open,
   .read = dev_read,
   .write = dev_write,
   .release = dev_release,
   .llseek = dev_llseek,
};

int init_module(void){
   // Code to create character device
   return 0;
}

void cleanup_module(void){
   // Code to delete character device
}
Run Code Online (Sandbox Code Playgroud)

输出量

# seek(1)
[DEBUGGER] - dev_llseek with offset: 0x0, orig: 0
[DEBUGGER] - dev_read with len: 1, offset: 0x0.
[DEBUGGER] - dev_llseek with offset: 0x1, orig: 0
# read(4)
[DEBUGGER] - dev_read with len: 4, offset: 0x0.
# seek(0x7f123456)
[DEBUGGER] - dev_llseek with offset: 0x7f123000, orig: 0
[DEBUGGER] - dev_read with len: 1110, offset: 0x0.
# read(20)
[DEBUGGER] - dev_read with len: 4096, offset: 0x0.
# write("\xff" * 4)
[DEBUGGER] - dev_write with len: 4, offset: 0x0.
Run Code Online (Sandbox Code Playgroud)

显然,基本文件操作不会直接转换为文件上的相同操作,最清晰的示例是,尝试读取0x7f123000而不是0x7f123456并读取4096个字节,而仅请求读取20个字节。

这提出了以下问题:

  • 为什么有此功能?
  • 它实现了什么优化,因为大多数看起来都不是一个很好的“下一个操作”预测?
  • 是否在任何地方都有文档记录,以便事先了解对读/写功能进行编程时的期望?
  • 除了对这一领域的兴趣外,我仍然希望使用Python来简化访问-那么有什么方法可以禁用此优化,并强制Python像执行这些操作的C代码一样工作?

谢谢!

Tsy*_*rev 5

Python的文件对象实际上是FILE*对象(使用C语言)的包装,因此它们是缓冲流。由于存在缓冲,Python的文件操作不会将它们转换为具有相同参数的syscall,而是尝试优化请求时间(当前和将来的操作)。

方法open() 接受 缓冲参数作为3d参数。传递0应该会禁用缓冲,因此python会将所有文件的请求直接转换为基础系统:

open("/dev/chardevice", "r+b", 0)
Run Code Online (Sandbox Code Playgroud)