Patch from Ian Lance Taylor <ian@airs.com>:

The select function is not particularly efficient when dealing with a
    large number of sockets.  The application has to build a big set of
    bits and pass it in.  RTEMS has to look through all those bits and see
    what is ready.  Then the application has to look through all the bits
    again.

    On the other hand, when using RTEMS, the select function is needed
    exactly when you have a large number of sockets, because that is when
    it becomes prohibitive to use a separate thread for each socket.

    I think it would make more sense for RTEMS to support callback
    functions which could be invoked when there is data available to read
    from a socket, or when there is space available to write to a socket.

    Accordingly, I implemented them.

    This patch adds two new SOL_SOCKET options to setsockopt and
    getsockopt: SO_SNDWAKEUP and SO_RCVWAKEUP.  They take arguments of
    type struct sockwakeup:

    struct  sockwakeup {
        void    (*sw_pfn) __P((struct socket *, caddr_t));
        caddr_t sw_arg;
    };

    They are used to add or remove a function which will be called when
    something happens for the socket.  Getting a callback doesn't imply
    that a read or write will succeed, but it does imply that it is worth
    trying.

    This adds functionality to RTEMS which is somewhat like interrupt
    driven socket I/O on Unix.

    After the patch to RTEMS, I have appended a patch to
    netdemos-19990407/select/test.c to test the new functionality and
    demonstrate one way it might be used.  To run the new test instead of
    the select test, change doSocket to call echoServer2 instead of
    echoServer.
This commit is contained in:
Joel Sherrill
1999-06-11 14:11:44 +00:00
parent 0643693198
commit a6f3cff703
16 changed files with 256 additions and 8 deletions

View File

@@ -979,6 +979,31 @@ sosetopt(so, level, optname, m0)
so->so_state &= ~SS_PRIV;
break;
case SO_SNDWAKEUP:
case SO_RCVWAKEUP:
{
/* RTEMS addition. */
struct sockwakeup *sw;
struct sockbuf *sb;
if (m == NULL
|| m->m_len != sizeof (struct sockwakeup)) {
error = EINVAL;
goto bad;
}
sw = mtod(m, struct sockwakeup *);
sb = (optname == SO_SNDWAKEUP
? &so->so_snd
: &so->so_rcv);
sb->sb_wakeup = sw->sw_pfn;
sb->sb_wakeuparg = sw->sw_arg;
if (sw->sw_pfn)
sb->sb_flags |= SB_ASYNC;
else
sb->sb_flags &=~ SB_ASYNC;
break;
}
default:
error = ENOPROTOOPT;
break;
@@ -1076,6 +1101,23 @@ sogetopt(so, level, optname, mp)
break;
}
case SO_SNDWAKEUP:
case SO_RCVWAKEUP:
{
struct sockbuf *sb;
struct sockwakeup *sw;
/* RTEMS additions. */
sb = (optname == SO_SNDWAKEUP
? &so->so_snd
: &so->so_rcv);
m->m_len = sizeof (struct sockwakeup);
sw = mtod(m, struct sockwakeup *);
sw->sw_pfn = sb->sb_wakeup;
sw->sw_arg = sb->sb_wakeuparg;
break;
}
default:
(void)m_free(m);
return (ENOPROTOOPT);

View File

