Browse Source

change socket notifier design

instead of keeping the structures in an opaque array (which was a shadow
of the struct pollfd array if poll() was supported), make them directly
addressable.

this has the advantage that notifier-altering operations (mostly
en-/disabling) don't need to look up the structure by file handle each
time.
on the downside, data locality in the main loop is worse.
neither of these have any real effect on performance.

note that the structures are not allocated separately, but embedded into
the the parent structure (like sockets already were).
wip/server-refactor
Oswald Buddenhagen 10 years ago
parent
commit
1fd66195d8
  1. 21
      src/common.h
  2. 20
      src/socket.c
  3. 2
      src/socket.h
  4. 136
      src/util.c

21
src/common.h

@ -127,6 +127,18 @@ uchar arc4_getbyte( void );
int bucketsForSize( int size );
typedef struct notifier {
struct notifier *next;
void (*cb)( int what, void *aux );
void *aux;
#ifdef HAVE_SYS_POLL_H
int index;
#else
int fd, events;
#endif
int faked;
} notifier_t;
#ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
#else
@ -135,10 +147,11 @@ int bucketsForSize( int size );
# define POLLERR 8
#endif
void add_fd( int fd, void (*cb)( int events, void *aux ), void *aux );
void conf_fd( int fd, int and_events, int or_events );
void fake_fd( int fd, int events );
void del_fd( int fd );
void init_notifier( notifier_t *sn, int fd, void (*cb)( int, void * ), void *aux );
void conf_notifier( notifier_t *sn, int and_events, int or_events );
static INLINE void fake_notifier( notifier_t *sn, int events ) { sn->faked |= events; }
void wipe_notifier( notifier_t *sn );
void main_loop( void );
#endif

20
src/socket.c

