1

我想卸载一个有线程的模块。我已经引用了dev/random中的代码,我的代码是这样的:

$ 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);
4

1 回答 1

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 */
}
于 2012-12-16T04:07:59.853 回答