Hello,
attached to this email I send you a patch against RTnet 0.6.2 which adds an (incomplete) select() functionality for sockets to RTnet. This patch is not supposed to work perfectly but has some flaws and race conditions. But it shows, that it is basically possible to add a select() functionality for sockets to RTnet.
Please feel free to post comments or critics!
[...]
rtskb_queue_tail(&rtsk->incoming, skb);
rtos_event_sem_signal(&rtsk->wakeup_event);
+#warning this is a race condition
+ if (rtsk->wakeup_select)
+ rtos_event_sem_signal(rtsk->wakeup_select); /* might be 0 meanwhile */
if (rtsk->wakeup != NULL)
rtsk->wakeup(rtsk->fd, rtsk->wakeup_arg);
Well, this race condition is really tricky. It also concerns the two lines below and a few other socket parameters the user may change on an open socket. But let's look at the select issue first:
I think we have two options. The first one is to put your two lines within the protection of a lock. This works as long as we demand that the executing task has always a higher priority than the task which we wake up - but this cannot be guaranteed as e.g. the lookback device will run the code above in the context of the packet sender, thus with arbitrary priority.
The other option is to make the event semaphore persistent even beyond the rt_select (or rt_poll) call. I currently have the following concept in mind, but it is not yet fully thought through: Set a pointer (replacing wakeup_select) from all sockets in the set to the first one and reference the first socket as often as this link is set. When rt_select exits, remove this links. Of course, all the linking and unlinking has to be protected by something like a per-socket spin lock.
Now rethink the rt_udp_rcv (rt_packet_rcv would be similar):
int rt_udp_rcv (struct rtskb *skb)
{
struct rtsocket *rtsk = skb->sk;
unsigned long flags;
#ifdef CONFIG_RTNET_CALLBACK
void *arg;
int (*wakeup)(int, void *);
#endif
rtskb_queue_tail(&rtsk->incoming, skb); rtos_event_sem_signal(&rtsk->wakeup_event);
#ifdef CONFIG_RTNET_SELECT
rtos_spin_lock_irqsave(&rtsk->param_lock, flags);
if (rtsk->socket_group) {
rt_socket_reference(rtsk->socket_group);
rtos_spin_unlock_irqsave(&rtsk->param_lock, flags);
rtos_event_sem_signal(&rtsk->socket_group->wakeup_event);
} else
rtos_spin_unlock_irqsave(&rtsk->param_lock, flags);
#endif#ifdef CONFIG_RTNET_CALLBACK
rtos_spin_lock_irqsave(&rtsk->param_lock, flags);
arg = rtskb->wakeup_arg;
wakeup = rtskb->wakeup;
rt_socket_reference(rtsk);
rtos_spin_unlock_irqsave(&rtsk->param_lock, flags); if (wakeup)
wakeup(rtsk->fd, arg);rt_socket_dereference(rtsk); #endif
return 0; }
Note: This means that rt_select would have to block on the wakeup_event of the first socket.
Well, looks ugly as it adds further code to the critical reception path. But, by using #ifdef, the user should be able to avoid the overhead when these features are not needed.
So, the rt_udp_rcv function also shows how the race conditions during the modification of socket parameters can be avoided (of course, locks are also required in the API functions). There are a few other parts of the reception path which also need a closer look to make RTnet more user-safe.
Jan
-------------------------------------------------------
This SF.Net email is sponsored by Sleepycat Software
Learn developer strategies Cisco, Motorola, Ericsson & Lucent use to deliver higher performing products faster, at low TCO.
http://www.sleepycat.com/telcomwpreg.php?From=osdnemail3
_______________________________________________
RTnet-users mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/rtnet-users

