用于生成随机数的字符设备实现

问题描述:

基于我的学习项目,我目前的任务是使用内核模块生成10个随机数,我的用户空间程序(c程序)应该能够显示这些数字。我一直在学习内核空间和用户空间程序。我遇到了字符设备的创建。我使用这个命令创建了一个设备。用于生成随机数的字符设备实现

mknod /dev/my_device c 222 0 

从我所了解的设备看来,它是用户空间和内核空间程序之间的中介。所以,我创建了一个内核模块至极登记和注销我的性格device.Saved作为my_dev.c

#include<linux/module.h> 
#include<linux/init.h> 
#include"my_dev.h" 

MODULE_AUTHOR("Krishna"); 
MODULE_DESCRIPTION("A simple char device"); 

static int r_init(void); 
static void r_cleanup(void); 

module_init(r_init); 
module_exit(r_cleanup); 


static int r_init(void) 
{ 
printk("<1>hi\n"); 
if(register_chrdev(222,"my_device",&my_fops)){ 
    printk("<1>failed to register"); 
} 
return 0; 
} 
static void r_cleanup(void) 
{ 
printk("<1>bye\n"); 
unregister_chrdev(222,"my_device"); 
return ; 
} 

为compling这个模块我Make文件是

obj-m += my_dev.o 

all: 
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 

clean: 
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 

这个内核模块编译并加载到内存中使用insmod命令。

这是一个写入并读取一些文本到用户缓冲区保存为my_dev.h的程序。

/* 
* my device header file 
*/ 
#ifndef _MY_DEVICE_H 
#define _MY_DEVICE_H 

#include <linux/fs.h> 
#include <linux/sched.h> 
#include <linux/errno.h> 
#include <asm/current.h> 
#include <asm/segment.h> 
#include <asm/uaccess.h> 

char my_data[80]="heloooo"; /* our device */ 

int my_open(struct inode *inode,struct file *filep); 
int my_release(struct inode *inode,struct file *filep); 
ssize_t my_read(struct file *filep,char *buff,size_t count,loff_t *offp); 
ssize_t my_write(struct file *filep,const char *buff,size_t count,loff_t *offp); 

struct file_operations my_fops={ 
    open: my_open, 
    read: my_read, 
write: my_write, 
release:my_release, 
}; 

int my_open(struct inode *inode,struct file *filep) 
{ 
    /*MOD_INC_USE_COUNT;*/ /* increments usage count of module */ 
return 0; 
} 

int my_release(struct inode *inode,struct file *filep) 
{ 
/*MOD_DEC_USE_COUNT;*/ /* decrements usage count of module */ 
return 0; 
} 
ssize_t my_read(struct file *filep,char *buff,size_t count,loff_t *offp) 
{ 
/* function to copy kernel space buffer to user space*/ 
if (copy_to_user(buff,my_data,strlen(my_data)) != 0) 
    printk("Kernel -> userspace copy failed!\n"); 
return strlen(my_data); 

} 
ssize_t my_write(struct file *filep,const char *buff,size_t count,loff_t *offp) 
{ 
/* function to copy user space buffer to kernel space*/ 
if (copy_from_user(my_data,buff,count) != 0) 
    printk("Userspace -> kernel copy failed!\n"); 
return 0; 
} 
#endif 

这里是我的用户空间程序acs.c其在被从上述程序读取从内核缓冲区文本打印运行“heloooo”。

#include<stdio.h> 
#include<unistd.h> 
#include<sys/types.h> 
#include<sys/stat.h> 
#include<fcntl.h> 

int main() 
{ 
int fd=0,ret=0; 
char buff[80]=""; 

fd=open("/dev/my_device",O_RDONLY); 

printf("fd :%d\n",fd); 

ret=read(fd,buff,10); 
buff[ret]='\0'; 

printf("buff: %s ;length: %d bytes\n",buff,ret); 
close(fd); 
} 

