我正在使用内核模块中的计时器来处理Debian 6,该模块自动编程以从jiffies获取n个“peudo-random”数字并将它们插入循环缓冲区。 fire_timer被第7次触发时(当items_cbuf == 7时),当发生这种情况时,操作系统执行崩溃就会出现问题:
mod_timer(&my_timer, my_timer.expires);
但不是之前,所以我不知道为什么会这样。有提示吗?预期的工作方式是当缓冲区达到其容量的80%时,整个内容将被转换为列表(即工作队列任务)
编辑:我已经完成了我的完整代码,peoblem可以在任何地方,我不想限制分辨率。我不确定,但相关的功能应该是:install_module,Open_module,Fire_timer和release_module。我所做的确切用法是开放的,等待十秒,之后我从proc条目中读取,但由于系统冻结我无法读取定义
#define PROC_ENTRY "modtimer"
#define PROC_ENTRY_OPS "modconfig"
#define CBUFFER_SIZE 10
#define MAX_BUFFER 512
[...]
/**********************************************************/
/*********** Open-close-read-write functions **************/
/**********************************************************/
/*Module instalation*/
int install_module(void){
int ret = 0;
/*Buffer treshold*/
TRESHOLD_SIZE = 80;
/*Delay in ticks*/
DELAY = 125;
/*timer init*/
my_timer.expires = jiffies + DELAY;
my_timer.data = 0;
my_timer.function = fire_timer;
init_timer(&my_timer);
/*workqueue init*/
workqueue_pendiente = 0;
INIT_WORK(&my_workqueue, copy_items_into_list);
/* semaphore init */
sema_init(&mtx,1);
openDevices = 0;
/*del spin_lock init*/
spin_lock_init(&spinlock);
/*buffer init*/
cbuf = create_cbuffer_t(CBUFFER_SIZE);
printk(KERN_INFO "buffer creado");
items_cbuf = 0;
/*list init*/
list_num_items = 0;
// another initializations
return ret;
}
[...]
static int modtimer_open (struct inode *inod, struct file *f){
int ret = 0;
//Iniciar el timer
if(openDevices==0){
my_timer.expires = jiffies + DELAY;
add_timer(&my_timer);
}
try_module_get(THIS_MODULE);
openDevices++;
return ret;
}
static int modtimer_release (struct inode *inod, struct file *f){
del_timer_sync(&my_timer);
flush_scheduled_work();
remove_cbuffer_t (cbuf); //delete the buffer
vacia_list_item(); //removes every element from the list
openDevices--;
module_put(THIS_MODULE);
return 0;
}
static ssize_t modtimer_read (struct file *file, char *user, size_t nbits, loff_t * offset){
struct list_head* pos = mylist.next;
struct list_head* auxpos;
list_item_t* item;
char aux[MAX_BUFFER];
char aux2[10];
int total =0;
int subt =0;
int hecho = 0;
if(down_interruptible(&mtx)){
return -EINTR;
}
while (hecho == 0){
if(pos == pos->next || list_num_items ==0){
hecho++;
}else{
item = list_entry(pos, list_item_t, links);
subt=sprintf(aux2, "%d\n",item->data);
auxpos = pos->next;
if(subt + total > MAX_BUFFER ) {
hecho++;
}else {
total+= sprintf(&aux[total],"%i\n",item->data);
list_del(pos);
vfree(item);
list_num_items--;
}
subt = 0;
pos = auxpos;
}
}
aux[total] = '\0';
up(&mtx);
copy_to_user(user,aux,total);
return total;
}
/*********************************************************/
/****************** Planified functions ******************/
/*********************************************************/
//Fills a buffer with integgers and planifies when is about to be out of space
void fire_timer(unsigned long data){
unsigned long flags;
int rnd = jiffies & 0xFF;
spin_lock_irqsave(&spinlock,flags);
if(!is_full_cbuffer_t(cbuf))
{
items_cbuf++;
insert_cbuffer_t(cbuf, rnd);
}
printk(KERN_INFO "workqueue_pendiente = %d, items_cbuf=%d, CBUFFER_SIZE = %d, TRESHOLD_SIZE = %d, umbral = %d",
workqueue_pendiente, items_cbuf, CBUFFER_SIZE, TRESHOLD_SIZE, (CBUFFER_SIZE*TRESHOLD_SIZE)/100);
if(workqueue_pendiente == 0 &&
items_cbuf >= (CBUFFER_SIZE*TRESHOLD_SIZE)/100 )
{
workqueue_pendiente=1;
schedule_work(&my_workqueue);
}
my_timer.expires = jiffies + DELAY;
spin_unlock_irqrestore(&spinlock,flags);
mod_timer(&my_timer, my_timer.expires);
}
void copy_items_into_list(struct work_struct *work){ //Dumps the buffer into the list
unsigned long flags;
list_item_t *items[items_cbuf];
int numbers[items_cbuf];
int a = -1;
while (++a < items_cbuf){
items[a] = vmalloc(sizeof(list_item_t));
}
a = -1;
spin_lock_irqsave(&spinlock,flags);
while(++a < items_cbuf){
numbers[a] = *head_cbuffer_t(cbuf);
remove_cbuffer_t(cbuf);
}
workqueue_pendiente = 0;
spin_unlock_irqrestore(&spinlock,flags);
a = -1;
if (down_interruptible(&mtx)) /*BLOQUEO*/
return;
while (++a < items_cbuf){//size_cbuffer_t(cbuf) > 0){
items[a]->data = numbers[a];
list_add_tail(&items[a]->links, &mylist);
list_num_items++;
}
up(&mtx);
}
这是我在系统冻结之前可以获得的代码:
“睡觉,剩下的6是来自我的测试程序的消息,它的内容只是
int main(void){
int l;
int i=11;
char bla[512];
l = open("/proc/modtimer",O_RDONLY);
bla[2] = '\0';
while(--i>=0){
printf("sleeping, remaining %d\n",i);
sleep(1);
}
read(l,bla,128);
close(l);
printf("numbers:%s",bla);
}
答案 0 :(得分:2)
在fire_timer()
spin_unlock_irqrestore(&spinlock,flags);
,您只需拨打spin_lock_irqsave()
两次即可拨打{{1}}。
答案 1 :(得分:0)
经过大量的工作后,我决定澄清我的代码,我发现一些指针失败了,我遇到了一对copy_to_user / from_user和/ proc条目的问题。我的全部新代码都出现在那些可能需要它的人身上(这次我不会删除西班牙语中的comentarys和printk:
#define PROC_ENTRY "modtimer"
#define PROC_ENTRY_OPS "modconfig"
#define CBUFFER_SIZE 10
#define MAX_BUFFER 512
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/proc_fs.h>
#include <linux/semaphore.h>
#include <linux/vmalloc.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <asm-generic/uaccess.h>
#include "cbuffer.h"
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Pseudo-Random number generator for DSO");
MODULE_AUTHOR("Kaostias*emphasized text*");
/**********************************************************/
/********************** Declaraciones *********************/
/**********************************************************/
/*Declaracion del timer*/
struct timer_list my_timer;
/*Declaracion del workqueue*/
struct work_struct my_workqueue;
/* Indica si el workqueue está planificado */
int workqueue_pendiente;
/*Entrada en proc*/
static struct proc_dir_entry *proc_entry, *proc_entry_opts;
/*Semáforo utilizado como un spin_lock para poder usar funciones bloqueantes*/
struct semaphore mtx;
int openDevices;
/*Semáforo consumidor*/
struct semaphore consumer;
int cons_waiting;
/*Spinlock*/
DEFINE_SPINLOCK(spinlock);
/*Lista*/
struct list_head mylist = LIST_HEAD_INIT(mylist);
typedef struct {
int data;
struct list_head links;
}list_item_t;
/*Buffer de enteros*/
cbuffer_t *cbuf;
/* Umbral de llenado del buffer*/
int TRESHOLD_SIZE; // 80
/* Cada cuantos ticks se dispara la rutina */
int DELAY;// 125 (1 cada medio seg)
/*Funciones*/
void vacia_list_item(void);
void fire_timer(unsigned long data);
void copy_items_into_list(struct work_struct *work);
static int modtimer_open (struct inode *, struct file *);
static int modtimer_release (struct inode*, struct file *);
static ssize_t modtimer_read (struct file *file, char __user*, size_t nbits, loff_t * offset);
/*Se escribe la entrada PROC_ENTRY_OPS*/
int procOpsWrite( struct file *punterofichero, const char __user *bufferusuario,
unsigned long longitud, void *data);
int procOpsRead( char *buffer, char **bufferlocation, off_t offset,
int buffer_lenghth, int *eof, void *data );
/*Operaciones de proc PROC_ENTRY*/
static const struct file_operations my_fops = {
.open = modtimer_open,
.read = modtimer_read,
.release = modtimer_release,
};
/**********************************************************/
/********* Funciones de apertura/cierre/lectura ***********/
/**********************************************************/
/*Instalación del módulo*/
int install_module(void){
int ret = 0;
printk(KERN_INFO "instalando módulo");
/*Umbral de vaciado del buffer*/
TRESHOLD_SIZE = 80;
/*Cada cuantos tics se dispara la rutina*/
DELAY = 125;
/*Inicialización del timer*/
my_timer.expires = jiffies + DELAY;
my_timer.data = 0;
my_timer.function = fire_timer;
init_timer(&my_timer);
printk(KERN_INFO "creado timer");
/*Inicialización de la cola de trabajo*/
workqueue_pendiente = 0;
INIT_WORK(&my_workqueue, copy_items_into_list);
printk(KERN_INFO "creada workqueue");
/* Inicialización del semáforo */
sema_init(&mtx,1);
openDevices = 0;
sema_init(&consumer,0);
cons_waiting = 0;
printk(KERN_INFO "inicializado semáforo");
/*Inicialización del spin_loc*/
spin_lock_init(&spinlock);
printk(KERN_INFO "inicializado spinlock");
/*Inicialización del buffer*/
cbuf = create_cbuffer_t(CBUFFER_SIZE);
printk(KERN_INFO "buffer creado");
/* Zona de las entradas de /proc */
proc_entry = create_proc_entry(PROC_ENTRY,0777, NULL);
if (proc_entry == NULL) {
ret = -ENOMEM;
printk(KERN_INFO "Error: No puedo crear la entrada en proc /proc/%s\n",PROC_ENTRY);
} else {
proc_entry->proc_fops=&my_fops;
printk(KERN_INFO "Entrada /proc/%s creada.\n", PROC_ENTRY);
}
proc_entry_opts = create_proc_entry(PROC_ENTRY_OPS,0777, NULL);
if (proc_entry_opts == NULL) {
ret = -ENOMEM;
printk(KERN_INFO "Error: No puedo crear la entrada en proc /proc/%s\n",PROC_ENTRY_OPS);
remove_proc_entry(PROC_ENTRY, NULL);
printk(KERN_INFO "Entrada /proc/%s eliminada.\n", PROC_ENTRY);
} else {
proc_entry_opts->read_proc = procOpsRead;
proc_entry_opts->write_proc =procOpsWrite;
printk(KERN_INFO "Entrada /proc/%s creada.\n", PROC_ENTRY_OPS);
}
printk(KERN_INFO "módulo instalado correctamente");
return ret;
}
/*Al desinstalar el módulo*/
void uninstall_module(void){
printk(KERN_INFO "Desinstalando módulo");
/*Quita proc entries*/
remove_proc_entry(PROC_ENTRY, NULL);
printk(KERN_INFO "Entrada /proc/%s eliminada.\n", PROC_ENTRY);
remove_proc_entry(PROC_ENTRY_OPS, NULL);
printk(KERN_INFO "Entrada /proc/%s eliminada.\n", PROC_ENTRY_OPS);
printk(KERN_INFO "Desinstalación completa");
}
/*Se escribe la entrada PROC_ENTRY_OPS*/
int procOpsWrite( struct file *punterofichero, const char __user *bufferusuario,
unsigned long longitud, void *data){
//char aux[MAX_BUFFER];
int period =0;
int treshold=0;
char aux[MAX_BUFFER] = "";
printk(KERN_INFO "entrando en proc_ops_write, deberia ejecutarse al abrir /proc/%s\n",PROC_ENTRY_OPS);
if (longitud > MAX_BUFFER) return -1;
printk(KERN_INFO "1");
if(copy_from_user(aux,bufferusuario,longitud))
return -EINVAL;
printk(KERN_INFO "2");
aux[longitud] = '\0';
if(sscanf(aux,"timer_period=%d",&period) == 1){
if(period >0 && period < 10000)
DELAY = period;
}
printk(KERN_INFO "2");
if(sscanf(aux,"emergency_threshold=%d",&treshold) == 1){
if(treshold > 0 && treshold <=100)
TRESHOLD_SIZE = treshold;
}
return longitud;
}
/*Se lee la entrada PROC_ENTRY_OPS*/
int procOpsRead( char *buffer, char **bufferlocation, off_t offset,
int buffer_lenghth, int *eof, void *data ){
//char aux[MAX_BUFFER];
int i = sprintf(buffer,"Timer_period=%d\nEmergency_threshold=%d\n",DELAY,TRESHOLD_SIZE);
return i;
}
/*Apertura de la entrada PROC_ENTRY*/
static int modtimer_open (struct inode *inod, struct file *f){
int ret = 0;
printk(KERN_INFO "entrando en modtimer_open");
//Iniciar el timer
if(openDevices==0){
my_timer.expires = jiffies + DELAY;
add_timer(&my_timer);
}
try_module_get(THIS_MODULE);
openDevices++;
printk(KERN_INFO "saliendo de modtimer_open");
return ret;
}
/*Se cierra la entrada PROC_ENTRY*/
static int modtimer_release (struct inode *inod, struct file *f){
int ret = 0;
printk(KERN_INFO "modtimer_release abierto");
//Eliminar temporizador
del_timer_sync(&my_timer);
printk(KERN_INFO "timer borrado");
//Esperar a que todo el trabajo planificado termine
flush_scheduled_work();
printk(KERN_INFO "workqueue finalizada");
/*Vacía el buffer*/
remove_cbuffer_t (cbuf);
/*Vacía la lista */
vacia_list_item();
printk(KERN_INFO "lista vacia");
openDevices--;
module_put(THIS_MODULE);
printk(KERN_INFO "modtimer_release cerrado");
return ret;
}
/*Se lee la entrada PROC_ENTRY*/
static ssize_t modtimer_read (struct file *file, char *user, size_t nbytes, loff_t * offset){
struct list_head* pos;
struct list_head* auxpos;
list_item_t* item;
char aux[MAX_BUFFER]="";
char aux2[10];
int total =0;
int subt =0;
printk(KERN_INFO "modtimer_read abierto");
if(down_interruptible(&mtx)){
return -EINTR;
}
/* SEMAFORO QUE COMPRUEBA QUE HAYA ELEMENTOS QUE LEER ANTES DE LEER */
while(list_empty(&mylist)){
cons_waiting++;
up(&mtx);
if(down_interruptible(&consumer)){
down(&mtx);
cons_waiting--;
up(&mtx);
return -EINTR;
}
if(down_interruptible(&mtx)){
return -EINTR;
}
}
/*
* Vaciar toda la lista que sea posible, dentro del tamaño máximo (512
* bytes es el máximo, así que hay que controlar que al copiar en una
* cadena auxiliar no se sobrepase el buffer.
*/
pos=mylist.next;
while (pos!=&mylist) {
auxpos = pos->next;
item = list_entry(pos, list_item_t, links);
subt=sprintf(aux2, "%d\n",item->data);
if (subt+total>nbytes)
break;
strcat(aux,aux2);
total+=subt;
list_del(pos);
vfree(item);
printk(KERN_INFO "sacado de la lista");
pos = auxpos;
}
//printk(KERN_INFO "Fuera del bucle, cadena copiada: %s\nTotal copiado:%d\nSizeof(aux):%d",aux,total,sizeof(aux));
up(&mtx);
if (copy_to_user(user,aux,total))
return -1;
printk(KERN_INFO "modtimer_read cerrado");
return total;
}
/*********************************************************/
/**************** Funciones planificadas *****************/
/*********************************************************/
/*Rutina que inserta números en el buffer cada pocos ticks*/
void fire_timer(unsigned long data){
unsigned long flags;
int rnd = jiffies & 0xFF;
int items_cbuf;
printk(KERN_INFO "Entrando a fire_timer");
spin_lock_irqsave(&spinlock,flags);
if(!is_full_cbuffer_t(cbuf))
{
insert_cbuffer_t(cbuf, rnd);
printk(KERN_INFO "Numero aleatorio %d",rnd);
}
items_cbuf=size_cbuffer_t(cbuf);
spin_unlock_irqrestore(&spinlock,flags);
printk(KERN_INFO "workqueue_pendiente = %d, items_cbuf=%d, CBUFFER_SIZE = %d, TRESHOLD_SIZE = %d, umbral = %d",
workqueue_pendiente, items_cbuf, CBUFFER_SIZE, TRESHOLD_SIZE, (CBUFFER_SIZE*TRESHOLD_SIZE)/100);
//Si el trabajo no estaba planificado y hace falta planificarlo
if(workqueue_pendiente == 0 &&
items_cbuf >= (CBUFFER_SIZE*TRESHOLD_SIZE)/100 )
{
workqueue_pendiente=1;
//Planificar copy_items_into_list()
schedule_work(&my_workqueue);
printk(KERN_INFO "Planificado");
}
//Programar el timer
printk(KERN_INFO "Byob");
mod_timer(&my_timer, jiffies + DELAY);
printk(KERN_INFO "Saliendo de Fire_timer");
}
/*Copia desde el cbuffer al list_item_t*/
void copy_items_into_list(struct work_struct *work){
unsigned long flags;
list_item_t *items[CBUFFER_SIZE];
int numbers[CBUFFER_SIZE];
int i;
int nr_elems =0;
printk(KERN_INFO "Entrando en copy_items_into_list");
spin_lock_irqsave(&spinlock,flags);
nr_elems = size_cbuffer_t(cbuf);
for(i =0; i< nr_elems;i++){
numbers[i] = *head_cbuffer_t(cbuf);
remove_cbuffer_t(cbuf);
}
workqueue_pendiente = 0; //workqueue no planificado
spin_unlock_irqrestore(&spinlock,flags);
for (i=0;i<nr_elems;i++){
items[i] = (list_item_t*)vmalloc(sizeof(list_item_t));
}
if (down_interruptible(&mtx)) /*BLOQUEO*/
return;
/* vaciar buffer y llenar cola enlazada */
for (i=0;i<nr_elems;i++){
items[i]->data = numbers[i];
list_add_tail(&items[i]->links, &mylist);
}
if (cons_waiting>0){
cons_waiting--;
up(&consumer);
}
up(&mtx);
printk(KERN_INFO "Saliendo de copy_items_into_list");
}
/*********************************************************/
/******************** Utilidades ***********************/
/*********************************************************/
/*Vacía la lista de list_item_t*/
void vacia_list_item(void){
struct list_head* pos = mylist.next;
struct list_head* posaux;
list_item_t* item;
printk(KERN_INFO "Vaciando la lista");
while(!list_empty(&mylist)){
item = list_entry(pos, list_item_t, links);
posaux = pos->next;
list_del(pos);
vfree(item);
pos = posaux;
}
printk(KERN_INFO "Lista vacía");
}
module_init(install_module);
module_exit(uninstall_module);