PDA

View Full Version : [Kernel] kthread e accesso ai device


Dawidh
22-11-2007, 11:39
Allora, ho un problema con la programmazione del kernel.
Mi è stato chiesto di realizzare un modulo che:
creo due device (char) e creo dei kthread (che attendono ciclicamente degli input su uno dei device).


static int output_thread(void *arg)
{
while (!kthread_should_stop()) {

wait_for_completion(&available_data);

printk("1"); //è solo per test

return 0;
}


qunado vado a mettere (tramite echo) qualcosa nel device faccio anche una complete(&available_data); così mi si può sbloccare un kthread. Il mio problema è questo: come faccio dopo la wait a dire al kthread di prendere i dati dal device?

Noi a lezione abbiamo fatto solo cat da spazio utente per estrarre i dati del device, ma come si può fare da kthread.
Oppure, avete un approccio diverso a questo esercizio per risolvere il problema?
Grazie

ilsensine
22-11-2007, 14:29
Il kernel thread viene eseguito in un contesto di processo diverso dal processo utente che effettua la scrittura, quindi non ha modo di accedere direttamente ai dati. Devi usare quindi un buffer intermedio che riempi direttamente nella read e leggi nel kernel thread (protetto da un mutex o uno spinlock ovviamente).

Dawidh
22-11-2007, 18:47
ah, ho capito.. non lo sapevo, vabbè peccato sarebbe stato molto più comodo accedere direttamente con il kernel.
dovrò fare così perfetto grazie mille per l'info

ci sentiamo più avanti (non credere che i problemi siano già finiti :D ) dopo tutto abbiamo iniziato il progetto oggi quindi mi vedrai spesso qui a chiedere consigli.

Bye. e grazie ancora

recoil
22-11-2007, 22:26
non puoi accedere a memoria in user space da kernel
le funzioni copy_to_user e copy_from_user sono fatte apposta :)
quando il processo in user space fa una write sul dispositivo a caratteri viene chiamata la funzione che tu hai specificato nella struttura fops per rispondere ad una scrittura
lì metti la copy_from_user per prendere i dati che l'utente ha scritto

ilsensine
23-11-2007, 09:59
ah, ho capito.. non lo sapevo, vabbè peccato sarebbe stato molto più comodo accedere direttamente con il kernel.
Sempre "con il kernel" accedi (intendevi: dal kernel thread forse?)

Puoi spiegare esattamente cosa devi fare? Forse la soluzione è banale, a che ti serve un kernel thread?

Dawidh
23-11-2007, 11:25
Si si, intendevo kernel thread, ho dimenticato una parola. :p sorry.

praticamente i kthread devono ciclicamente attendere -sul device chiamato controllo- delle richieste (che verranno fatte da spazio utente sullo stesso device). le richieste contengono una parola, un tempo e una priorità, il kthread deve solo prendere la parola e stamparla con una printk una volta al secondo per un tempo t.
Se non ci sono kthread disponibili (perchè tutti stanno stampando)metto le richieste in una coda in attesa che un kthread finisca di servire una richiesta e prenda quella in coda.

Però è un progetto per scuola quindi devo proprio svilupparlo così, con i kthread. non è che ho altre scelte.

Tu come mi consiglieresti di procedere? Faccio un buffer intermedio e i kthread prendono le richieste da lì?
Perchè il mio dubbio è la .read della struttura fops non ho modo di chiamarla io diciamo manualmente con una cat per poi passare i dati al kthread. ma qunado faccio la .write questa mi sblocca un kthread (in attesa su una completion) e quindi non so come prendere i dati della .write
Consigli? grazie.
Spero di essermi spiegato decentemente altrimenti ti posso postare i pezzi di codice.

ilsensine
23-11-2007, 13:47
Abbastanza semplice sembra; non devi però usare il completion, ma una waitqueue.

ilsensine
23-11-2007, 14:08
Perchè il mio dubbio è la .read della struttura fops non ho modo di chiamarla io diciamo manualmente con una cat per poi passare i dati al kthread. ma qunado faccio la .write questa mi sblocca un kthread (in attesa su una completion) e quindi non so come prendere i dati della .write
Avevo scritto male io, intendevo la write non la read.

