Главная страница


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)
 
 

Вернуться к списку тем, сортированных по: возрастание даты  уменьшение даты  тема  автор 

 Тема:    Автор:    Дата:  
 FreeBSD module programming & panic   Igor A. Valcov   27 Jan 2005 01:57:37 
 Re: FreeBSD module programming & panic   Gleb Smirnoff   27 Jan 2005 12:24:41 
 Re: FreeBSD module programming & panic   Igor A. Valcov   27 Jan 2005 21:56:55 
Архивное /ru.unix.bsd/631162eed460.html, оценка 3 из 5, голосов 10
Яндекс.Метрика
Valid HTML 4.01 Transitional