LINUX.ORG.RU

linux driver: wake_up_interruptible


0

1

Есть драйвер для некоего устройства, через ioctl запрос процессу нужно ждать внешнее событие, которое генерирует аппаратное прерывание на устройстве.
В коде запроса я использую wait_event_interruptible_timeout(), передавая туда объект очереди ожидания и условие, в тасклете вызываю wake_up_interruptible() с тем же объектом очереди ожидания. В обработчике прерывания условие становится истинным, и вызывается тасклет. Используя printk, в системном логе я вижу, что выполняется обработчик прерывания и тасклет, но процесс просыпается только по истечении таймаута, независимо от того было прерывание или нет!
В чём может быть проблема?
Приведу код запроса, обработчика и тасклета.

Ioctl запрос:

  
int wait_event(struct *dev, ...)
{
  struct dev_priv *dp = dev->private;
  ...
  spin_lock_irqsave(dp->lock, flags);
  dp->flag = 1;
  spin_unlock_irqrestore(dp->lock, flags);
  wait_event_interruptible_timeout(dp->queue, (flag == 0), timeout);
  spin_lock_irqsave(dp->lock, flags);
  dp->flag = 0;   // явно очищаю флаг, если таймаут истёк
  spin_unlock_irqrestore(dp->lock, flags);
  ...
}


Обработчик прерывания:
irq_return_t dev_isr(void *dev_id, ...)
{
  struct device *dev = (struct device*)dev_id;
  struct dev_priv *dp = dev->private;
  int sched_bh = 0; 
  ...
  spin_lock_irqsave(dp->lock, flags);
  if(dp->flag != 0)   // процесс ждёт событие 
  {
    dp->flag = 0;
    sched_bh = 1;
    printk(...);    // сообщение появляется в логе при прерывании
  }
  spin_unlock_irqrestore(dp->lock, flags);
  ...
  if(sched_bh == 1)
    tasklet_schedule(&dev_tasklet);
  return IRQ_HANDLED;
}


Тасклет:
void do_tasklet(ulong param)
{
  struct device* dev = (struct device*)param;
  struct dev_priv *dp = dev->private;
  wake_up_interruptible(&dp->queue);
}

Да, очередь ожидания инициализируется при старте драйвера для каждого устройства.

эта.... я тут совсем нетрезвый, может что не понял

spin_lock_irqsave(dp->lock, flags);

dp->flag = 1;


spin_unlock_irqrestore(dp->lock, flags);


wait_event_interruptible_timeout(dp->queue, (flag == 0), timeout);


^^^^^^^^^
(i assume, dp->flags == 0?)

а теперь предположим, что do_tasklet() вызывается прямо
перед spin_lock_irqsave(). или задолго до.

не?

кстати, использование tasklet_schedule() для простого
wake_up_* выглядит странно.

idle ★★★★★
()

Нахрена тут столько спинлоков ?

в обработчике:

[code] dp->flag++; // <-- u32 wake_up_interruptible(&dp->queue); [/code]

в ioctl запросе:

[code] int wait_event(struct *dev, ...) { struct dev_priv *dp = dev->private; u32 flag = dp->flag; ... wait_event_interruptible_timeout(dp->queue, (flag != dp->flag), timeout); ... } [/code]

anonymous
()
Ответ на: комментарий от anonymous
dp->flag++; // <-- u32
wake_up_interruptible(&dp->queue);

в ioctl запросе:

int wait_event(struct *dev, ...)
{
  struct dev_priv *dp = dev->private;
  u32 flag = dp->flag;
  ...
  wait_event_interruptible_timeout(dp->queue, (flag != dp->flag), timeout);
  ...
}
anonymous
()
Ответ на: комментарий от idle

Я ошибся, конечно, flags - это локальная переменная, в функции wait_event_intrruptible_timeout должно быть условие (dp->flag == 0) c приватной переменной устройства.
Если do_tasklet() вызывается до захвата блокировки ничего не произойдёт - обработчик прерывания выполнится, но dp->flag в этот момент равен 0, поэтому тасклет не выполнится...

linux__user
() автор топика
Ответ на: комментарий от tailgunner

А что выполняется быстрее wake_up_interruptible() или schedule_tasklet(), такслет использую для того чтобы обработчик прерывания выполнился максимально быстро.
А какая разница какой таймаут, ну 10 секунд, например, таймаут задаётся при ioctl запросе.

