问题
I am writing a sleepy driver. Here any process that tries to write to the device file should sleep for 'n' number of seconds supplied by the user. Reader process should wake up all the waiting processes.
Writer code :
printk("Invoking interruptible_timeout for device flag[%d] = %d\n", idn, flag[idn]);
long ret = wait_event_interruptible_timeout(wq[idn],flag[idn]==1,sec*HZ)/HZ;
//flag[idn]=0;
printk("timeout returned : %d idn = %d\n", ret, idn)
printk("writer : flag[%d] = %d\n", idn, flag[idn]);
retval=ret;
Reader code :
printk("waking up process with idn = %d\n", idn);
flag[idn]=1;
printk("reader : flag[%d] = %d \n", idn, flag[idn]);
wake_up_interruptible(&wq[idn]);
while(waitqueue_active(&wq[idn]));
flag[idn] = 0;
printk("returned from wake_up_interruptible \n");
printk("reader : flag[%d] = %d \n", idn, flag[idn]);
Initially flag[0] = 0; So all the writer processes sleep till the condition flag[idn] == 1 become true. This is working as expected.
But in reader code, I am setting flag[idn] = 1 and invoking wake_up_interruptible() to wake all processes sleeping on the condition. But this is not waking up the sleeping processes. But if I take out flag[idn] = 0 just below while(waitqueue_active(&wq[idn])), it is working i.e, function is waking up the sleeping processes.
Why is this so ?
回答1:
When reader process executes flag[idn] = 0
, waitqueue is empty, but there is no garantee that awoken writer process has wait condition (flag[idn] == 1
) already checked. So, writer process can see that flag is 0, and continues waiting.
The thing is that, wait_event-family macros use autoremove_wake_function when add wait into the waitqueue. This function is called by the reader at wake_up_interruptible() call and, aside from marks writer process as awoken, immediately removes wait from the waitqueue.
Actually, reseting wait condition after wake_up() is a bad idea anyway: resulted code has obscure semantic, and likely suffers from race conditions.
For achive effect with repeatable awoken, you can use this code:
Writer:
int cflag = flag[idn];
wait_event_interruptible_timeout(&wq[idn], flag[idn] != cflag, sec*HZ);
Reader:
flag[idn]++;
wake_up_interruptible_all(&wq[idn]);
Here writer process always waits at least one reader process is executed.
Note, that flag[idn]++
now doesn't reset wait condition flag[idn] != cflag
.
来源:https://stackoverflow.com/questions/29763742/wake-up-interruptible-is-not-waking-up-the-processes-sleeping-on-condition