2012-12-16 57 views
1

我想卸載一個有線程的模塊。我曾經引用的開發/隨機碼,和我的代碼是這樣的:如何卸載在FreeBSD中創建kproc/kthread的內核模塊

$ cat tmp.c 

#include <sys/param.h> 
#include <sys/module.h> 
#include <sys/kernel.h> 
#include <sys/systm.h> 
#include <sys/proc.h> 
#include <sys/kthread.h> 

/* 
* $ ps auxH | grep kproc 
*/ 

static int kproc_control = 1; 

#define output_id(p, td, fmt, args...)         \ 
     printf("%s[%d]:%s[%d]:[%s] %s\n", p->p_comm, p->p_pid,   \ 
      td->td_name, td->td_tid, __func__, msg) 

static void thread_routine(void *arg) 
{ 
     char *msg = arg; 
     struct thread *td = curthread; 
     struct proc *p = td->td_proc; 

     output_id(p, td, msg); 
     pause("-", hz * 100); 
     output_id(p, td, msg); 

     kthread_exit(); 
} 

static void proc_routine(void *arg) 
{ 
     char *msg = arg; 
     struct thread *td = curthread; 
     struct proc *p = td->td_proc; 
     struct thread *ntd; 
     int error; 

     output_id(p, td, msg); 

     error = kthread_add(thread_routine, "I'm kthread", p, &ntd, 
      0, 0, "kthread"); 
     if (error) 
       printf("error: %d\n", error); 

     while (kproc_control >= 0) { 
       pause("-", hz/10); 
     } 

     wakeup(&kproc_control); 
     kproc_exit(0); 
} 

static int foobar_init(void) 
{ 
     int error; 
     struct proc *p; 

     error = kproc_create(proc_routine, "I'm kproc", &p, 0, 0, "kproc"); 
     uprintf("error: %d\n", error); 

     return error; 
} 

static void foobar_fini(void) 
{ 
     kproc_control = -1; 
     tsleep(&kproc_control, 0, "term", 0); 
     //pause("delay", 2 * hz); 
} 

static int 
foobar_modevent(module_t mod __unused, int event, void *arg __unused) 
{ 
     int error = 0; 

     switch (event) { 
     case MOD_LOAD: 
       error = foobar_init(); 
       break; 
     case MOD_UNLOAD: 
       foobar_fini(); 
       break; 
     default: 
       error = EOPNOTSUPP; 
       break; 
     } 

     return (error); 
} 

static moduledata_t foobar_mod = { 
     "foobar", 
     foobar_modevent, 
     NULL 
}; 

DECLARE_MODULE(foobar, foobar_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 

當我通過kldunload卸載它,我的內核崩潰,系統重新啓動。什麼是解決這個問題的正確方法?任何意見將不勝感激! ;-)

PS。我可以睡& p-> p_stype嗎?我在exit1()中看到以下代碼:

/* 
    * Note that we are exiting and do another wakeup of anyone in 
    * PIOCWAIT in case they aren't listening for S_EXIT stops or 
    * decided to wait again after we told them we are exiting. 
    */ 
    p->p_flag |= P_WEXIT; 
    wakeup(&p->p_stype); 

PS。更新代碼:

#include <sys/param.h> 
#include <sys/module.h> 
#include <sys/kernel.h> 
#include <sys/systm.h> 
#include <sys/proc.h> 
#include <sys/kthread.h> 
#include <sys/lock.h> 
#include <sys/mutex.h> 

/* 
* $ ps auxH | grep kproc 
*/ 

static int kproc_control = 1; 
static struct proc *foobar_proc; 
static struct mtx mtx; 

#define output_id(p, td, fmt, args...)         \ 
     printf("%s[%d]:%s[%d]:[%s] %s\n", p->p_comm, p->p_pid,   \ 
      td->td_name, td->td_tid, __func__, msg) 

static void thread_routine(void *arg) 
{ 
     char *msg = arg; 
     struct thread *td = curthread; 
     struct proc *p = td->td_proc; 

     output_id(p, td, msg); 
     pause("-", hz * 100); 
     output_id(p, td, msg); 

     kthread_exit(); 
} 

