Possible thread synchronisation bug in rtems networking
Graham Darnell
graham at popwish.com
Sat Mar 1 11:19:52 UTC 2008
Hi,
I am concerned that there is a thread synchronisation problem in the
rtems networking code.
All calls to rtems socket functions are protected by a single mutex, but
in order to prevent the networking stack from seizing up in the presence
of long-running calls, there are two mechanisms in place. One of these
deals with blocking reads, the other deals with functions like connect,
accept, and close (in the presence of SO_LINGER), which need to wait for
a connection or disconnection.
It is this second mechanism that concerns me.
It consists of two functions:
soconnsleep: this function is called in connect, accept, and close in
the context of a client thread of arbitrary priority in order to wait
for the connection state to change.
soconnwakeup: this function is called in the context of a high priority
networking thread when the connection state changes
The idea is that soconnsleep releases the global networking mutex then
waits on an rtems event which is produced some time later when
soconnwakeup is called. soconnsleep then reacquires the global
networking mutex and carries on as normal.
The source code is reproduced below.
My concern is with the call to rtems_event_receive() marked with the
comment 'Soak up any pending events'. And my fear is that this will,
under unfavourable thread scheduling conditions, soak up not only the
pending events but also the actual connection/disconnection event that
we are waiting for. The result being that we never return from
soconnsleep and the application thread is largely toast.
What I am really seeking is some confirmation that my fears are correct
from someone who knows this code better than me.
I do have a couple of proposals for a solution, but I guess that can
wait until my fears have been verified or refuted.
Best regards
Graham Darnell
/*
* Wait for a connection/disconnection event.
*/
*int*
soconnsleep (*struct* socket *so)
{
rtems_event_set events;
rtems_id tid;
rtems_status_code sc;
/*
* Soak up any pending events.
* The sleep/wakeup synchronization in the FreeBSD
* kernel has no memory.
*/
rtems_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY |
RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
/*
* Set this task as the target of the wakeup operation.
*/
* if* (so->so_pgid)
rtems_panic ("Another task is already sleeping on that
socket");
rtems_task_ident (RTEMS_SELF, 0, &tid);
so->so_pgid = tid;
/*
* Wait for the wakeup event.
*/
sc = rtems_bsdnet_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY
| RTEMS_WAIT, so->so_rcv.sb_timeo, &events);
/*
* Relinquish ownership of the socket.
*/
so->so_pgid = 0;
* switch* (sc) {
* case* RTEMS_SUCCESSFUL: * return* 0;
* case* RTEMS_TIMEOUT: * return* EWOULDBLOCK;
* default*: * return* ENXIO;
}
}
/*
* Wake up a task waiting for a connection/disconnection to complete.
*/
*void*
soconnwakeup (*struct* socket *so)
{
* if* (so->so_pgid)
rtems_event_send (so->so_pgid, SOSLEEP_EVENT);
}
More information about the users
mailing list