2015-07-30 13 views
5

EDIT: I think Ho risolto il problema. Aggiungerò la mia risposta/soluzione non appena sarò di nuovo al lavoro domani.C - Kernel Linux: la chiusura di due kthread blocca la macchina


Sto lavorando su un modulo del kernel per il kernel Linux 3.16.x. Il mio modulo dovrebbe ricevere e inviare frame ethernet, quindi ho creato due thread. Uno per la parte di ricezione, uno per la parte di trasmissione. Funziona bene.

Il mio problema appare quando provo a chiudere il file del dispositivo del modulo e lo scarico. Per essere precisi, succede quando cerchi di uccidere i miei thread. La macchina (sto testando su una macchina virtuale, con Ubuntu 14.04) si blocca prima che ci sia un qualunque output. Tuttavia, quando rimuovo il "thread killing part" dal codice, non si congela più. Questo è il motivo per cui sono abbastanza certo, il problema deriva dal modo in cui gestisco l'uccisione dei kthread.

Qui sono i miei due thread:

TX Discussione: tx_sem semaforo è up'ed in un'altra parte del codice.

static int tx_task(void *par) 
{ 
    device->tx_task_running = 1; 

    allow_signal(SIGTERM); 
    while (!signal_pending(current) && device->tx_task_running) { 
     /* wait until there is something to send */ 
     down_interruptible(&device->tx_sem); 

     if (signal_pending(current)) { 
      PRINTD("device_TX_task(): Received kill signal\n"); 
      break; 
     } 

     /* check if device is still initialized before continuing*/ 
     if (!device->init_flag) { 
      break; 
     } 
    } 
    device->tx_task_running = 0; 
    return DEVICE_RET_OK; 
} 

RX FILO

static int device_rx_task(void *par) 
{ 
    device->rx_task_running = 1; 

    /* task loop */ 
    allow_signal(SIGTERM); 
    while (!signal_pending(current) && device->rx_task_running) { 
     rxlen = kernel_recvmsg(device->sock, &msg, 
      (struct kvec *)&iov, 1, DEVICE_PAY_SIZE, 0); 

     if (signal_pending(current)) { 
      PRINTD("device_rx_task(): Received kill signal\n"); 
      break; 
     } 

     if(rxlen < 0) { 
      PRINTD("device_RX_task(): Got error when receiving\n"); 
      break; 
     } 

     /* check if device is still initialized before continuing*/ 
     if (!device->init_flag) { 
      break; 
     } 
    } 
    device->rx_task_running = 0; 
    return DEVICE_RET_OK; 
} 

Questi ragazzi correre fino a quando provo a chiudere il mio dispositivo. Quando si chiude il modulo del kernel, questa funzione viene chiamata e questo è quando si blocca. Ad esempio, se commento le funzioni "send_sig", non si blocca. Si blocca anche quando provo ad uccidere manualmente i fili:

int Device_DevTerm(int dev) 
{ 
    device->init_flag = 0; 

    send_sig(SIGTERM, device->rx_thread, 0); 
    send_sig(SIGTERM, device->tx_thread, 0); 
    device->rx_task_running = 0; 
    device->tx_task_running = 0; 

    return DEVICE_RET_OK; 
} 

Googled e cercato per lungo tempo al fine di trovare il problema, ma finora non ha avuto successo. Dato che ho già trascorso molto tempo per questo problema, ho deciso di chiederti ragazzi.

Cosa sto facendo di sbagliato qui?

p.s. Non penso di aver mai postato qui, ho solo letto molto. Spero che la mia domanda sia chiara e concisa. Probabilmente no.

+1

Se si verifica un arresto anomalo, inviare la traccia dello stack. Se intendevi bloccare, usa SysRq per trovare l'operazione bloccata. – stark

+0

Purtroppo mi sembra di non essere in grado di farlo. Quando guardo in/var/log/syslog/non c'è nulla riguardo al blocco. Immagino che si sia bloccato prima che si verificasse qualsiasi output. Quando provo SysRq (che non sapevo prima) non succede niente, rimane bloccato. Forse il fatto che sia una macchina virtuale non aiuta, non sono sicuro. Continuerò a cercare di raccogliere qualsiasi informazione utile, ma fino ad ora non sono in grado di farlo. –

risposta

0

Quindi, sembra di aver trovato il mio problema.

Quando si imposta la msghdr per la funzione kernel_recvmsg(), ho usato per fare in questo modo:

struct sockaddr_in client; 

MEM_SET(&client, 0x00, sizeof(struct sockaddr_in)); 

/* setup receive parameter */ 
msg.msg_name = &client; 
msg.msg_namelen = sizeof(struct sockaddr_in); 
msg.msg_control = NULL; 
msg.msg_controllen = 0; 
msg.msg_iov = &iov; 
msg.msg_iovlen = 1; 

Ora ho cambiato la routine per:

struct sockaddr_in client[3]; 

MEM_SET(&client[0], 0x00, 3 *sizeof(struct sockaddr_in)); 

/* setup receive parameter */ 
msg.msg_name = &client[1]; 
msg.msg_namelen = sizeof(struct sockaddr_in); 
msg.msg_control = NULL; 
msg.msg_controllen = 0; 
msg.msg_iov = &iov; 
msg.msg_iovlen = 1; 

Con questo non lo fa crash più. Poi ho trovato il seguente commento nella nostra base di codice:

/* 
* NOTE: 
* use three times the size of struct sockaddr_in as workaround 
* for a possible kernel bug which has been seen on a Ubuntu 64bit 
* system 
* after the call of kernel_recvmsg 2 bytes behind the structure 
* client had been corrupted on the stack 
*/ 

Non sono sicuro di quanto sia vero e se questo comprende tutto il mio problema, ma sembra per risolvere il problema.