2014-01-29 49 views
1

我正在使用一個內核模塊中的定時器來處理Debian 6,它自動編程從jiffies中獲取n個「peudo-random」數字並將它們插入到循環緩衝區中。問題是當fire_timer由第七次(當items_cbuf == 7),這種情況發生時,在該行的OS執行崩潰觸發:定時器和自旋鎖凍結

mod_timer(&my_timer, my_timer.expires); 

但在此之前,所以我不知道爲什麼會這樣。任何提示?預期的工作方式是,當緩衝區將在其容量的80%時,整個內容將被轉換成一個列表(即workqueue任務)

編輯:我已經把我的完整的代碼,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); 
} 

這是代碼的系統之前,我可以得到凍結:

Kernel Error

「沉睡,剩餘的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); 
} 
+1

您不能少的代碼 –

+1

我這樣做,對不起,你在閱讀我編輯時 – Kaostias

回答

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); 
1

fire_timer()你叫spin_unlock_irqrestore(&spinlock,flags);的兩倍,而只有在傳喚spin_lock_irqsave()一次。

+0

我的不好,那是不是原來的代碼,我已經離開,如果來自一個證明,謝謝。Tha會使代碼崩潰時運行fire_timer的第一次執行,但我的問題是當items_cbuf = 7 – Kaostias