static void proc_routine(void *arg) 
{ 
     char *msg = arg; 
     struct thread *td = curthread; 
     struct proc *p = td->td_proc; 
     struct thread *ntd; 
     int error; 

     output_id(p, td, msg); 

     error = kthread_add(thread_routine, "I'm kthread", p, &ntd, 
      0, 0, "kthread"); 
     if (error) 
       printf("error: %d\n", error); 

     mtx_lock(&mtx); 
     while (kproc_control >= 0) { 
       mtx_unlock(&mtx); 
       pause("-", hz/10); 
       mtx_lock(&mtx); 
     } 
     mtx_unlock(&mtx); 
     kproc_exit(0); 
} 
static int foobar_init(void) 
{ 
     int error; 

     mtx_init(&mtx, "foobar_mtx", NULL, MTX_DEF); 
     error = kproc_create(proc_routine, "I'm kproc", &foobar_proc, 0, 0, "kproc"); 
     uprintf("error: %d\n", error); 

     return error; 
} 

static void foobar_fini(void) 
{ 
     mtx_lock(&mtx); 
     kproc_control = -1; 
     //mtx_sleep(foobar_proc, &mtx, 0, "waiting", 0); 
     mtx_sleep(&foobar_proc->p_stype, &mtx, 0, "waiting", 0); 
} 

static int 
foobar_modevent(module_t mod __unused, int event, void *arg __unused) 
{ 
     int error = 0; 

     switch (event) { 
     case MOD_LOAD: 
       error = foobar_init(); 
       break; 
     case MOD_UNLOAD: 
       foobar_fini(); 
       break; 
     default: 
       error = EOPNOTSUPP; 
       break; 
     } 

     return (error); 
} 

static moduledata_t foobar_mod = { 
     "foobar", 
     foobar_modevent, 
     NULL 
}; 

DECLARE_MODULE(foobar, foobar_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); 

回答

1

原則上,您等待線程或proc句柄以確保它已退出。

您應該使用某種鎖來同步對共享變量的訪問,如kproc_control標誌。您也可以使用mtx_sleep以原子方式釋放鎖並等待proc句柄,以避免處理終止事件時的競爭條件。

我使用的模型看起來是這樣的:

void proc(whatver) 
{ 
    mtx_lock(&sc->m_lock); 

    while (!sc->time_to_die) { 
     mtx_unlock(&sc->m_lock); 
     /* Do whatever */ 
     mtx_lock(&sc->m_lock); 
    } 

    mtx_unlock(&sc->m_lock); 

    kproc_exit(0); 
} 

void detach(whatever) 
{ 
    mtx_lock(&sc->m_lock); 
    sc->time_to_die = 1; 
    mtx_sleep(sc->m_proc, &sc->m_lock, 0, "waiting", 0); 
    /* proc cleaned up, safe to continue */ 
} 
+0

非常感謝您的寶貴意見。但我認爲睡在&sc-> m_proc-> p_stype上會更好。由於'wakeup(sc-> m_proc)'是在任何其他線程退出之前在kproc_exit()中執行的,而其他線程退出時會在exit1()中執行'wakeup(&sc-> m_proc-> p_stype)'。我試着睡在sc-> m_proc上(實際上mtx_sleep(foobar_proc,&mtx,0,「waiting」,0);),但是內核再次崩潰。也許這是由於在thread_routine()中'暫停(「 - 」,hz * 100)'。但是,如果我使用mtx_sleep(&foobar_proc-> p_stype,&mtx,0,「waiting」,0),則內核仍然崩潰。 ;-( – user1907234

+0

是否需要在'void proc(whatver){}'中'kproc_exit(0);'之前添加'mtx_unlock(&sc-> m_lock);' – user1907234

+0

你需要等待你開始的所有事情。在你的情況下,我認爲你叫kthread_add()和kproc_create()。你應該等待這兩個退出。我沒有詳細通過你的其他代碼,但你依賴於定時器,而不是有一個正確的同步機制。 – janm