linux__user
() автор топика
Ответ на: комментарий от linux__user

> А что выполняется быстрее wake_up_interruptible() или schedule_tasklet()

wake_up_interruptible

А какая разница какой таймаут, ну 10 секунд, например, таймаут задаётся при ioctl запросе.

Без «ну например». Я сейчас бодаюсь с проблемой, где у tasklet, workqueue и wake_up задержки по нескольку мс. Если у тебя такие же, тогда ХЗ, что тебе сказать.

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

А как без блокировок, кроме dp->flag есть ещё некоторые приватные данные для каждого устройства, доступ к ним возможен как из обработчика, так и из запроса, поэтому они охраняются блокировками.
Единственное где я погорячился - в обработчие не нужно запрещать прерывания - просто spin_lock()/spin_unlock().
Единственный момент, который меня смущает - момент прихода прерывания после истечения таймаута, но до захвата блокировки (dp->flag в этот момент всё ещё равен 1), тогда по идее вызовется wake_up_interruptible, но очередь ожидания будет уже пуста.

linux__user
() автор топика
Ответ на: комментарий от tailgunner

Дело не в задержке, если в единственном запросе передать 10 секунд и сымитировать единственное прерывание во время ожидания, то процесс получает управление всё-равно по истечении 10 секунд.
Дело видимо в условии (dp->flag == 0) хотя код запроса и прерывания я просматривал уже много раз.
А по-поводу такслета исправлюсь, если это действительно так, я считал что вызов schedule_tasklet() намного быстрее.

linux__user
() автор топика
Ответ на: комментарий от linux__user

> если в единственном запросе передать 10 секунд и сымитировать единственное прерывание во время ожидания, то процесс получает управление всё-равно по истечении 10 секунд.

Да, такое задержками планирования не объяснить %)

я считал что вызов schedule_tasklet() намного быстрее.

Вызов schedule_tasklet вряд ли быстрее, к тому же tasklet выполняется уже после завершения вызова.

tailgunner ★★★★★
()
Ответ на: комментарий от linux__user

А как без блокировок

Я прекрасно понимаю для чего нужны блокировки, поэтому спрашиваю зачем они в данном случае распиханы в каждой строчке кода ? никаких других данных кроме одного флага в вашем коде нет. spin_lock_irqsave в ioctl отключит прерывания на локальном процессоре - оработчик не сработает в это время, зачем в обработчике ставить спинлок - или вы считаете обычный процесс может вытеснить обработчик прерывания ? Если нужно ловить ioctl то можно сделать так:

в ioctl:

int wait_event(struct *dev, ...)
{
  struct dev_priv *dp = dev->private;
  unsigned long flags;

  local_irq_save(flags);  
  dp->flag = 0;
  local_irq_restore();
  ...
  wait_event_interruptible_timeout(dp->queue, (dp->flag), timeout);
  ...
}

в обработчике:

if (!dp->flag) {
  dp->flag++;
  wake_up_interruptible(&dp->queue);
}
anonymous
()
Ответ на: комментарий от anonymous

это racy.

еще раз. представь, что обработчик вызывается прямо
перед тем, как ioctl() делает local_irq_save().

последовательность должна быть прямо противоположной.

idle ★★★★★
()
Ответ на: комментарий от linux__user

> Если do_tasklet() вызывается до захвата блокировки

ничего не произойдёт


именно. и событие пропущено.

приведи код полностью. может быть, он это учитывает,
но здесь этого не видно.

idle ★★★★★
()
Ответ на: комментарий от idle

>это racy.

А вот это бред

представь, что обработчик вызывается прямо

перед тем, как ioctl() делает local_irq_save().



Ничего не произойдет - флаг не обнулен, обработчик просто пропустит код после проверки а ioctl будет ждать следующее прерывание. Я так понимаю прерывания там постоянно срабатывают иначе идея вообще бессмысленная - ioctl вызывается асинхронно. Чтобы ловить каждое прерывание в ioctl нужно включать это прерывание при входе и отключить на выходе.

anonymous
()
Ответ на: комментарий от anonymous

> > это racy.



А вот это бред



как скажешь.

Ничего не произойдет - флаг не обнулен,

будет ждать следующее прерывание



именно. это и называется missed event.

чтобы ловить каждое прерывание