@@ -345,6 +345,9 @@ sowakeup(so, sb)
sb->sb_flags &= ~SB_WAIT;
rtems_event_send (sb->sb_sel.si_pid, SBWAIT_EVENT);
}
if (sb->sb_wakeup) {
(*sb->sb_wakeup) (so, sb->sb_wakeuparg);
}
}
/*

View File

@@ -37,6 +37,8 @@
#ifndef _SYS_SOCKET_H_
#define _SYS_SOCKET_H_
#include <sys/cdefs.h>
/*
* Definitions related to sockets: types, address families, options.
*/
@@ -78,6 +80,12 @@
#define SO_TYPE 0x1008 /* get socket type */
#define SO_PRIVSTATE 0x1009 /* get/deny privileged state */
/*
* RTEMS addition: get and set wakeup functions.
*/
#define SO_SNDWAKEUP 0x1020 /* wakeup when ready to send */
#define SO_RCVWAKEUP 0x1021 /* wakeup when ready to receive */
/*
* Structure used for manipulating linger option.
*/
@@ -86,6 +94,15 @@ struct linger {
int l_linger; /* linger time */
};
/*
* RTEMS addition: structure used to get and set wakeup function.
*/
struct socket;
struct sockwakeup {
void (*sw_pfn) __P((struct socket *, caddr_t));
caddr_t sw_arg;
};
/*
* Level number for (get/set)sockopt() to apply to socket itself.
*/
@@ -327,8 +344,6 @@ struct omsghdr {
#ifndef KERNEL
#include <sys/cdefs.h>
__BEGIN_DECLS
int accept __P((int, struct sockaddr *, int *));
int bind __P((int, const struct sockaddr *, int));

View File

@@ -89,6 +89,8 @@ struct socket {
struct selinfo sb_sel; /* process selecting read/write */
short sb_flags; /* flags, see below */
u_long sb_timeo; /* timeout for read/write */
void (*sb_wakeup) __P((struct socket *, caddr_t));
caddr_t sb_wakeuparg; /* arg for above */
} so_rcv, so_snd;
#define SB_MAX (256*1024) /* default for max chars in sockbuf */
#define SB_LOCK 0x01 /* lock on data queue */

View File

@@ -979,6 +979,31 @@ sosetopt(so, level, optname, m0)
so->so_state &= ~SS_PRIV;
break;
case SO_SNDWAKEUP:
case SO_RCVWAKEUP:
{
/* RTEMS addition. */
struct sockwakeup *sw;
struct sockbuf *sb;
if (m == NULL
|| m->m_len != sizeof (struct sockwakeup)) {
error = EINVAL;
goto bad;
}
sw = mtod(m, struct sockwakeup *);
sb = (optname == SO_SNDWAKEUP
? &so->so_snd
: &so->so_rcv);
sb->sb_wakeup = sw->sw_pfn;
sb->sb_wakeuparg = sw->sw_arg;
if (sw->sw_pfn)
sb->sb_flags |= SB_ASYNC;
else
sb->sb_flags &=~ SB_ASYNC;
break;
}
default:
error = ENOPROTOOPT;
break;
@@ -1076,6 +1101,23 @@ sogetopt(so, level, optname, mp)
break;
}
case SO_SNDWAKEUP:
case SO_RCVWAKEUP:
{
struct sockbuf *sb;
struct sockwakeup *sw;
/* RTEMS additions. */
sb = (optname == SO_SNDWAKEUP
? &so->so_snd
: &so->so_rcv);
m->m_len = sizeof (struct sockwakeup);
sw = mtod(m, struct sockwakeup *);
sw->sw_pfn = sb->sb_wakeup;
sw->sw_arg = sb->sb_wakeuparg;
break;
}
default:
(void)m_free(m);
return (ENOPROTOOPT);

View File