@ -67,7 +67,7 @@ ssl_return( const char *func, conn_t *conn, int ret )
case SSL_ERROR_NONE:
return ret;
case SSL_ERROR_WANT_WRITE:
conf_fd( conn->fd, POLLIN, POLLOUT );
conf_notifier( &conn->notify, POLLIN, POLLOUT );
/* fallthrough */
case SSL_ERROR_WANT_READ:
return 0;
@ -290,13 +290,13 @@ socket_open_internal( conn_t *sock, int fd )
{
sock->fd = fd;
fcntl( fd, F_SETFL, O_NONBLOCK );
add_fd( fd, socket_fd_cb, sock );
init_notifier( &sock->notify, fd, socket_fd_cb, sock );
}
static void
socket_close_internal( conn_t *sock )
{
del_fd( sock->fd );
wipe_notifier( &sock->notify );
close( sock->fd );
sock->fd = -1;
}
@ -434,7 +434,7 @@ socket_connect_one( conn_t *sock )
socket_connect_failed( sock );
return;
}
conf_fd( s, 0, POLLOUT );
conf_notifier( &sock->notify, 0, POLLOUT );
sock->state = SCK_CONNECTING;
info( "\v\n" );
return;
@ -464,7 +464,7 @@ socket_connected( conn_t *conn )
#ifdef HAVE_IPV6
freeaddrinfo( conn->addrs );
#endif
conf_fd( conn->fd, 0, POLLIN );
conf_notifier( &conn->notify, 0, POLLIN );
conn->state = SCK_READY;
conn->callbacks.connect( 1, conn->callback_aux );
}
@ -517,7 +517,7 @@ socket_fill( conn_t *sock )
if ((n = ssl_return( "read from", sock, SSL_read( sock->ssl, buf, len ) )) <= 0)
return;
if (n == len && SSL_pending( sock->ssl ))
fake_fd( sock->fd, POLLIN );
fake_notifier( &sock->notify, POLLIN );
} else
#endif
{
@ -592,10 +592,10 @@ do_write( conn_t *sock, char *buf, int len )
socket_fail( sock );
} else {
n = 0;
conf_fd( sock->fd, POLLIN, POLLOUT );
conf_notifier( &sock->notify, POLLIN, POLLOUT );
}
} else if (n != len) {
conf_fd( sock->fd, POLLIN, POLLOUT );
conf_notifier( &sock->notify, POLLIN, POLLOUT );
}
return n;
}
@ -632,7 +632,7 @@ do_queued_write( conn_t *conn )
}
#ifdef HAVE_LIBSSL
if (conn->ssl && SSL_pending( conn->ssl ))
fake_fd( conn->fd, POLLIN );
fake_notifier( &conn->notify, POLLIN );
#endif
return conn->write_callback( conn->callback_aux );
}
@ -700,7 +700,7 @@ socket_fd_cb( int events, void *aux )
}
if (events & POLLOUT)
conf_fd( conn->fd, POLLIN, 0 );
conf_notifier( &conn->notify, POLLIN, 0 );
#ifdef HAVE_LIBSSL
if (conn->state == SCK_STARTTLS) {

2
src/socket.h

@ -86,6 +86,8 @@ typedef struct {
} callbacks;
void *callback_aux;
notifier_t notify;
/* writing */
buff_chunk_t *write_buf, **write_buf_append; /* buffer head & tail */
int write_offset; /* offset into buffer head */

136
src/util.c

@ -584,84 +584,73 @@ bucketsForSize( int size )
}
}
static notifier_t *notifiers;
static int changed; /* Iterator may be invalid now. */
#ifdef HAVE_SYS_POLL_H
static struct pollfd *pollfds;
static int npolls, rpolls;
#else
# ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
# endif
# define pollfds fdparms
#endif
static struct {
void (*cb)( int what, void *aux );
void *aux;
#ifndef HAVE_SYS_POLL_H
int fd, events;
#endif
int faked;
} *fdparms;
static int npolls, rpolls, changed;
static int
find_fd( int fd )
{
int n;
for (n = 0; n < npolls; n++)
if (pollfds[n].fd == fd)
return n;
return -1;
}
void
add_fd( int fd, void (*cb)( int events, void *aux ), void *aux )
init_notifier( notifier_t *sn, int fd, void (*cb)( int, void * ), void *aux )
{
int n;
assert( find_fd( fd ) < 0 );
n = npolls++;
#ifdef HAVE_SYS_POLL_H
int idx = npolls++;
if (rpolls < npolls) {
rpolls = npolls;
#ifdef HAVE_SYS_POLL_H
pollfds = nfrealloc(pollfds, npolls * sizeof(*pollfds));
#endif
fdparms = nfrealloc(fdparms, npolls * sizeof(*fdparms));
pollfds = nfrealloc( pollfds, npolls * sizeof(*pollfds) );
}
pollfds[n].fd = fd;
pollfds[n].events = 0; /* POLLERR & POLLHUP implicit */
fdparms[n].faked = 0;
fdparms[n].cb = cb;
fdparms[n].aux = aux;
changed = 1;
}
void
conf_fd( int fd, int and_events, int or_events )
{
int n = find_fd( fd );
assert( n >= 0 );
pollfds[n].events = (pollfds[n].events & and_events) | or_events;
pollfds[idx].fd = fd;
pollfds[idx].events = 0; /* POLLERR & POLLHUP implicit */
sn->index = idx;
#else
sn->fd = fd;
sn->events = 0;
#endif
sn->cb = cb;
sn->aux = aux;
sn->faked = 0;
sn->next = notifiers;
notifiers = sn;
}
void
fake_fd( int fd, int events )
conf_notifier( notifier_t *sn, int and_events, int or_events )
{
int n = find_fd( fd );
assert( n >= 0 );
fdparms[n].faked |= events;
#ifdef HAVE_SYS_POLL_H
int idx = sn->index;
pollfds[idx].events = (pollfds[idx].events & and_events) | or_events;
#else
sn->events = (sn->events & and_events) | or_events;
#endif
}
void
del_fd( int fd )
wipe_notifier( notifier_t *sn )
{
int n = find_fd( fd );
assert( n >= 0 );
npolls--;
notifier_t **snp;
#ifdef HAVE_SYS_POLL_H
memmove(pollfds + n, pollfds + n + 1, (npolls - n) * sizeof(*pollfds));
int idx;
#endif
memmove(fdparms + n, fdparms + n + 1, (npolls - n) * sizeof(*fdparms));
for (snp = &notifiers; *snp != sn; snp = &(*snp)->next)
assert( *snp );
*snp = sn->next;
sn->next = 0;
changed = 1;
#ifdef HAVE_SYS_POLL_H
idx = sn->index;
memmove( pollfds + idx, pollfds + idx + 1, (--npolls - idx) * sizeof(*pollfds) );
for (sn = notifiers; sn; sn = sn->next) {
if (sn->index > idx)
sn->index--;
}
#endif
}
#define shifted_bit(in, from, to) \
@ -672,12 +661,13 @@ del_fd( int fd )
static void
event_wait( void )
{
int m, n;
notifier_t *sn;
int m;
#ifdef HAVE_SYS_POLL_H
int timeout = -1;
for (n = 0; n < npolls; n++)
if (fdparms[n].faked) {
for (sn = notifiers; sn; sn = sn->next)
if (sn->faked) {
timeout = 0;
break;
}
@ -685,16 +675,18 @@ event_wait( void )
perror( "poll() failed in event loop" );
abort();
}
for (n = 0; n < npolls; n++)
if ((m = pollfds[n].revents | fdparms[n].faked)) {
for (sn = notifiers; sn; sn = sn->next) {
int n = sn->index;
if ((m = pollfds[n].revents | sn->faked)) {
assert( !(m & POLLNVAL) );
fdparms[n].faked = 0;
fdparms[n].cb( m | shifted_bit( m, POLLHUP, POLLIN ), fdparms[n].aux );
sn->faked = 0;
sn->cb( m | shifted_bit( m, POLLHUP, POLLIN ), sn->aux );
if (changed) {
changed = 0;
break;
}
}
}
#else
struct timeval *timeout = 0;
static struct timeval null_tv;
@ -705,13 +697,13 @@ event_wait( void )
FD_ZERO( &wfds );
FD_ZERO( &efds );
m = -1;
for (n = 0; n < npolls; n++) {
if (fdparms[n].faked)
for (sn = notifiers; sn; sn = sn->next) {
if (sn->faked)
timeout = &null_tv;
fd = fdparms[n].fd;
if (fdparms[n].events & POLLIN)
fd = sn->fd;
if (sn->events & POLLIN)
FD_SET( fd, &rfds );
if (fdparms[n].events & POLLOUT)
if (sn->events & POLLOUT)
FD_SET( fd, &wfds );
FD_SET( fd, &efds );
if (fd > m)
@ -721,9 +713,9 @@ event_wait( void )
perror( "select() failed in event loop" );
abort();
}
for (n = 0; n < npolls; n++) {
fd = fdparms[n].fd;
m = fdparms[n].faked;
for (sn = notifiers; sn; sn = sn->next) {
fd = sn->fd;
m = sn->faked;
if (FD_ISSET( fd, &rfds ))
m |= POLLIN;
if (FD_ISSET( fd, &wfds ))
@ -731,8 +723,8 @@ event_wait( void )
if (FD_ISSET( fd, &efds ))
m |= POLLERR;
if (m) {
fdparms[n].faked = 0;
fdparms[n].cb( m, fdparms[n].aux );
sn->faked = 0;
sn->cb( m, sn->aux );
if (changed) {
changed = 0;
break;
@ -745,6 +737,6 @@ event_wait( void )
void
main_loop( void )
{
while (npolls)
while (notifiers)
event_wait();
}

Loading…
Cancel
Save