ловится не прерывание, ловится событие. если оно
уже наступило, мы не должны ждать следующего.

idle ★★★★★
()
Ответ на: комментарий от idle

ловится не прерывание, ловится событие. если оно
уже наступило, мы не должны ждать следующего.

Советую посмотреть исходный вариант ТС

spin_lock_irqsave(dp->lock, flags);

if(dp->flag != 0) // процесс ждёт событие

{ dp->flag = 0; sched_bh = 1; printk(...); // сообщение появляется в логе при прерывании }

если никто не ждет этого события то его не нужно обрабатывать.

anonymous
()
Ответ на: комментарий от anonymous

> Советую посмотреть исходный вариант ТС

я говорил вообще, а не про исходный вариант.
что там происходит и что на самом деле нужно,
я не знаю. поэтому и попросил привести код
полностью.

сообщение появляется в логе при прерывании


опять-таки, я не знаю, что там. я не уверен, что
log интерпретируется правильно. может, сообщение
относится к другому (и успешному) wakeup'у.

еще раз, я не утверждаю, я просто не уверен, и
полной картины у меня нет.

точно так же, я не знаю точно, что именно ты хотел
показать своим примером. если у нас постоянный поток
прерываний, то да, навсегда процесс не уснет. но я-то
имел в виду другое, и ты меня понял.

и, раз уж мы начали с этим разбираться...

local_irq_save(flags);

dp->flag = 0;



что нам дает этот local_irq_save() ? это похоже на
попытку синхронизироваться с обработчиком. если мы
можем пропустить событие - зачем? и как это работает
если прерывание приходит на другой CPU ?

idle ★★★★★
()
Ответ на: комментарий от idle

>я говорил вообще, а не про исходный вариант.

что нам дает этот local_irq_save() ?


В данном случае ничего - можете убрать.

Чтобы _правильно_ решить задачу которую вы описали в своем видении - нужно управлять прерыванием в самом ioctl - выставить флаг, включить ожидаемое прерывание, уснуть в ожидании, проснуться и отключить прерывание до следующего ioctl.

anonymous
()
Ответ на: комментарий от idle

Хорошо приведу почти полный код для запроса и обработчика прерывания.

Некоторые структуры

struct dio_event
{
	unsigned int mod_number;	
	unsigned int timeout;		
	unsigned int ev_count;		
	unsigned int ev_data;		
	void *private;			
};

struct event_data
{
	unsigned int count;	// stores amount of events
	int wait_flag;		// inicates whether thread waits
};

struct dev_private
{
	struct _8255_dev hw_blk[2];
	struct event_data events[2];		
	spinlock_t lock;		
	wait_queue_head_t queue;	
};


Код запроса:

int dio_event(struct daq_device *dev, struct dio_event *de)
{
	struct dev_private *dp = dev->private;
	struct daq_module *mod;
	struct dio_module *dio_mod;
	int err;
	unsigned int ev_code;
	struct event_data *pevents = dp->events;
	unsigned long flags;
     
    	mod = dev->modules;
	dio_mod = mod->private;

#ifdef DAQ_DRV_DEBUG
	printk(KERN_INFO "dio_wait for pci-1751 device begin\n");
	printk(KERN_INFO "dio_wait: de->ev_data: %x, de->ev_count: %d, de->timeout: %d\n", de->ev_data, de->ev_count, de->timeout);
#endif	
	ev_code = (de->ev_data & 0x7FFFFFFF);  // индекс внутри массива dp->events
	
	spin_lock_irqsave(&dp->lock, flags);	// дпугой процесс получит ошибку если кто-то уже ждёт событие, проверка и изменение приватных данных должны быть выполнены атомарно
	if(pevents[ev_code].wait_flag != 0)
	{
		spin_unlock_irqrestore(&dp->lock, flags);
		return -EBUSY;
	}
	pevents[ev_code].count = de->ev_count;
	pevents[ev_code].wait_flag = 1;
        // записываю в регистр рассчитанное значение tmp
        // (его вычисление опускаю, оно верное!) 
	outb(tmp, dev->iobase + ADV_PCI_1751_ICR_OFFSET);
	spin_unlock_irqrestore(&dp->lock, flags);
#ifdef DAQ_DRV_DEBUG
	printk(KERN_INFO "count: %d, wait_flag: %d\n", pevents[ev_code].count, pevents[ev_code].wait_flag);
#endif
	if(de->timeout == 0) // жду вечно
	{
#ifdef DAQ_DRV_DEBUG
		printk(KERN_INFO "before send task to sleep\n");
#endif		
		err = wait_event_interruptible(dp->wait_queue, (pevents[ev_code].wait_flag == 0));
	}
	else
	{
#ifdef DAQ_DRV_DEBUG
		printk(KERN_INFO "before send task to sleep for %d msecs\n", (de->timeout));
#endif
		err = wait_event_interruptible_timeout(dp->wait_queue,
					(pevents[ev_code].wait_flag == 0), msecs_to_jiffies(de->timeout));
	}

#ifdef DAQ_DRV_DEBUG
	printk(KERN_INFO "task woked up, time remain: %d msecs\n", jiffies_to_msecs(err));
#endif
	spin_lock_irqsave(&dp->lock, flags);
	pevents[ev_code].wait_flag = 0;	// явно обнуляю. если истёк таймаут
	de->ev_count = pevents[ev_code].count;
	spin_unlock_irqrestore(&dp->lock, flags);

	if(err >= 0)	
	{
		de->timeout = jiffies_to_msecs(err);
		err = 0;
	}
	else							
	{
#ifdef DAQ_DRV_DEBUG
		printk(KERN_INFO "signal received\n");
#endif
	}
#ifdef DAQ_DRV_DEBUG
		printk(KERN_INFO "dio_wait for pci-1751 device end\n");
#endif	
	return err;
}


Код обработчика прерывания
static irqreturn_t pci_dev_isr(int irq, void *dev_id)
{
	unsigned char isr_value;
	struct dev_private *dp;
	struct daq_device *dev;
	struct event_data *ed;
	int sched_bh = 0;

	dev = (struct daq_device*)dev_id;
        // сохраняю статусный регистр
	isr_value = inb(dev->iobase + ADV_PCI_1751_ISR_OFFSET);
	if((isr_value & 0x88) == 0) 
		return IRQ_NONE;
        // очищаю флаг прерывания
	outb(isr_value, dev->iobase + ADV_PCI_1751_ICR_OFFSET);
	dp = (struct dev_private*)dev->private;
	spin_lock(&dp->lock);
	if(isr_value & 0x08)  // источник 0-й канал
	{
		ed = dp->events + 0;
		if(ed->wait_flag != 0)	// кто-то ждёт событие
		{
			ed->count--;
			if(ed->count == 0)  // просыпаемся
			{
				sched_bh = 1;
				ed->wait_flag = 0;
			}
		}
	}
	if(isr_value & 0x80)	// источник - 1-й канал
	{
		ed = dp->events + 1;
		if(ed->wait_flag != 0) // кто-то ждёт событие
		{
			ed->count--;
			if(ed->count == 0)  // просыпаемся
			{
				sched_bh = 1;
				ed->wait_flag = 0;
			}
		}
	}
	spin_unlock(&dp->lock);
#ifdef DAQ_DRV_DEBUG
	printk(KERN_INFO "from ISR -> isr_value: %x, sched_bh: %d\n", isr_value, sched_bh);
#endif
	if(sched_bh == 1)
		tasklet_schedule(&pci_1751_tasklet);
	return IRQ_HANDLED;
}


Устройство это - плата цифрового ввода/вывода, у неё есть 2 входных цифровых канала. При появлении переднего или заднего фронтов на этих каналах плата генерирует прерывание. Anonymous всё правильно понял - мне нужно считать заданное количество фронтов сигнала по таймауту при поступлении запроса и вернуть управление как только поступит указанное кол-во фронтов. Прерывания разрешаютcя/запрещаются при открытии/закрытии устройства.
Единственный момент - возможно я путаю dp->flag, точнее индексы в массиве в приватной структуре, так как их 2 на каждое устройство (для каждого канала), очередь ожидания одна, значит с ней всё должно быть в порядке. Сейчас нет возможности проверить только в понедельник.

linux__user
() автор топика
Ответ на: комментарий от anonymous

> > что нам дает этот local_irq_save() ?

В данном случае ничего - можете убрать.


ну и ладно. а я это воспринял - еще раз - как попытку
синхронизации.

Чтобы _правильно_ решить задачу которую вы

описали в своем видении



да я ничего не описывал. поэтому мало что могу сказать
про задачу, которая возникла вы вообразили при попытке
прочитать мое «видиние» ;)