现在我的问题是我需要写一个用户空间程序,它运行打印10个随机数。但是这些数字应该使用内核模块生成。所以基本上在三个代码上正确地打印并打印出“helooo”。我需要做的是取代“helooo”,我需要随机数字作为输出。

这是一个内存模块,它使用线性同余生成器算法生成一些随机数。 LCG.c

#include <linux/module.h> /* Needed by all modules */ 
#include <linux/kernel.h> /* Needed for KERN_INFO */ 

int init_module(void) 
{ 
int M = 8; //Modulus, M>0 
    int a = 9; //Multiplier, 0 <= a < M. 
    int c = 3; //Increment, 0 <= c < M. 
    int X = 1; //seed value, 0 <= X(0) < M 
    int i;  //iterator, i < M 
    for(i=0; i<8; i++) 
    { 
      X = (a * X + c) % M; 
      printk(KERN_INFO "%d\n",X); 

    } 
    return 0; 
} 
void cleanup_module(void) 
{ 
printk(KERN_INFO "Task Done ! :D.\n"); 
} 

我有所有的代码。但我不知道如何适应这个随机数发生器代码在我的字符设备调用代码。当我运行程序acs.c我需要通过使用字符设备获得内存模块LCG.c的输出。请帮我找到一个解决方案。

+0

'ret = read(fd,buff);''read()'需要3个参数,忘记最后一个(nbytes) – 2013-04-05 15:24:03

+0

但是这个程序即使没有第三个参数 – Krishna 2013-04-06 05:19:23

+0

你确定吗?它不会编译:'错误:数组初始化必须是一个初始化列表int buff [80] =“”;' – 2013-04-06 07:37:40

这些变化试试,我刚加入的变化:

重构LCG.C使随机数生成器是一个单独的功能,确保此功能是不是静态。您还需要导出此SYMBOL。

void generate_random_lcg(char* output_str) 
{ 
    static const int M = 8; //Modulus, M>0 
    static const int a = 9; //Multiplier, 0 <= a < M. 
    static const int c = 3; //Increment, 0 <= c < M. 
    static int X = 1; //seed value, 0 <= X(0) < M 

    int i;  //iterator, i < M 
    ssize_t index = 0; 
    for(i=0; i<8; i++) 
    { 
     X = (a * X + c) % M; 
     index += sprintf(output_str + index, "%d\n", X); 
    } 
    output_str[index] = '\0'; 
} 

EXPORT_SYMBOL(generate_random_lcg); 

这样,该功能可以直接由LCG模块调用,也可以从外部调用。

我们了解你的模块my_dev调用这个函数,并返回输出,你需要这些变化:

my_dev.c

static int r_init(void) 
{                 
    printk("<1>hi\n"); 
    if(register_chrdev(222,"my_device",&my_fops)){     
      printk("<1>failed to register");      
    } 

    memset(output_str, 0, MAX_SIZE);        

    return 0;              
} 

my_dev。^ h

extern void generate_random_lcg(char* output_str); 

#define MAX_SIZE 1024 
static char output_str[MAX_SIZE]; 

ssize_t my_read(struct file *filep,char *buff,size_t count,loff_t *offp) 
{ 
    ssize_t output_str_size = 0; 
    generate_random_lcg(output_str); 
    output_str_size = strlen(output_str); 
    /* function to copy kernel space buffer to user space*/ 
    if (copy_to_user(buff,output_str,output_str_size) != 0) 
    { 
     printk("Kernel -> userspace copy failed!\n"); 
     return 0; 
    } 
    return output_str_size; 
} 

几件事情要记住:

  • 更新MAX_SIZE的值按您的需求。如果数量变得非常大,您可以考虑使用kmalloc来获取内存。
  • 除了内联函数,在.h文件中定义函数实现是一种非常糟糕的编码习惯。
  • copy_from_usercopy_to_user失败返回0而不是strlen的输出。

上面只是一个非常粗糙的实现,当使用sprintf打印字符串时,您可能还需要额外的检查来检查缓冲区溢出。

+0

非常感谢。这非常有帮助:) – Krishna 2013-05-04 12:02:25