|
|
ru.unix.bsd- RU.UNIX.BSD ------------------------------------------------------------------ From : Igor A. Valcov 2:5020/400 27 Jan 2005 21:56:55 To : Gleb Smirnoff Subject : Re: FreeBSD module programming & panic -------------------------------------------------------------------------------- Спасибо большое. Разобрался. Теперь работает. Gleb Smirnoff wrote: > IAV> Изучил множество драйверов из sys/dev. Вроде нигде криминально не > IAV> ошибся. Всё так. А вот почему такое происходит, никак н пойму. > > Если бы ядро было собрано с INVARIANTS, то оно спаниковало бы еще на load, вот > так: "sleeping without a mutex". То есть msleep() используется не правильно. Значит, в данном случае tsleep использовать надо? Если mutex'а нету и надобности в блокировках нету. > IAV> И ещё вопрос. Я так понял, что функция, которую выполняет kthread не > IAV> диспетчеризируется, то есть пока она работает и не вызывается никаких > IAV> tsleep и ему подобных, sheduler не передаст управление никакому другому > IAV> процессу (на UP системе). Поскольку если там вставить бесконечный цикл, > IAV> то всё виснет намертво. > > Так и есть. Возможно он передаст его, если ядро собрано с PREEMPTION (или даже > FULL_PREEMPTION). Hо это всё равно ошибка. Hельзя делать бесконечных циклов > в нижней части ядра. Да я понял, что нельзя. Это я просто с исследовательской целью. Посмотреть как оно будет работать. Чтобы яснее представить себе картину, как это работает. > IAV> for (; kpcl_thread_exit != 1;) { > IAV> for (i = 0; i < 10; i++) > IAV> printf ("KPCL_THREAD CALLED\n"); > > IAV> msleep (&kpcl_fifo, NULL, PRIBIO, "kpcl_wait", 0); > IAV> } > > Зачем обвязка for (i = 0; i < 10; i++)? Ведь wakeup() посылается только один > раз, а msleep() делается 10 раз. Да это всё тестовое. Чтоб не одно сообщение а десять писало. Чтоб видно было, что запустился :) > IAV> MALLOC (kpcl_fifo, kpcl_fifo_t*, sizeof(kpcl_fifo_t), > IAV> M_KPCL_FIFO, M_ZERO | M_WAITOK); > > Проверить kpcl_fifo != NULL. > Оказывается, дело было в том, что модуль выгружался до того, как будет завершён kthread. Хотя и вызывается при выходе wakeup, но управление kthread не передаётся вплоть до того, пока не завершится функция kpcl_loader () и, соответственно, не выгружен модуль. А как передастся управление - то страниц памяти где он был уже нет. Вот и page fault. Если я всё правильно понял. Вот работающий вариант. #include <sys/types.h> #include <sys/module.h> #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ #include <sys/conf.h> /* cdevsw struct */ #include <sys/uio.h> /* uio struct */ #include <sys/malloc.h> #include <sys/kthread.h> #include <sys/priority.h> #define KPCL_FIFO_SIZE 4096 int kpcl_open(dev_t dev, int oflags, int devtype, struct proc *p); int kpcl_close(dev_t dev, int fflag, int devtype, struct proc *p); static struct cdevsw kpcl_cdevsw = { .d_open = kpcl_open, .d_close = kpcl_close, .d_name = "kpcl", .d_maj = 0, .d_version = D_VERSION, .d_flags = D_NEEDGIANT }; typedef struct __kpcl_fifo { char msg[KPCL_FIFO_SIZE]; int kf_beg; int kf_end; } kpcl_fifo_t; static dev_t sdev; static kpcl_fifo_t *kpcl_fifo; MALLOC_DECLARE(M_KPCL_FIFO); MALLOC_DEFINE(M_KPCL_FIFO, "fifobuffer", "FIFO buffer for KPCL"); static int kpcl_thread_exit = 0; static void kpcl_thread (void *arg) { int i; for (; kpcl_thread_exit != 1;) { printf ("KPCL_THREAD CALLED\n"); msleep (&kpcl_fifo, NULL, PWAIT, "kpcl_wait", 0); } wakeup (&kpcl_thread_exit); kthread_exit (0); } static int kpcl_loader(struct module *m, int what, void *arg) { int err = 0; switch (what) { case MOD_LOAD: sdev = make_dev (&kpcl_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "kpcl"); MALLOC (kpcl_fifo, kpcl_fifo_t*, sizeof(kpcl_fifo_t), M_KPCL_FIFO, M_ZERO | M_WAITOK); kthread_create (kpcl_thread, NULL, NULL, 0, 0, "kpcl0"); printf ("KPCL successfully loaded.\n"); break; case MOD_UNLOAD: kpcl_thread_exit = 1; wakeup (&kpcl_fifo); printf ("KPCL: waiting fot kthread terminate\n"); msleep (&kpcl_thread_exit, NULL, PWAIT, "kpcl_thread_exit_wait", 0); printf ("KPCL: kthread terminating. Destroy the device\n"); destroy_dev (sdev); FREE (kpcl_fifo, M_KPCL_FIFO); printf("KPCL unloaded.\n"); break; default: err = EINVAL; break; } return (err); } int kpcl_open (dev_t dev, int oflags, int devtype, struct proc *p) { int err = 0; wakeup (&kpcl_fifo); printf ("Opened device \"KPCL\" successfully.\n"); return (err); } int kpcl_close (dev_t dev, int fflag, int devtype, struct proc *p) { printf ("Closing device \"KPCL.\"\n"); return (0); } /* int kpcl_read (dev_t dev, struct uio *uio, int ioflag) { int err = 0; int amt; amt = MIN (uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); if ((err = uiomove (echomsg->msg + uio->uio_offset, amt, uio)) != 0) { uprintf ("uiomove failed!\n"); } return err; } int kpcl_write (dev_t dev, struct uio *uio, int ioflag) { int err = 0; err = copyin (uio->uio_iov->iov_base, echomsg->msg, MIN (uio->uio_iov->iov_len, BUFFERSIZE)); *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); if (err != 0) { uprintf("Write failed: bad address!\n"); } count++; return(err); } */ DEV_MODULE (kpcl, kpcl_loader, NULL); Ещё, стало мне интересно насчёт аргумента ident в tsleep, msleep, wakeup и подобных им функциях. tsleep(void *ident, int priority, const char *wmesg, int timo); В Linux используются очереди ожидания для таких целей. А тут, как я понял, можно использовать любой указатель, главное чтобы в вызовах *sleep, wakeup он был одинаковый. Или неправильно я понял? Спасибо огромное, за внимание к проблеме. С уважением. Игорь. --- ifmail v.2.15dev5.3 * Origin: CenterTelecom Voronezh ISP (2:5020/400) Вернуться к списку тем, сортированных по: возрастание даты уменьшение даты тема автор
Архивное /ru.unix.bsd/631162eed460.html, оценка из 5, голосов 10
|