нужно


зависит. может, и нужно. но не всегда. плюс миллион
других деталей, которые нужно учитывать при конкретных
обстоятельствах.

ладно, разобрались, я думаю.

idle ★★★★★
()
Ответ на: комментарий от linux__user

> Хорошо приведу почти полный код для запроса и

обработчика прерывания.


называется, сам напросился ;)

ну, сказать ничего не могу так сразу. тем более,
что логика все равно не ясна. кстати, в dev_private
должно быть wait_queue, а не queue, не?

Единственный момент - возможно я путаю dp->flag


возможно, но в dev_private нету ->flag ;)

мне непонятна логика count/ev_count, и из приведенного
фрагмента понять ее - вроде бы - нельзя.

одна только вещь выглядит подозрительно. в первоначальном
сообщении сказано:

> Используя printk, в системном логе я вижу, что

> выполняется обработчик прерывания и тасклет


однако:

#ifdef DAQ_DRV_DEBUG

printk(KERN_INFO «from ISR -> isr_value: %x, sched_bh: %d\n»,isr_value, sched_bh);


#endif


if(sched_bh == 1)


tasklet_schedule(&pci_1751_tasklet);



те, сообщение в логе не говорит о том, что wakeup был?

idle ★★★★★
()
Ответ на: комментарий от tailgunner