Dawidh
23-11-2007, 14:39
ok capito.....allora procedo con le waitqueue.
Grazie mille per i consigli.

Dawidh
26-11-2007, 10:21
Ciao, avrei un'altra domandina riguardo il programma descritto sopra.ù

Allora, io ho fatto il mio kthread che prende i dati da un buffer riempito dalla write, adesso però dovrei implementare anche una specie di log per il kthread, cioè ad esempio quando il kthread parte e si ferma sulla waitqueue io dovrei loggare l'evento "il thread è in attesa di richieste e blablabla" scrivendo su un altro device creato appositamente (che poi potrà venire letto con una cat /dev/logging).

Posso scrivere dal kthread direttamente sul device? se si come potrei fare e i dati scritti posso visualizzarli tranquillamente con una cat?

Grazie e ciao.

ilsensine
26-11-2007, 12:36
Posso scrivere dal kthread direttamente sul device?
Non ha senso questa affermazione. Il tuo driver _è_ il device. Potresti (duale della precedente) riempire un buffer dal thread e passarlo in userspace dalla read.

Però non reinventarti la ruota, esistono tanti metodi per il logging. Uno già lo conosci (printk), ma ci sono anche debugfs/netlink/sysfs/connector ecc.

Nel tuo caso vedo bene il connector, non un device node.

Dawidh
03-12-2007, 07:33
EDIT: Scusate sono veramente fuso!! ho già risolto il problema.
printk("%s",logging);
Non so perché ma c'era questo comando!! probabilmente per debug. vabbè........



Di nuovo ciao a tutti.
Intanto grazie per i vostri consigli, abbiamo quasi finito il progetto.

Nel tuo caso vedo bene il connector, non un device node.
Purtroppo dovevo per forza usare un chardevice per fare il logging, è una richiesta del progetto da parte del professore.

Ora, ho un ultimo problemino. Non sono proprio pratico dei device e non capisco perché nel progetto quando vado a fare una lettura sul device "log" tutto ok però quando faccio una scrittura sul device "controllo" mi viene anche fatta una lettura su quello di "log", il che è abbastanza seccante perché l'utente dovrebbe decidere lui quando fare una lettura del log e non che mi venga stampata ogni volta che faccio una scrittura (tra l'altro su un altro device!!)
Sono abbastanza sicuro che il problema sta in conflitti che forse creo durante le open dei device. Cmq vi posto il codice perché proprio non riesco a venirne a capo.
Grazie infinite. Ciao.


#include <linux/poll.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/list.h>
#include <linux/string.h>
#include <linux/delay.h>


#include "ex_thread.h"
#include "ex_dev.h"

int nthread = 1;
int coda = 1;
int num = 0;

static struct miscdevice log_out_device;
static struct miscdevice controllo_out_device;
static int my_len;
char logging[2048] = "";

struct node blist;
struct node* iter;


int list_full()
{
return (num == coda);
}

int list_vuota()
{
return (num == 0);
}

int list_insert(struct node *n)
{
while(list_full()) {
mutex_unlock(&buff_m);
strcat(logging, "La coda e' piena! richiesta in attesa.\n");
wait_for_completion(&coda_piena);
mutex_lock(&buff_m);
}

if(list_vuota()) {
num++;
list_add(&n->list, &(blist.list));
strcat(logging, "Una richiesta e' stata inserita in coda\n");
return 1;
}


struct node *tmp = NULL;
num++;
struct list_head* l;

list_for_each(l, &blist.list){
tmp = list_entry(l, struct node, list);
if(tmp->p < n->p) {
list_add_tail(&n->list, &tmp->list);
strcat(logging, "Una richiesta e' stata inserita in coda\n");
return 1;
}
}
list_add(&n->list, &tmp->list);
strcat(logging, "Una richiesta e' stata inserita in coda\n");
return 1;
}


static int log_open(struct inode *inode, struct file *file)
{
int *cont;

cont = kmalloc(sizeof(int), GFP_USER);
if (cont == NULL) {
return -1;
}

*cont = 0;
file->private_data = cont;

return 0;
}


