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! BTW: To compile "example/select/rt_server.c" you should run "./autogen.sh" before running "configure && make". To run the test I load RTnet and the test module on the "Target-System": modprobe rtnet modprobe 8139too-rt # Or the module for your real time NIC rtifconfig rteth0 up 192.168.6.4 netmask 255.255.255.0 cd .../rtnet-select/examples/select insmod ./rt_server # now watch the kernel log messages On "Another-Host", which has no RTnet, but is attached to the same network as the "Target-System" I run: echo blubb | nc -u -q1 192.168.6.4 45054 # for the one socket... echo blubb | nc -u -q1 192.168.6.4 36000 # ...for the other socket # watch the kernel log messages of the "Target-System" # (nc -> netcat; -u -> udp-packets;) The main changes against RTnet are in "socket.c" and "include/rtnet_socket.h". -- Hans-Peter Bock Dipl.-Ing. ISW - Universitaet Stuttgart Seidenstrasse 36 D-70174 Stuttgart http://www.isw.uni-stuttgart.de/
diff -NrU3 rtnet-0-6-2/configure.ac rtnet-0-6-2-select/configure.ac
--- rtnet-0-6-2/configure.ac 2004-03-24 18:10:52.000000000 +0100
+++ rtnet-0-6-2-select/configure.ac 2004-05-06 17:02:06.000000000 +0200
@@ -808,6 +808,7 @@
examples/round_trip_time/client/Makefile \
examples/round_trip_time/server/Makefile \
examples/rtnet_lxrt/Makefile \
+examples/select/Makefile \
examples/rtskb_alloc/Makefile \
examples/rtt/Makefile \
examples/frag_ip/Makefile \
diff -NrU3 rtnet-0-6-2/examples/Makefile.am rtnet-0-6-2-select/examples/Makefile.am
--- rtnet-0-6-2/examples/Makefile.am 2003-11-07 09:02:53.000000000 +0100
+++ rtnet-0-6-2-select/examples/Makefile.am 2004-05-06 16:33:36.000000000 +0200
@@ -4,4 +4,4 @@
OPTDIRS += rtnet_lxrt
endif
-SUBDIRS = round_trip_time rtskb_alloc rtt frag_ip raw_packets $(OPTDIRS)
+SUBDIRS = round_trip_time rtskb_alloc rtt frag_ip raw_packets select $(OPTDIRS)
diff -NrU3 rtnet-0-6-2/examples/select/Makefile.am
rtnet-0-6-2-select/examples/select/Makefile.am
--- rtnet-0-6-2/examples/select/Makefile.am 1970-01-01 01:00:00.000000000 +0100
+++ rtnet-0-6-2-select/examples/select/Makefile.am 2004-05-06 16:34:40.000000000
+0200
@@ -0,0 +1,10 @@
+noinst_LIBRARIES = librt_server.a
+
+librt_server_a_SOURCES = rt_server.c
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/include \
+ @RTAI_KMOD_CFLAGS@
+
+all-local: rt_server.o
diff -NrU3 rtnet-0-6-2/examples/select/rt_server.c
rtnet-0-6-2-select/examples/select/rt_server.c
--- rtnet-0-6-2/examples/select/rt_server.c 1970-01-01 01:00:00.000000000 +0100
+++ rtnet-0-6-2-select/examples/select/rt_server.c 2004-05-06 16:44:03.000000000
+0200
@@ -0,0 +1,239 @@
+/***
+ *
+ * rtnet/examples/select/rt_server.c
+ * test for implementation of rtnet_select()
+ * 2004 by Hans-Peter Bock <[EMAIL PROTECTED]>
+ *
+ * based on rt_echo_client/rt_server (C) 2002 by
+ * Ulrich Marx <[EMAIL PROTECTED]>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <net/ip.h>
+
+#include <rtnet_config.h>
+
+#include <rtai.h>
+#include <rtai_sched.h>
+#include <rtai_fifos.h>
+
+#ifdef HAVE_RTAI_SEM_H
+#include <rtai_sem.h>
+#endif
+
+#include <rtnet.h>
+
+#define MIN_LENGTH_IPv4 7
+#define MAX_LENGTH_IPv4 15
+static char *local_ip_s = "192.168.6.4";
+
+MODULE_PARM (local_ip_s ,"s");
+MODULE_PARM_DESC (local_ip_s, "local ip-addr");
+
+#define TICK_PERIOD 100000
+#define PRINT 0
+RT_TASK rt_task;
+
+#define RCV_PORT1 36000
+#define RCV_PORT2 45054
+
+static struct sockaddr_in local_addr1;
+static struct sockaddr_in local_addr2;
+
+static int sock1, sock2;
+
+#define BUFSIZE 1500
+char buffer[BUFSIZE];
+
+
+unsigned long rt_inet_aton(const char *ip)
+{
+ int p, n, c;
+ union { unsigned long l; char c[4]; } u;
+ p = n = 0;
+ while ((c = *ip++)) {
+ if (c != '.') {
+ n = n*10 + c-'0';
+ } else {
+ if (n > 0xFF) {
+ return 0;
+ }
+ u.c[p++] = n;
+ n = 0;
+ }
+ }
+ u.c[3] = n;
+ return u.l;
+}
+
+
+int packetsize = 58;
+
+void *process(void * arg)
+{
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ struct msghdr msg;
+ struct iovec iov;
+ struct sockaddr_in addr;
+
+ memset(&msg, 0, sizeof(msg));
+ iov.iov_base=&buffer;
+ iov.iov_len=BUFSIZE;
+ msg.msg_name=&addr;
+ msg.msg_namelen=sizeof(addr);
+ msg.msg_iov=&iov;
+ msg.msg_iovlen=1;
+ msg.msg_control=NULL;
+ msg.msg_controllen=0;
+
+ rt_printk("readfds: %08x\n", *((int*)&readfds));
+ rt_printk("Setting bits %d and %d in file descriptor set.\n", sock1, sock2);
+ FD_SET((sock1&255), &readfds);
+ FD_SET((sock2&255), &readfds);
+ rt_printk("### FD_SET succeeded.\n");
+ rt_printk("readfds: %08x\n", *((int*)&readfds));
+
+ while(1) {
+ int ret;
+ ret = rtnet_select(sock1 > sock2 ? sock1 : sock2,
+ &readfds, 0, 0);
+
+ while (0<rt_socket_recvmsg(sock1, &msg, MSG_DONTWAIT)) {
+ rt_printk("--> Socket %u\n", sock1);
+ }
+
+ while (0<rt_socket_recvmsg(sock2, &msg, MSG_DONTWAIT)) {
+ rt_printk("--> Socket %u\n", sock2);
+ }
+ }
+}
+
+
+/*
+int echo_rcv(int s,void *arg)
+{
+ int ret=0;
+ struct msghdr msg;
+ struct iovec iov;
+ struct sockaddr_in addr;
+
+ memset(&msg, 0, sizeof(msg));
+ iov.iov_base=&buffer;
+ iov.iov_len=BUFSIZE;
+ msg.msg_name=&addr;
+ msg.msg_namelen=sizeof(addr);
+ msg.msg_iov=&iov;
+ msg.msg_iovlen=1;
+ msg.msg_control=NULL;
+ msg.msg_controllen=0;
+
+ ret=rt_socket_recvmsg(sock, &msg, RT_SOCK_NONBLOCK);
+ if ( (ret>0) && (msg.msg_namelen==sizeof(struct sockaddr_in)) ) {
+ if ((0 < ret) && (ret <= 1400))
+ packetsize = ret;
+ memcpy(&tx_msg, &buffer, packetsize);
+ rt_sem_signal(&tx_sem);
+ }
+
+ return 0;
+}
+*/
+
+
+int init_module(void)
+{
+ int ret;
+
+ unsigned int local_ip = rt_inet_aton(local_ip_s);
+
+ printk("*** Compiled on %s %s ***\n", __DATE__, __TIME__);
+
+ printk ("local ip address 1: %s=%08x\n", local_ip_s, local_ip);
+
+ /* create rt-socket */
+ printk("create rtsocket 1\n");
+ if ((sock1=rt_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ printk("socket not created\n");
+ return -ENOMEM;
+ }
+
+ printk("create rtsocket 2\n");
+ if ((sock2=rt_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ printk("socket not created\n");
+ return -ENOMEM;
+ }
+ printk("Sockets: %d / %d.\n", sock1, sock2);
+
+ /* bind the rt-socket to local_addr */
+ printk("bind rtsocket 1 to local address:port\n");
+ memset(&local_addr1, 0, sizeof(struct sockaddr_in));
+ local_addr1.sin_family = AF_INET;
+ local_addr1.sin_port = htons(RCV_PORT1);
+ local_addr1.sin_addr.s_addr = local_ip;
+ if ( (ret=rt_socket_bind(sock1, (struct sockaddr *) &local_addr1,
sizeof(struct sockaddr_in)))<0 ) {
+ printk("can't bind rtsocket\n");
+ return ret;
+ }
+
+ printk("bind rtsocket 2 to local address:port\n");
+ memset(&local_addr1, 0, sizeof(struct sockaddr_in));
+ local_addr2.sin_family = AF_INET;
+ local_addr2.sin_port = htons(RCV_PORT2);
+ local_addr2.sin_addr.s_addr = local_ip;
+ if ( (ret=rt_socket_bind(sock2, (struct sockaddr *) &local_addr2,
sizeof(struct sockaddr_in)))<0 ) {
+ printk("can't bind rtsocket\n");
+ return ret;
+ }
+
+ /* create print-fifo */
+ rtf_create(PRINT, 3000);
+
+ ret=rt_task_init(&rt_task,(void *)process,0,4096,9,0,NULL);
+ rt_task_resume (&rt_task);
+
+ return ret;
+}
+
+
+
+
+void cleanup_module(void)
+{
+ while (rt_socket_close(sock1) == -EAGAIN) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1*HZ); /* wait a second */
+ }
+
+ while (rt_socket_close(sock2) == -EAGAIN) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1*HZ); /* wait a second */
+ }
+
+ rt_task_delete(&rt_task);
+ rtf_destroy(PRINT);
+ printk("module unloaded\n\n");
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -NrU3 rtnet-0-6-2/include/rtnet.h rtnet-0-6-2-select/include/rtnet.h
--- rtnet-0-6-2/include/rtnet.h 2004-02-24 18:14:38.000000000 +0100
+++ rtnet-0-6-2-select/include/rtnet.h 2004-05-06 16:32:53.000000000 +0200
@@ -65,6 +65,7 @@
extern int rt_socket_setsockopt (int s, int level, int optname,
const void *optval, socklen_t optlen);
extern int rt_socket_ioctl (int s, int request, void *arg);
+extern int rtnet_select (int n, fd_set *readfds, fd_set *writefds, fd_set
*exceptfds);
#define rt_bind rt_socket_bind
#define rt_listen rt_socket_listen
diff -NrU3 rtnet-0-6-2/include/rtnet_socket.h rtnet-0-6-2-select/include/rtnet_socket.h
--- rtnet-0-6-2/include/rtnet_socket.h 2004-04-01 15:43:28.000000000 +0200
+++ rtnet-0-6-2-select/include/rtnet_socket.h 2004-05-06 16:33:01.000000000 +0200
@@ -86,6 +86,7 @@
int (*wakeup)(int s,void *arg); /* callback function */
void *wakeup_arg; /* argument of callback function */
rtos_event_sem_t wakeup_event; /* for blocking calls */
+ rtos_event_sem_t *wakeup_select; /* for selecting calls - this should be the
head of a list of mailboxes */
union {
/* IP specific */
diff -NrU3 rtnet-0-6-2/ipv4/udp.c rtnet-0-6-2-select/ipv4/udp.c
--- rtnet-0-6-2/ipv4/udp.c 2004-04-01 15:48:08.000000000 +0200
+++ rtnet-0-6-2-select/ipv4/udp.c 2004-05-06 16:33:24.000000000 +0200
@@ -468,6 +468,9 @@
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);
diff -NrU3 rtnet-0-6-2/rtnet_syms.c rtnet-0-6-2-select/rtnet_syms.c
--- rtnet-0-6-2/rtnet_syms.c 2004-03-17 13:41:29.000000000 +0100
+++ rtnet-0-6-2-select/rtnet_syms.c 2004-05-06 16:32:31.000000000 +0200
@@ -54,6 +54,7 @@
EXPORT_SYMBOL(rt_socket_getsockname);
EXPORT_SYMBOL(rt_socket_setsockopt);
EXPORT_SYMBOL(rt_socket_ioctl);
+EXPORT_SYMBOL(rtnet_select);
EXPORT_SYMBOL(rt_socket_callback);
diff -NrU3 rtnet-0-6-2/socket.c rtnet-0-6-2-select/socket.c
--- rtnet-0-6-2/socket.c 2004-04-01 15:43:24.000000000 +0200
+++ rtnet-0-6-2-select/socket.c 2004-05-06 16:32:45.000000000 +0200
@@ -652,6 +652,60 @@
}
+/***
+ * rtnet_select
+ */
+
+int rtnet_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds) { /*
timeval is missing here */
+ int i;
+ fd_set fds; /* 128 bytes on i386 */
+ rtos_event_sem_t wakeme;
+
+ rt_printk("\n*** select ***\n");
+ rt_printk("readfds: %08x @ %p\n", *((int*)readfds), (void*)readfds);
+ FD_ZERO(&fds);
+ rt_printk("fds: %08x\n", *((int*)&fds));
+ rtos_event_sem_init(&wakeme);
+
+ n = RT_SOCKETS < n ? RT_SOCKETS : n;
+ for (i=0; i<=n; i++) { /* n vs. RT_SOCKETS */
+ struct rtsocket *sock;
+ if (FD_ISSET(i, readfds)) {
+ FD_SET(i, &fds);
+#warning ...overwriting others data, heh?
+ sock=rt_socket_lookup(i);
+ if (sock)
+ sock->wakeup_select=&wakeme;
+#warning what if there is data already available
+ }
+ }
+
+ rt_printk("fds: %08x\n", *((int*)&fds));
+ rtos_event_sem_wait(&wakeme); /* should be rtos_event_sem_wait_timed() */
+
+ for (i=0; i<=n; i++) { /* n vs. RT_SOCKETS */
+ if (FD_ISSET(i, &fds)) {
+ struct rtsocket *sock;
+ sock = rt_socket_lookup(i);
+ sock->wakeup_select=0;
+#warning it is not nice to dereference the socket twice at this place
+ rt_socket_dereference(sock);
+ rt_socket_dereference(sock);
+ }
+ }
+
+ /* check mailbox non blocking for further messages*/
+
+ rtos_event_sem_delete(&wakeme);
+
+ /* On success, select and pselect return the number of descriptors con-
+ * tained in the descriptor sets, which may be zero if the timeout expires
+ * before anything interesting happens. On error, -1 is returned, and
+ * errno is set appropriately; the sets and timeout become undefined, so
+ * do not rely on their contents after an error.
+ */
+ return 0; /* fix this */
+}
/************************************************************************
* initialisation of rt-socket interface *
@@ -669,6 +723,7 @@
rt_sockets[0].list_entry.next = (struct list_head *)&rt_sockets[1];
rt_sockets[0].state = TCP_CLOSE;
rt_sockets[0].fd = 0;
+ rt_sockets[0].wakeup_select = 0;
/* initialise the last socket */
rt_sockets[RT_SOCKETS-1].list_entry.next = NULL;
@@ -679,6 +734,7 @@
rt_sockets[i].list_entry.next = (struct list_head *)&rt_sockets[i+1];
rt_sockets[i].state = TCP_CLOSE;
rt_sockets[i].fd = i;
+ rt_sockets[i].wakeup_select = 0;
}
free_rtsockets=&rt_sockets[0];
}
pgp00000.pgp
Description: PGP signature