>Что сказать-то хотел?

очевдно - что ты не прав, очки протри :) Это внешнее событие по твоему определению и никто для его ожидания poll не использует и не будет использовать.

anonymous
()
Ответ на: комментарий от tailgunner

> > Вам привет от FBIO_WAITFORVSYNC.



Что сказать-то хотел?



он хотел сказать, что ты вот не знаешь, a у video drivers
есть такой ioctl который делает wait_.

а вот он знает. он знает! и поэтому в poll() никогда ждать
не будет, ибо нефиг. и тебе не советует.

idle ★★★★★
()
Ответ на: комментарий от anonymous

> очевдно - что ты не прав, очки протри :)

вотъ. вот эта и есть всегда главная цель на lor'e.
«я всем докажу, что ты не прав, сука» ;)

ну, правда. понятно же, что имел в виду tailgunner.
и правильно он сказал. и я почти уверен, что ты это
тоже понимаешь.

для его ожидания poll не использует и не будет

использоват



еще бы. в «struct file_operations fb_fops» его просто нет.

и потом, никто и не говорит, что это не имеет смысла
никогда. в данном случае, у нас, скорее, синхронизация,
а не ожидание события, кстати. но это не важно, спорить
я не буду.

idle ★★★★★
()
Ответ на: комментарий от idle

>он хотел сказать

То что я хотел - сказал сам, хотелось бы услышать - чем poll правильней ioctl в контексте вновь создаваемого драйвера устройства а не того что уже принято использовать в той или иной подсистеме ? я же прекрасно понял что Т-р имел ввиду.

anonymous
()
Ответ на: комментарий от idle

> те, сообщение в логе не говорит о том, что wakeup был?

не, я ступил. printk() выводит sched_bh, не заметил, сорри.

idle ★★★★★
()
Ответ на: комментарий от linux__user

не знаю, насколько это имеет значение, но один баг,
_вроде бы_, есть.

wait_event_interruptible_timeout(pevents[ev_code].wait_flag == 0)


ok, isr очищает wait_flag и делает wakeup().

однако, перед тем, как __wait_event_ завершится, другой
процесс может вызвать dio_event() и выставить wait_flag
снова.

idle ★★★★★
()
Ответ на: комментарий от idle

да и выход из dio_event() выглядит racy... но я не
думаю, что в этом причина.

если эта проблема легко воспроизводится, начни с того,
что посмотри /proc/pid/status «повисшего» процесса после
того, как лог доложит о wakeup.

idle ★★★★★
()
Ответ на: комментарий от idle

