Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/108.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Loops 从字符设备读取时无休止地循环_Loops_Kernel_Driver_Device - Fatal编程技术网

Loops 从字符设备读取时无休止地循环

Loops 从字符设备读取时无休止地循环,loops,kernel,driver,device,Loops,Kernel,Driver,Device,作为家庭作业,我写了一个字符设备驱动程序。它似乎工作正常。我能读能写。问题是,当我读取设备时,它会无休止地循环,一遍又一遍地打印出消息缓冲区的内容 这似乎应该是相当直截了当的。只需使用copy_to_user(),但事实证明这是非常有问题的 不管怎样,这是代码。我认为问题出在gdev_read()函数中。 printk是用来调试和讨论的,因为我必须在课堂上介绍这个项目 /* * Implement a generic character pseudo-device driver */ #i

作为家庭作业,我写了一个字符设备驱动程序。它似乎工作正常。我能读能写。问题是,当我读取设备时,它会无休止地循环,一遍又一遍地打印出消息缓冲区的内容

这似乎应该是相当直截了当的。只需使用copy_to_user(),但事实证明这是非常有问题的

不管怎样,这是代码。我认为问题出在gdev_read()函数中。 printk是用来调试和讨论的,因为我必须在课堂上介绍这个项目

/*
 * Implement a generic character pseudo-device driver
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>

/* you need these, or the kernel will be tainted */
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple sample character device driver");

/*
 * function prototypes
 */
int init_module(void);
void cleanup_module(void);
static ssize_t gdev_read(struct file *, char *, size_t, loff_t *);
static ssize_t gdev_write(struct file *, const char *, size_t, loff_t *);
static int gdev_open(struct inode *, struct file *);
static int gdev_release(struct inode *, struct file *);

/* macros */
#define TRUE 1
#define FALSE 0
#define MAX_MSG_LEN 64

/*
 * global variables
 */
static dev_t dev_num;   /* device number, for new device */
static char *mesg;  /* buffer for message */


/* file operations structure, so my device knows how to act */
static struct file_operations fops = {
    .owner =    THIS_MODULE,
    .read =     gdev_read,
    .write =    gdev_write,
    .open =     gdev_open,
    .release =  gdev_release,
};

/* character device struct.  Declaired here, but initialized elsewhere */
struct cdev *gdev;

int init_module(void)
{   
    int err;
    printk(KERN_ALERT "in init_module\n");

    if(alloc_chrdev_region(&dev_num, 0, 1, "/dev/gdev")){
        printk(KERN_INFO "Could not allocate device numbers\n");
        printk(KERN_INFO "Module gdev not loaded\n");
        return -1;
    }

    /* now I need to make the device and register it */
    gdev = cdev_alloc();
    gdev->owner = THIS_MODULE;
    gdev->ops = &fops;
    err = cdev_add(gdev, dev_num, 1);
    if(err){
        printk(KERN_NOTICE "Error %d adding gdev", err);
        return err;
    }

    mesg = (char *)vmalloc(MAX_MSG_LEN);

    printk(KERN_INFO "Module gdev successfully loaded.\n");
    printk(KERN_INFO "gdev Major Number: %d\n", MAJOR(dev_num));

    return 0;
}


void cleanup_module(void)
{
    printk(KERN_ALERT "in cleanup_module\n");
    unregister_chrdev_region(dev_num, 3);
    vfree(mesg);
    cdev_del( gdev );
    printk(KERN_INFO "Module gdev unregistered\n");
}

static ssize_t gdev_read(struct file *filp, char *page, 
            size_t len, loff_t *offset)
{
    ssize_t bytes = len < MAX_MSG_LEN ? len : MAX_MSG_LEN;
    printk(KERN_ALERT "in gdev_read\n");
    if(copy_to_user(page, mesg, bytes)){
        return -EFAULT;
    }
    return bytes;
}

static ssize_t gdev_write(struct file *filp, const char *page, 
            size_t len, loff_t *offset)
{
    ssize_t bytes = len < MAX_MSG_LEN ? len : MAX_MSG_LEN; 
    printk(KERN_ALERT "in gdev_write\n");
    if(copy_from_user(mesg, page, bytes)){
        return -EFAULT;
    }

    return bytes;
}

static int gdev_open(struct inode *inode, struct file *filp)
{
    printk(KERN_ALERT "in gdev_open\n");
    return 0;
}

