LINUX.ORG.RU

strange Linux scheduler


0

0

Здравствуйте!

Пишу модуль ядра для Linux и столкнулся с одной непонятностью...

после загрузки в ядро модуль создает два файла устройств, один - для чтения, другой - для записи. Оба фала связаны логически с одним буфером в модуле. Устройство "виртуальное", типа PIPE'a.

логика такая: 1) программа - ридер открывает 1й файл и пытается читать из него. Тк данных нет в буфере, она блокируется (sleep_on). 2) программа - писатель открывает 2й файл и пишет туда (в буфер) строку. Тк буфер чист, она не блокируется и по завершении делает wake_up для ридера (чтоб он проснулся и получил данные).

НО! ридер не просыпается. он так и остается в спящем виде до получения прерываения с клавы (Ctrl+C).

Выдержка из кода:

static ssize_t vsp_read( struct file *_file, char *_buff, size_t _len, loff_t *_off) { /// ... if ( !(VSP_NONBLOCK( _file))) if ( dev->buff_len < 1) interruptible_sleep_on( &( dev->wqr)); // .. skipped wake_up_interruptible( &dev->wqw); // ... return( readed); } // read end

static ssize_t vsp_write( struct file *_file, const char *_buff, size_t _len, loff_t *_off) { /// ... if ( !(VSP_NONBLOCK( _file))) if ( dev->buff_len >= VSP_MAXBUF - 1) interruptible_sleep_on( &( dev->wqw)); // .. skipped wake_up_interruptible( &dev->wqr); // ... return( wrote); } // write end

dev имеет примерно следующую структуру: struct VSP_DEVICE { char buff[ VSP_MAXBUF]; unsigned short buff_len; wait_queue_head_t wqr, wqw; };

все wait_queue_head_t инициализируются на этапе регистрации девайсов

* я заглядывал в очереди wait_queue_head_t на состояние процессов до и после вызова wake_up_interruptible, выяснил, что состояние будимого процесса не меняется. Тоесть, как было 1 (INTERRUPTIBLE), так и осталось. Самое странное... Если непосредственно до вызова wake_up_interruptible сделать printk(""); с любой строкой в качестве параметра, хоть "\0", после wake_up_interruptible состояние читающего процесса меняется, он просыпается и успешно завершается, возврашая прочитанные данные.

Пытался делать wake_up_sync, wake_up_all и тд... ниче не помогает. Кто знает где грабли?

gcc 2.96, kernel 2.4.18-6mdk

WBR, Dvorkin


A что не нравится?

ИМХО все правильно - процесс у тебя спит и просыпается только после получения прерывания с клавиатуры, а wake_up происходит после того, как процесс уже проснулся. Если ты хочешь будить его из драйвера , то wake_up_interruptible должен вызываться из другой процедуры - скажем из обработчика poll, или из таймера, или из обработчика прерывания(где ты предварительно проверяешь поступили данные или нет)

geekkoo
()

хм. но процесс, заснувший на vsp_read я пытаюсь будить из vsp_write, тоесть из другой процедуры. Я наверно туплю, но не понял в чем фишка...

WBR, Dvorkin

Dvorkin
() автор топика

Чудес на свете не бывает. wake_up -- если его вызвали -- должен
изменить состояние процесса.
Глядя на выдержку из кода, я заметил, что Вы не любите рисовать
"лишних" фигурных скобок. То, что бессмысленный printk меняет логику
исполнения наводит на мысли, верно? Убедитесь, пожалуйста, что
wake_up действительно вызывается.

vnp
()

Strange...

Да нет - это я туплю :)...
Действительно все правильно, но по всей видимости вся загвоздка в том коде, что у тебя поскипан. По-моему ситуация может быть такой - процесс просыпается, но по каким-то причинам буфер еще не обновился - он пытается прочитать его снова, видит длину <1 и снова засыпает, после чего буфер уже успешно обновляется. Понятно почему printk в этой ситуации помогает - буфер у тебя успевает обновиться за время выполнения printk

geekkoo
()

а че ты собсно не разруливаешь доступ к этому dev у тебя
ведь не атомарные операции над ним?

помоему было бы надежнее делать типа

read:
/*
 * TODO:
 *   o поднять семафор доступа к buff
 *   o проверить длину       | critical section
 *   o считать из бефера     | critical section
 *   o опустить семафор
 */

write:
/*
 * TODO:
 *   o поднять семафор доступа к buff
 *   o записать в буффер      | critical section
 *   o изменить длину буфера  | critical section
 *   o опустить семафор
 */

я не знаю специфику линукса, но обычно так делается ..

lg ★★
()

Вот чувак правильно сказал, а кто будет лочить dev перед тем как получить сайз из него? Пушкин?

Banshee
()

лочить - не лочить баг не исчезает.

WBR, Dvorkin

Dvorkin
() автор топика

Да нету никакого бага,,,

...разбирайся в том что у тебя поскипано. Вот модуль

#ifndef MODULE #define MODULE #endif #ifndef __KERNEL__ #define __KERNEL__ #endif

#ifndef EXPORT_SYMTAB # define EXPORT_SYMTAB #endif

#include <linux/module.h> #include <linux/kernel.h> #include <asm/system.h> #include <linux/fs.h> #include <linux/tqueue.h> #include <linux/config.h> #include <linux/types.h> #include <linux/poll.h> #include <linux/ioport.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/semaphore.h>

int chj_major = 251;

MODULE_PARM(chj_major, "i");

char hold[1024]; int buff_len; wait_queue_head_t wqr, wqw; struct semaphore lock;

static ssize_t vsp_read( struct file *_file, char *_buff, size_t _len, loff_t *_off) { int i; if ( buff_len < 1) interruptible_sleep_on( &(wqr)); wake_up_interruptible( &wqw); down_interruptible(&lock); for (i=0;i<buff_len;i++){ hold[i]+=1; }; copy_to_user(_buff,hold,buff_len); buff_len=0; up(&lock); return i; }

static ssize_t vsp_write( struct file *_file, const char *_buff, size_t _len, loff_t *_off) { if ( buff_len >= 1024) interruptible_sleep_on( &(wqw)); down_interruptible(&lock); copy_from_user(hold,_buff,_len); buff_len+=_len; up(&lock); wake_up_interruptible( &wqr); return _len; } struct file_operations _fops={ read:vsp_read, write:vsp_write, } ;

int init_module() { int i,result = register_chrdev(chj_major,"Test",&_fops); void * z; if (result <0){ printk("<3>Can not gt major %d \n",chj_major); return result; } sema_init(&lock,1); init_waitqueue_head (&wqr); init_waitqueue_head (&wqw); return 0; }

void cleanup_module(void) { unregister_chrdev(chj_major,"Test"); }

mknod /dev/testscull c 251 1 cat /dev/testscull echo "1111" > /dev/testscull

у меня работает не лочится (ядро 2.4.18 стандартное из Слаквари)

geekkoo
()

Да нету никакого бага,,,

#ifndef MODULE
#define MODULE
#endif
#ifndef __KERNEL__
#define __KERNEL__
#endif

#ifndef EXPORT_SYMTAB
# define EXPORT_SYMTAB
#endif


#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/system.h>
#include <linux/fs.h>
#include <linux/tqueue.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/poll.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>

int chj_major = 251;

MODULE_PARM(chj_major, "i");


char hold[1024];
int buff_len;
wait_queue_head_t wqr, wqw;
struct semaphore lock;

static ssize_t vsp_read( struct file *_file, char *_buff, size_t _len, loff_t *_off) {
int i;
if ( buff_len < 1) interruptible_sleep_on( &(wqr));
wake_up_interruptible( &wqw);
down_interruptible(&lock);
for (i=0;i<buff_len;i++){
hold[i]+=1;
};
copy_to_user(_buff,hold,buff_len);
buff_len=0;
up(&lock);
return i;
}

static ssize_t vsp_write( struct file *_file, const char *_buff, size_t _len, loff_t *_off) {
if ( buff_len >= 1024)
interruptible_sleep_on( &(wqw));
down_interruptible(&lock);
copy_from_user(hold,_buff,_len);
buff_len+=_len;
up(&lock);
wake_up_interruptible( &wqr);
return _len;
}
struct file_operations _fops={
read:vsp_read,
write:vsp_write,
} ;


int init_module()
{
int i,result = register_chrdev(chj_major,"Test",&_fops);
void * z;
if (result <0){
printk("<3>Can not gt major %d \n",chj_major);
return result;
}
sema_init(&lock,1);
init_waitqueue_head (&wqr);
init_waitqueue_head (&wqw);
return 0;
}

void cleanup_module(void)
{
unregister_chrdev(chj_major,"Test");
}

geekkoo
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.