Hi,

I failed to find the original message from Sebastian that led to the following change:

-----
2005-11-09 Philippe Gerum <[EMAIL PROTECTED]>

* nucleus/pipe.c (xnpipe_disconnect): Flush the output queue
upon closure. Issue spotted by Sebastian Smolorz.
(xnpipe_release): Flush the input queue upon closure.
-----

There is one more issue as follows. The reason is that xnpipe_open/release() are not atomic.

Briefly, a newly connected standard linux thread may get a message that have been posted by the real-time side long time before a connection has been opened by that thread. That message has been placed to the queue at the time when there was another linux thread connected to the pipe.

err... I'm not sure now that we should fight against that :confused a bit:

--- details ---

THREAD #1 on CPU #1 (normal linux thread):

xnpipe_release()
{

// ok, we are locked here and noone may access the inq queue, let's free all the messages if any
...
if (state->output_handler != NULL)
{
while ((holder = getq(&state->outq)) != NULL)
state->output_handler(minor,link2mh(holder),-EPIPE,state->cookie);
}
while ((holder = getq(&state->inq)) != NULL)
{
if (state->input_handler != NULL)
state->input_handler(minor,link2mh(holder),-EPIPE,state->cookie);
else if (state->alloc_handler == NULL)
xnfree(link2mh(holder));
}

...
if (waitqueue_active(&state->readq))
wake_up_interruptible_all(&state->readq);

if (state->asyncq) /* Clear the async queue */
{
xnlock_get_irqsave(&nklock,s);
removeq(&xnpipe_asyncq,&state->alink);
clrbits(state->status,XNPIPE_USER_SIGIO);
xnlock_put_irqrestore(&nklock,s);
fasync_helper(-1,file,0,&state->asyncq);
}

// here the lock is not held.

(*** EIP ***) -------> THREAD #1 is about to drop the XNPIPE_USER_CONN flag.

/* Free the state object. Since that time it can be open by someone else */
clrbits(state->status,XNPIPE_USER_CONN);
}


THREAD #2 on CPU #2 (real-time thread)

xnpipe_send()
{
...
// locked section

xnlock_get_irqsave(&nklock,s);

// actually, the following 2 checks should be re-ordered :)

(*** EIP ***) <----- THREAD #1 doesn't dropped the XNPIPE_USER_CONN flag yet but the pipe is almost non-valid!

if (!testbits(state->status,XNPIPE_USER_CONN))
{
xnlock_put_irqrestore(&nklock,s);
return -EPIPE;
}

if (!testbits(state->status,XNPIPE_KERN_CONN))
{
xnlock_put_irqrestore(&nklock,s);
return -EBADF;
}

inith(xnpipe_m_link(mh));
xnpipe_m_size(mh) = size - sizeof(*mh);
state->ionrd += xnpipe_m_size(mh);

// here the message is successfully added to the outq

if (flags & XNPIPE_URGENT)
prependq(&state->outq,xnpipe_m_link(mh));
else
appendq(&state->outq,xnpipe_m_link(mh));

}

...

In the mean time, THREAD #1 drops the XNPIPE_USER_FLAG so another standard linux thread may open a pipe. When that happens, that thread will find a message that have been posted when the old connection existed.

err... so is it a problem regarding desired behaviour of pipes?


---

Dmitry


Reply via email to