static int controllo_close(struct inode *inode, struct file *file)
{
return 0;
}
static int log_close(struct inode *inode, struct file *file)
{
return 0;
}
ssize_t log_read(struct file *file, char __user *p, size_t len, loff_t *ppos)
{
int err, res;
int *cont;

cont = file->private_data;

if (*cont == 1) {
return 0;
}

err = copy_to_user(p, logging, 2048);
if (err)
return -EFAULT;

*cont = 1;
return 2048;
}

ssize_t controllo_write(struct file *file, const char __user * buf, size_t count, loff_t *ppos)
{

int err;
printk("%s",logging);
mutex_lock(&buff_m);
if (my_pointer) {
mutex_unlock(&buff_m);
return -1;
}
my_pointer = kmalloc(count, GFP_USER);
if (my_pointer == NULL) {
mutex_unlock(&buff_m);
return -1;
}
my_len = count;

err = copy_from_user(my_pointer, buf, count);
if (err) {
mutex_unlock(&buff_m);
return -EFAULT;
}

char msg[25];
int t, p;
sscanf(my_pointer, "%s %d %d", msg, &t, &p);


struct node* tmp;
tmp = (struct node*)kmalloc(sizeof(struct node), GFP_USER);
if(!tmp) {
return(-1);
}
strcpy(tmp->msg, msg);
tmp->t = t;
tmp->p = p;

list_insert(tmp);
my_pointer = NULL;

wake_up_interruptible(&my_waitqueue);
mutex_unlock(&buff_m);

return count;

}



int device_create(void)
{
misc_register(&controllo_out_device);
return misc_register(&log_out_device);
}

void device_destroy(void)
{
misc_register(&log_out_device);
}

static struct file_operations log_fops = {
.owner = THIS_MODULE,
.read = log_read,
.open = log_open,
.release = log_close,
};

static struct miscdevice log_out_device = {
MISC_DYNAMIC_MINOR, "log", &log_fops
};

static struct file_operations controllo_fops = {
.owner = THIS_MODULE,
// .open = controllo_open,
.release = controllo_close,
.write = controllo_write,
};

static struct miscdevice controllo_out_device = {
MISC_DYNAMIC_MINOR, "controllo", &controllo_fops
};

module_param(nthread, int, 0000);
MODULE_PARM_DESC(nthread, "numero dei thread");
module_param(coda, int, 0000);
MODULE_PARM_DESC(coda, "grandezza della coda");

ilsensine
03-12-2007, 09:34
Ora sono un pò occupato, appena posso do una occhiata. Se intanto puoi allegare i sorgenti completi, lì sembra che manchi qualcosa...

Dawidh
03-12-2007, 10:18
No no, tranquillo... non serve più, ho messo anche l'edit in rosso perché non mi ero proprio accorto che avevo messo una printk di troppo che stampava il buffer contenente il log. :p
grazie per l'interessamento cmq, adesso il programmino funziona benone.
Ciao.

ilsensine
03-12-2007, 12:10
Ok, credevo ci tenevate a farlo "bene" :p

(almeno, correggete il macroscopico bug nella log_read prima che il prof vi uccide ;) poi c'è il memleak nella log_close, la device_destroy sballata, il sospetto memleak di my_pointer ecc.)

Dawidh
03-12-2007, 19:37
bug, c'è un bug nella read? eppure è proprio come quella che ha fatto il prof negli esempi mi sembra strano.l'abbiamo solo adattata alle nostre esigenze ma è come l'ha fatta lui, cosa c'è che non va?non riesco proprio a vederlo

cmq l'esercizio di per se era un esercizio di sincronizzazione, gestire bene mutex, wait e quelle cose lì......linked list con priorità, bloccaggio client se la list è piena... etc... (ci ha addirittura detto che è lo stesso se togliendo il modulo crasha tutto... quindi immagina :rolleyes: )

oggi abbaimo messo tutto un pò a posto, anche i memleak.... quello che ho postato era ancora solo un abbozzo non il definitivo....

ilsensine
03-12-2007, 19:52
bug, c'è un bug nella read? eppure è proprio come quella che ha fatto il prof negli esempi mi sembra strano.l'abbiamo solo adattata alle nostre esigenze ma è come l'ha fatta lui, cosa c'è che non va?non riesco proprio a vederlo
char buf[512];
int fd = open("/dev/log", O_RDONLY);
read(fd, buf, sizeof(buf)); // kabum
application buffer overflow