@@ -345,6 +345,9 @@ sowakeup(so, sb)
sb->sb_flags &= ~SB_WAIT;
rtems_event_send (sb->sb_sel.si_pid, SBWAIT_EVENT);
}
if (sb->sb_wakeup) {
(*sb->sb_wakeup) (so, sb->sb_wakeuparg);
}
}
/*

View File

@@ -37,6 +37,8 @@
#ifndef _SYS_SOCKET_H_
#define _SYS_SOCKET_H_
#include <sys/cdefs.h>
/*
* Definitions related to sockets: types, address families, options.
*/
@@ -78,6 +80,12 @@
#define SO_TYPE 0x1008 /* get socket type */
#define SO_PRIVSTATE 0x1009 /* get/deny privileged state */
/*
* RTEMS addition: get and set wakeup functions.
*/
#define SO_SNDWAKEUP 0x1020 /* wakeup when ready to send */
#define SO_RCVWAKEUP 0x1021 /* wakeup when ready to receive */
/*
* Structure used for manipulating linger option.
*/
@@ -86,6 +94,15 @@ struct linger {
int l_linger; /* linger time */
};
/*
* RTEMS addition: structure used to get and set wakeup function.
*/
struct socket;
struct sockwakeup {
void (*sw_pfn) __P((struct socket *, caddr_t));
caddr_t sw_arg;
};
/*
* Level number for (get/set)sockopt() to apply to socket itself.
*/
@@ -327,8 +344,6 @@ struct omsghdr {
#ifndef KERNEL
#include <sys/cdefs.h>
__BEGIN_DECLS
int accept __P((int, struct sockaddr *, int *));
int bind __P((int, const struct sockaddr *, int));

View File

@@ -89,6 +89,8 @@ struct socket {
struct selinfo sb_sel; /* process selecting read/write */
short sb_flags; /* flags, see below */
u_long sb_timeo; /* timeout for read/write */
void (*sb_wakeup) __P((struct socket *, caddr_t));
caddr_t sb_wakeuparg; /* arg for above */
} so_rcv, so_snd;
#define SB_MAX (256*1024) /* default for max chars in sockbuf */
#define SB_LOCK 0x01 /* lock on data queue */

View File

@@ -979,6 +979,31 @@ sosetopt(so, level, optname, m0)
so->so_state &= ~SS_PRIV;
break;
case SO_SNDWAKEUP:
case SO_RCVWAKEUP:
{
/* RTEMS addition. */
struct sockwakeup *sw;
struct sockbuf *sb;
if (m == NULL
|| m->m_len != sizeof (struct sockwakeup)) {
error = EINVAL;
goto bad;
}
sw = mtod(m, struct sockwakeup *);
sb = (optname == SO_SNDWAKEUP
? &so->so_snd
: &so->so_rcv);
sb->sb_wakeup = sw->sw_pfn;
sb->sb_wakeuparg = sw->sw_arg;
if (sw->sw_pfn)
sb->sb_flags |= SB_ASYNC;
else
sb->sb_flags &=~ SB_ASYNC;
break;
}
default:
error = ENOPROTOOPT;
break;
@@ -1076,6 +1101,23 @@ sogetopt(so, level, optname, mp)
break;
}
case SO_SNDWAKEUP:
case SO_RCVWAKEUP:
{
struct sockbuf *sb;
struct sockwakeup *sw;
/* RTEMS additions. */
sb = (optname == SO_SNDWAKEUP
? &so->so_snd
: &so->so_rcv);
m->m_len = sizeof (struct sockwakeup);
sw = mtod(m, struct sockwakeup *);
sw->sw_pfn = sb->sb_wakeup;
sw->sw_arg = sb->sb_wakeuparg;
break;
}
default:
(void)m_free(m);
return (ENOPROTOOPT);

View File