static int gdev_release(struct inode *inode, struct file *filp)
{
    printk(KERN_ALERT "in gdev_release\n");
    /* doesn't do anything because it doesn't need too */
    return 0;
}
/*
*实现一个通用字符伪设备驱动程序
*/
#包括
#包括
#包括
#包括
#包括
#包括
#包括
/*你需要这些,否则内核会被污染*/
模块许可证(“GPL”);
模块描述(“一个简单的示例字符设备驱动程序”);
/*
*功能原型
*/
int init_模块(void);
空洞清理模块(空洞);
静态ssize_t gdev_read(结构文件*,字符*,大小,loff_t*);
静态ssize_t gdev_write(结构文件*,常量字符*,大小,loff_t*);
静态int gdev_打开(结构索引节点*,结构文件*);
静态int gdev_发布(结构索引节点*,结构文件*);
/*宏*/
#定义真1
#定义FALSE 0
#定义最大消息长度64
/*
*全局变量
*/
静态dev_t dev_num;/*设备编号,用于新设备*/
静态字符*mesg;/*消息缓冲区*/
/*文件操作结构,因此我的设备知道如何操作*/
静态结构文件\u操作fops={
.owner=此_模块,
.read=gdev_read,
.write=gdev_write,
.open=gdev_open,
.release=gdev_release,
};
/*字符设备结构。在这里声明,但在别处初始化*/
结构cdev*gdev;
int init_模块(void)
{   
INTERR;
printk(初始化模块中的内核警报);
if(alloc_chrdev_region(&dev_num,0,1,“/dev/gdev”)){
printk(KERN_INFO“无法分配设备编号\n”);
printk(内核信息“模块gdev未加载”\n);
返回-1;
}
/*现在我需要制作设备并注册它*/
gdev=cdev_alloc();
gdev->owner=该模块;
gdev->ops=&fops;
err=cdev\u add(gdev,dev\u num,1);
如果(错误){
printk(KERN_通知“添加gdev时出现错误%d”,err);
返回错误;
}
mesg=(字符*)vmalloc(最大值);
printk(KERN_INFO“模块gdev已成功加载。\n”);
printk(KERN_INFO“gdev主要编号:%d\n”,主要编号(dev_num));
返回0;
}
空洞清理_模块(空洞)
{
printk(清除模块中的内核警报);
注销chrdev_区域(dev_num,3);
vfree(mesg);
cdev_del(gdev);
printk(KERN_INFO“模块gdev未注册”\n);
}
静态ssize_t gdev_读取(结构文件*filp,字符*page,
尺寸(长度、落差*偏移)
{
ssize\u t bytes=len
如果未从
read()
返回零(在您的情况下是
gdev\u read()
),则将再次调用read函数。 要停止此操作,请使用
loff\u t*offset
参数。使用
(*offset)+=字节,将其增加读取的字节数
复制到用户()之后。
。下次调用
read()
时,
offset
将是您将其增加到的值。现在只需检查您之前发送的字节数,只发送您剩余的字节数。您的函数应该如下所示:

static ssize_t gdev_read(struct file *filp, char *page, 
            size_t len, loff_t *offset)
{
    ssize_t bytes = len < (MAX_MSG_LEN-(*offset)) ? len : (MAX_MSG_LEN-(*offset));
    printk(KERN_ALERT "in gdev_read\n");
    if(copy_to_user(page, mesg, bytes)){
        return -EFAULT;
    }
    (*offset) += bytes;
    return bytes;
}
static ssize\u t gdev\u read(结构文件*filp,字符*page,
尺寸(长度、落差*偏移)
{
ssize_t bytes=len<(MAX_MSG_len-(*offset))?len:(MAX_MSG_len-(*offset));
printk(gdev_读取中的“内核警报”);
if(将\复制到\用户(第页、中间页、字节)){
返回-默认值;
}
(*偏移量)+=字节;
返回字节;
}

您可以使用'linux/fs.h'中的'simple\u read\u from\u buffer'函数:

static ssize_t gdev_read(struct file *filep, char __user *buff, size_t count, loff_t *offp)
{
    return simple_read_from_buffer(buff, count, offp, my_buffer, buffer_len);
}

my\u buffer”和“buffer\u len”在您的模块中定义。

hm.好的。在花了几天时间搜索web之后,我发现如果我从gdev_read返回0,那么就不会得到无限循环。但是,没有打印任何数据。但愿我能算出这一个。但变量“bytes”的值永远不会为零,所以不会再次调用它吗?这样,它还需要一个额外的条件来“返回0”;即,“if(*ppos!=0),然后返回0;”。从设备读取数据后,应返回0以停止进一步读取。