草庐IT

linux - 如何在内核模块代码中添加轮询功能?

coder 2023-06-17 原文

据我所知,要从内核空间通知用户空间,一种方法是使用轮询。这意味着内核驱动程序应该首先提供 poll 方法。 下面的代码是从网上找来的,确实有效!

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
 
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Fortune Cookie Kernel Module");
MODULE_AUTHOR("M. Tim Jones");
 
#define MAX_COOKIE_LENGTH       PAGE_SIZE
 
static struct proc_dir_entry *proc_entry;
static char *cookie_buf;  // Space for fortune strings
static int write_index;   // Index to write next fortune
static int read_index;    // Index to read next fortune
 
ssize_t fortune_write( struct file *filp, const char __user *buff,
                        unsigned long len, void *data )
// Refer to: ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
{
  int space_available = (MAX_COOKIE_LENGTH-write_index);
 
  if (len > space_available) {
    printk(KERN_INFO "fortune: cookie buffer is full!\n");
    return -ENOSPC;
  }
 
  if (copy_from_user( &cookie_buf[write_index], buff, len )) {
    return -EFAULT;
  }
 
  write_index += len;
  cookie_buf[write_index-1] = 0;
 
  return len;
}
 
ssize_t fortune_read(struct file *file, char *buf, size_t count, loff_t *f_pos){
// Refer to: ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    int len;
 
    //there's no fortune or a fortune has already been read
    //the *f_pos > 0 hack is needed because `cat /proc/fortune` would otherwise
    //display every thing in the cookie_buf
    if(write_index == 0 || *f_pos > 0){
        return 0;
    }
 
    // cicle through fortunes
    if(read_index >= write_index){
        read_index = 0;
    }
 
    len = sprintf(buf, "%s\n", &cookie_buf[read_index]);
 
    read_index += len;
    *f_pos += len;
 
    return len;
}
 
static const struct file_operations proc_test_fops = {
   .owner        = THIS_MODULE,
//    .open        = led_proc_open,
   .read        = fortune_read,
//    .llseek        = seq_lseek,
//    .release    = single_release,
   .write        = fortune_write,
//    unsigned int (*poll) (struct file *, struct poll_table_struct *);
//    int (*fasync) (int, struct file *, int);
};
 
int __init init_fortune_module( void )
{
    int ret = 0;
    cookie_buf = (char *)vmalloc( MAX_COOKIE_LENGTH );
    if (!cookie_buf) {
        ret = -ENOMEM;
    } else {
        memset( cookie_buf, 0, MAX_COOKIE_LENGTH );
//        proc_entry = create_proc_entry( "fortune", 0644, NULL );
        proc_entry = proc_create( "fortune", 0644, NULL, &proc_test_fops );
 
        if (proc_entry == NULL) {
            ret = -ENOMEM;
            vfree(cookie_buf);
            printk(KERN_INFO "fortune: Couldn't create proc entry\n");
        } else {
            write_index = 0;
            read_index = 0;
            printk(KERN_INFO "fortune: Module loaded.\n");
        }
    }
 
    return ret;
}
 
void __exit exit_fortune_module( void )
{
//    remove_proc_entry("fortune", &proc_entry);
    proc_remove(proc_entry);
    vfree(cookie_buf);
    printk(KERN_INFO "fortune: Module unloaded.\n");
}
 
module_init( init_fortune_module );
module_exit( exit_fortune_module );

我可以这样做让它工作:

echo "hello" > /proc/fortune

然后

cat /proc/fortune

查看结果。

但是如何给它添加poll方法呢?我尝试了几次,但还是失败了。

最佳答案

你可以在内核中找到一些很好的例子。查看下一个文件:

要将 poll() 函数添加到您的代码中,请按照以下步骤操作。

  1. 包括所需的 header :

     #include <linux/wait.h>
     #include <linux/poll.h>
    
  2. 声明等待队列变量:

     static DECLARE_WAIT_QUEUE_HEAD(fortune_wait);
    
  3. 添加 fortune_poll() 函数并将其(作为 .poll 回调)添加到您的文件操作结构中:

     static unsigned int fortune_poll(struct file *file, poll_table *wait)
     {
         poll_wait(file, &fortune_wait, wait);
         if (new-data-is-ready)
             return POLLIN | POLLRDNORM;
         return 0;
     }
    
     static const struct file_operations proc_test_fops = {
         ....
         .poll = fortune_poll,
     };
    

    请注意,您应该返回 POLLIN | POLLRDNORM 如果您有一些新数据要读取,0 如果没有新数据要读取(poll() 调用超时)。参见 man 2 poll了解详情。

  4. 一旦有新数据就通知您的等待队列:

     wake_up_interruptible(&fortune_wait);
    

这是实现 poll() 操作的基本内容。根据您的任务,您可能需要使用一些 waitqueue API在您的 .read 函数中(如 wait_event_interruptible())。


另见相关问题:Implementing poll in a Linux kernel module .

关于linux - 如何在内核模块代码中添加轮询功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30035776/

有关linux - 如何在内核模块代码中添加轮询功能?的更多相关文章

  1. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  2. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  5. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  6. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  7. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  8. ruby - 将 Bootstrap Less 添加到 Sinatra - 2

    我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它

  9. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  10. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

随机推荐