@@ -345,6 +345,9 @@ sowakeup(so, sb)
sb->sb_flags &= ~SB_WAIT;
rtems_event_send (sb->sb_sel.si_pid, SBWAIT_EVENT);
}
if (sb->sb_wakeup) {
(*sb->sb_wakeup) (so, sb->sb_wakeuparg);
}
}
/*

View File

@@ -37,6 +37,8 @@
#ifndef _SYS_SOCKET_H_
#define _SYS_SOCKET_H_
#include <sys/cdefs.h>
/*
* Definitions related to sockets: types, address families, options.
*/
@@ -78,6 +80,12 @@
#define SO_TYPE 0x1008 /* get socket type */
#define SO_PRIVSTATE 0x1009 /* get/deny privileged state */
/*
* RTEMS addition: get and set wakeup functions.
*/
#define SO_SNDWAKEUP 0x1020 /* wakeup when ready to send */
#define SO_RCVWAKEUP 0x1021 /* wakeup when ready to receive */
/*
* Structure used for manipulating linger option.
*/
@@ -86,6 +94,15 @@ struct linger {
int l_linger; /* linger time */
};
/*
* RTEMS addition: structure used to get and set wakeup function.
*/
struct socket;
struct sockwakeup {
void (*sw_pfn) __P((struct socket *, caddr_t));
caddr_t sw_arg;
};
/*
* Level number for (get/set)sockopt() to apply to socket itself.
*/
@@ -327,8 +344,6 @@ struct omsghdr {
#ifndef KERNEL
#include <sys/cdefs.h>
__BEGIN_DECLS
int accept __P((int, struct sockaddr *, int *));
int bind __P((int, const struct sockaddr *, int));

View File

@@ -89,6 +89,8 @@ struct socket {
struct selinfo sb_sel; /* process selecting read/write */
short sb_flags; /* flags, see below */
u_long sb_timeo; /* timeout for read/write */
void (*sb_wakeup) __P((struct socket *, caddr_t));
caddr_t sb_wakeuparg; /* arg for above */
} so_rcv, so_snd;
#define SB_MAX (256*1024) /* default for max chars in sockbuf */
#define SB_LOCK 0x01 /* lock on data queue */

View File

@@ -979,6 +979,31 @@ sosetopt(so, level, optname, m0)
so->so_state &= ~SS_PRIV;
break;
case SO_SNDWAKEUP:
case SO_RCVWAKEUP:
{
/* RTEMS addition. */
struct sockwakeup *sw;
struct sockbuf *sb;
if (m == NULL
|| m->m_len != sizeof (struct sockwakeup)) {
error = EINVAL;
goto bad;
}
sw = mtod(m, struct sockwakeup *);
sb = (optname == SO_SNDWAKEUP
? &so->so_snd
: &so->so_rcv);
sb->sb_wakeup = sw->sw_pfn;
sb->sb_wakeuparg = sw->sw_arg;
if (sw->sw_pfn)
sb->sb_flags |= SB_ASYNC;
else
sb->sb_flags &=~ SB_ASYNC;
break;
}
default:
error = ENOPROTOOPT;
break;
@@ -1076,6 +1101,23 @@ sogetopt(so, level, optname, mp)
break;
}
case SO_SNDWAKEUP:
case SO_RCVWAKEUP:
{
struct sockbuf *sb;
struct sockwakeup *sw;
/* RTEMS additions. */
sb = (optname == SO_SNDWAKEUP
? &so->so_snd
: &so->so_rcv);
m->m_len = sizeof (struct sockwakeup);
sw = mtod(m, struct sockwakeup *);
sw->sw_pfn = sb->sb_wakeup;
sw->sw_arg = sb->sb_wakeuparg;
break;
}
default:
(void)m_free(m);
return (ENOPROTOOPT);

View File

@@ -345,6 +345,9 @@ sowakeup(so, sb)
sb->sb_flags &= ~SB_WAIT;
rtems_event_send (sb->sb_sel.si_pid, SBWAIT_EVENT);
}
if (sb->sb_wakeup) {
(*sb->sb_wakeup) (so, sb->sb_wakeuparg);
}
}
/*

View File

@@ -37,6 +37,8 @@
#ifndef _SYS_SOCKET_H_
#define _SYS_SOCKET_H_
#include <sys/cdefs.h>
/*
* Definitions related to sockets: types, address families, options.
*/
@@ -78,6 +80,12 @@
#define SO_TYPE 0x1008 /* get socket type */
#define SO_PRIVSTATE 0x1009 /* get/deny privileged state */
/*
* RTEMS addition: get and set wakeup functions.
*/
#define SO_SNDWAKEUP 0x1020 /* wakeup when ready to send */
#define SO_RCVWAKEUP 0x1021 /* wakeup when ready to receive */
/*
* Structure used for manipulating linger option.
*/
@@ -86,6 +94,15 @@ struct linger {
int l_linger; /* linger time */
};
/*
* RTEMS addition: structure used to get and set wakeup function.
*/
struct socket;
struct sockwakeup {
void (*sw_pfn) __P((struct socket *, caddr_t));
caddr_t sw_arg;
};
/*
* Level number for (get/set)sockopt() to apply to socket itself.
*/
@@ -327,8 +344,6 @@ struct omsghdr {
#ifndef KERNEL
#include <sys/cdefs.h>
__BEGIN_DECLS
int accept __P((int, struct sockaddr *, int *));
int bind __P((int, const struct sockaddr *, int));

View File

@@ -89,6 +89,8 @@ struct socket {
struct selinfo sb_sel; /* process selecting read/write */
short sb_flags; /* flags, see below */
u_long sb_timeo; /* timeout for read/write */
void (*sb_wakeup) __P((struct socket *, caddr_t));
caddr_t sb_wakeuparg; /* arg for above */
} so_rcv, so_snd;
#define SB_MAX (256*1024) /* default for max chars in sockbuf */
#define SB_LOCK 0x01 /* lock on data queue */