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 に答える