Некоторые переменные я впопыхах неправильно написал/урезал, дело не в них, count и ev_count - это количество событий(фронтов) в приватном массиве и в запросе соответственно.
А вот гонка после wait_event и перед захватом блокировки действительно возможна по-крайней мере для того кода, который я привёл. На самом деле есть ещё одна блокировка - внешняя (блокировка с выклчением прерываний - вложенная), я её просто не привёл здесь. Эта блокировка необходима, чтобы другой процесс не попытался изменить направление цифрового канала на выход во время ожидания первым процессом события по входу. Она не позволит другому процессу добраться до условия (if(pevents[ev_code].wait_flag != 0)), так что гонки не будет.
На выходе вроде только локальные переменные и переменные в контексте вызывающего процесса, так что там гонки быть не может.
А вот по поводу cat /proc/pid/status надо посмотреть, хотя там скорее всего будет sleep.

linux__user
() автор топика
Ответ на: комментарий от anonymous

ой. я тут совершенно случайно перечитал этот thread...

Я так понимаю прерывания там постоянно срабатывают


вот этого я не заметил.

да, при условии, что это оговорено явно, мои претензии
к вашему примеру были бредовыми.

я был не прав, сорри.

idle ★★★★★
()
Ответ на: комментарий от linux__user

> count и ev_count - это количество событий

это я понял. я имел в виду, а вдруг ev_count == 0
при вызове dio_event().

хотя там скорее всего будет sleep.


да, наверное. скорее всего, не будится просто задача,
не верю я в такие ошибки планировщика/tasklet.

можешь глянуть в /sys/kernel/debug/tracing/events/sched_wakeup

какая-то простая ошибка должна быть...

idle ★★★★★
()
Ответ на: комментарий от linux__user

При появлении переднего или заднего фронтов на этих каналах плата генерирует прерывание.

Это какие-то медленные каналы ? Подозрителен такой подход с прерыванием на каждый клок.

Я бы на вашем месте сначала отладил работу с одним каналом а потом искал где баг.

.....
   struct event_data *pevents = dp->events;
   unsigned long flags;
   
   mutex_lock(&dp->mutex_lock);
  
       mod = dev->modules;
.....


   mutex_unlock(&mutex_lock);
   
  return err;
}

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

pevents[ev_code].wait_flag != 0

можно было сразу после определения текущего индекса присвоить указатель на нужный элемент массива и работать с короткой записью.

PS названия переменных и структур мозг выносят, код трудно читаемый

anonymous
()
Ответ на: комментарий от anonymous

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

anonymous
()
Ответ на: комментарий от Idle

В тасклете только вызывается wake_up_interruptible() и выводится в лог сам факт выполнения.
Попробую проверить адреса флагов в запросе и обработчике прерывания.

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

Ого, ничего себе вы тут развлекаетесь :) Оживленная дискуссия.

Я почитал пошивку ЛОРа за 2005-2006 год, тогда в таких темах человека два с половиной сидело.

ttnl ★★★★★
()
Ответ на: комментарий от idle

В общем сегодня проверил работу драйвера ещё раз. Если вызывать wake_up_interruptible() в обработчике прерывания, то процесс просыпается когда надо... В связи с этим вопрос - почему этот вызов в тасклете ни к чему не приводит? Куски кода тасклета следующие:

// обработчик для тасклета
static void do_tasklet(unsigned long param)
{
   struct daq_device *dev = (struct daq_device*)param;
   struct dev_priv *dp    = (struct dev_priv*)dev->private;
   wake_up_interruptible(&dp->wait_queue); 

}

// объявление такслета
static DECLARE_TASKLET(dev_tasklet, do_tasklet, 0);

// в коде инициализации устройства
int dev_init(struct daq_device* dev)
{
   ...
   // сохраняю указатель на устройство в структуре тасклета
   dev_tasklet.data = (unsigned long)dev;
   ...
}

Возможно, нужно ещё что-то добавить в такслет? Да, кстати, ядро версии 2.6.35.

linux__user
() автор топика
Ответ на: комментарий от linux__user

> Если вызывать wake_up_interruptible() в обработчике прерывания, то процесс просыпается когда надо..

Это похоже на race

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Откуда гонка? Единственный процесс посылает один запрос на один импульс, имитирую один импульс, приходит прерывание, затем выполняется тасклет, вызывая wake_up_interruptible(), процесс просыпается по истечении таймаута. Всё протрассировал через printk() - в контексте процесса до wait_event_... флаг равен 1, сразу после wait_event_... флаг равен 0 (изменяется в прерывании). Как будто в тасклете этот вызов игнорируется.
На другой машине с более ранней версией ядра (не помню какой) код выполнялся корректно. Может что-то в версии 2.6.35 что-то поменяли?

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