スレッドを持つモジュールをアンロードしたい。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);