slirp: replace global polling with per-instance & notifier
Remove hard-coded dependency on slirp in main-loop, and use a "poll" notifier instead. The notifier is registered per slirp instance. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
This commit is contained in:
parent
625a526b32
commit
1ab67b98cd
|
@ -302,4 +302,19 @@ void qemu_fd_register(int fd);
|
||||||
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
|
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
|
||||||
void qemu_bh_schedule_idle(QEMUBH *bh);
|
void qemu_bh_schedule_idle(QEMUBH *bh);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAIN_LOOP_POLL_FILL,
|
||||||
|
MAIN_LOOP_POLL_ERR,
|
||||||
|
MAIN_LOOP_POLL_OK,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct MainLoopPoll {
|
||||||
|
int state;
|
||||||
|
uint32_t timeout;
|
||||||
|
GArray *pollfds;
|
||||||
|
} MainLoopPoll;
|
||||||
|
|
||||||
|
void main_loop_poll_add_notifier(Notifier *notify);
|
||||||
|
void main_loop_poll_remove_notifier(Notifier *notify);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
24
net/slirp.c
24
net/slirp.c
|
@ -86,6 +86,7 @@ typedef struct SlirpState {
|
||||||
NetClientState nc;
|
NetClientState nc;
|
||||||
QTAILQ_ENTRY(SlirpState) entry;
|
QTAILQ_ENTRY(SlirpState) entry;
|
||||||
Slirp *slirp;
|
Slirp *slirp;
|
||||||
|
Notifier poll_notifier;
|
||||||
Notifier exit_notifier;
|
Notifier exit_notifier;
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
gchar *smb_dir;
|
gchar *smb_dir;
|
||||||
|
@ -144,6 +145,7 @@ static void net_slirp_cleanup(NetClientState *nc)
|
||||||
SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
|
SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
|
||||||
|
|
||||||
g_slist_free_full(s->fwd, slirp_free_fwd);
|
g_slist_free_full(s->fwd, slirp_free_fwd);
|
||||||
|
main_loop_poll_remove_notifier(&s->poll_notifier);
|
||||||
slirp_cleanup(s->slirp);
|
slirp_cleanup(s->slirp);
|
||||||
if (s->exit_notifier.notify) {
|
if (s->exit_notifier.notify) {
|
||||||
qemu_remove_exit_notifier(&s->exit_notifier);
|
qemu_remove_exit_notifier(&s->exit_notifier);
|
||||||
|
@ -209,6 +211,25 @@ static const SlirpCb slirp_cb = {
|
||||||
.notify = qemu_notify_event,
|
.notify = qemu_notify_event,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void net_slirp_poll_notify(Notifier *notifier, void *data)
|
||||||
|
{
|
||||||
|
MainLoopPoll *poll = data;
|
||||||
|
SlirpState *s = container_of(notifier, SlirpState, poll_notifier);
|
||||||
|
|
||||||
|
switch (poll->state) {
|
||||||
|
case MAIN_LOOP_POLL_FILL:
|
||||||
|
slirp_pollfds_fill(s->slirp, poll->pollfds, &poll->timeout);
|
||||||
|
break;
|
||||||
|
case MAIN_LOOP_POLL_OK:
|
||||||
|
case MAIN_LOOP_POLL_ERR:
|
||||||
|
slirp_pollfds_poll(s->slirp, poll->pollfds,
|
||||||
|
poll->state == MAIN_LOOP_POLL_ERR);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int net_slirp_init(NetClientState *peer, const char *model,
|
static int net_slirp_init(NetClientState *peer, const char *model,
|
||||||
const char *name, int restricted,
|
const char *name, int restricted,
|
||||||
bool ipv4, const char *vnetwork, const char *vhost,
|
bool ipv4, const char *vnetwork, const char *vhost,
|
||||||
|
@ -429,6 +450,9 @@ static int net_slirp_init(NetClientState *peer, const char *model,
|
||||||
&slirp_cb, s);
|
&slirp_cb, s);
|
||||||
QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
|
QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
|
||||||
|
|
||||||
|
s->poll_notifier.notify = net_slirp_poll_notify;
|
||||||
|
main_loop_poll_add_notifier(&s->poll_notifier);
|
||||||
|
|
||||||
for (config = slirp_configs; config; config = config->next) {
|
for (config = slirp_configs; config; config = config->next) {
|
||||||
if (config->flags & SLIRP_CFG_HOSTFWD) {
|
if (config->flags & SLIRP_CFG_HOSTFWD) {
|
||||||
if (slirp_hostfwd(s, config->str, errp) < 0) {
|
if (slirp_hostfwd(s, config->str, errp) < 0) {
|
||||||
|
|
|
@ -63,9 +63,9 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
|
||||||
void *opaque);
|
void *opaque);
|
||||||
void slirp_cleanup(Slirp *slirp);
|
void slirp_cleanup(Slirp *slirp);
|
||||||
|
|
||||||
void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout);
|
void slirp_pollfds_fill(Slirp *slirp, GArray *pollfds, uint32_t *timeout);
|
||||||
|
|
||||||
void slirp_pollfds_poll(GArray *pollfds, int select_error);
|
void slirp_pollfds_poll(Slirp *slirp, GArray *pollfds, int select_error);
|
||||||
|
|
||||||
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
|
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
|
||||||
|
|
||||||
|
|
637
slirp/slirp.c
637
slirp/slirp.c
|
@ -368,9 +368,8 @@ void slirp_cleanup(Slirp *slirp)
|
||||||
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
|
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
|
||||||
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
|
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
|
||||||
|
|
||||||
static void slirp_update_timeout(uint32_t *timeout)
|
static void slirp_update_timeout(Slirp *slirp, uint32_t *timeout)
|
||||||
{
|
{
|
||||||
Slirp *slirp;
|
|
||||||
uint32_t t;
|
uint32_t t;
|
||||||
|
|
||||||
if (*timeout <= TIMEOUT_FAST) {
|
if (*timeout <= TIMEOUT_FAST) {
|
||||||
|
@ -382,370 +381,352 @@ static void slirp_update_timeout(uint32_t *timeout)
|
||||||
/* If we have tcp timeout with slirp, then we will fill @timeout with
|
/* If we have tcp timeout with slirp, then we will fill @timeout with
|
||||||
* more precise value.
|
* more precise value.
|
||||||
*/
|
*/
|
||||||
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
|
if (slirp->time_fasttimo) {
|
||||||
if (slirp->time_fasttimo) {
|
*timeout = TIMEOUT_FAST;
|
||||||
*timeout = TIMEOUT_FAST;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
if (slirp->do_slowtimo) {
|
||||||
if (slirp->do_slowtimo) {
|
t = MIN(TIMEOUT_SLOW, t);
|
||||||
t = MIN(TIMEOUT_SLOW, t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*timeout = t;
|
*timeout = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
|
void slirp_pollfds_fill(Slirp *slirp, GArray *pollfds, uint32_t *timeout)
|
||||||
{
|
{
|
||||||
Slirp *slirp;
|
|
||||||
struct socket *so, *so_next;
|
struct socket *so, *so_next;
|
||||||
|
|
||||||
if (QTAILQ_EMPTY(&slirp_instances)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First, TCP sockets
|
* First, TCP sockets
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
|
/*
|
||||||
/*
|
* *_slowtimo needs calling if there are IP fragments
|
||||||
* *_slowtimo needs calling if there are IP fragments
|
* in the fragment queue, or there are TCP connections active
|
||||||
* in the fragment queue, or there are TCP connections active
|
*/
|
||||||
*/
|
slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
|
||||||
slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
|
(&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
|
||||||
(&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
|
|
||||||
|
|
||||||
|
for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) {
|
||||||
|
int events = 0;
|
||||||
|
|
||||||
|
so_next = so->so_next;
|
||||||
|
|
||||||
|
so->pollfds_idx = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if we need a tcp_fasttimo
|
||||||
|
*/
|
||||||
|
if (slirp->time_fasttimo == 0 &&
|
||||||
|
so->so_tcpcb->t_flags & TF_DELACK) {
|
||||||
|
slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOFDREF can include still connecting to local-host,
|
||||||
|
* newly socreated() sockets etc. Don't want to select these.
|
||||||
|
*/
|
||||||
|
if (so->so_state & SS_NOFDREF || so->s == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set for reading sockets which are accepting
|
||||||
|
*/
|
||||||
|
if (so->so_state & SS_FACCEPTCONN) {
|
||||||
|
GPollFD pfd = {
|
||||||
|
.fd = so->s,
|
||||||
|
.events = G_IO_IN | G_IO_HUP | G_IO_ERR,
|
||||||
|
};
|
||||||
|
so->pollfds_idx = pollfds->len;
|
||||||
|
g_array_append_val(pollfds, pfd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set for writing sockets which are connecting
|
||||||
|
*/
|
||||||
|
if (so->so_state & SS_ISFCONNECTING) {
|
||||||
|
GPollFD pfd = {
|
||||||
|
.fd = so->s,
|
||||||
|
.events = G_IO_OUT | G_IO_ERR,
|
||||||
|
};
|
||||||
|
so->pollfds_idx = pollfds->len;
|
||||||
|
g_array_append_val(pollfds, pfd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set for writing if we are connected, can send more, and
|
||||||
|
* we have something to send
|
||||||
|
*/
|
||||||
|
if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
|
||||||
|
events |= G_IO_OUT | G_IO_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set for reading (and urgent data) if we are connected, can
|
||||||
|
* receive more, and we have room for it XXX /2 ?
|
||||||
|
*/
|
||||||
|
if (CONN_CANFRCV(so) &&
|
||||||
|
(so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
|
||||||
|
events |= G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events) {
|
||||||
|
GPollFD pfd = {
|
||||||
|
.fd = so->s,
|
||||||
|
.events = events,
|
||||||
|
};
|
||||||
|
so->pollfds_idx = pollfds->len;
|
||||||
|
g_array_append_val(pollfds, pfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UDP sockets
|
||||||
|
*/
|
||||||
|
for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
|
||||||
|
so_next = so->so_next;
|
||||||
|
|
||||||
|
so->pollfds_idx = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if it's timed out
|
||||||
|
*/
|
||||||
|
if (so->so_expire) {
|
||||||
|
if (so->so_expire <= curtime) {
|
||||||
|
udp_detach(so);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
slirp->do_slowtimo = true; /* Let socket expire */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When UDP packets are received from over the
|
||||||
|
* link, they're sendto()'d straight away, so
|
||||||
|
* no need for setting for writing
|
||||||
|
* Limit the number of packets queued by this session
|
||||||
|
* to 4. Note that even though we try and limit this
|
||||||
|
* to 4 packets, the session could have more queued
|
||||||
|
* if the packets needed to be fragmented
|
||||||
|
* (XXX <= 4 ?)
|
||||||
|
*/
|
||||||
|
if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
|
||||||
|
GPollFD pfd = {
|
||||||
|
.fd = so->s,
|
||||||
|
.events = G_IO_IN | G_IO_HUP | G_IO_ERR,
|
||||||
|
};
|
||||||
|
so->pollfds_idx = pollfds->len;
|
||||||
|
g_array_append_val(pollfds, pfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ICMP sockets
|
||||||
|
*/
|
||||||
|
for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
|
||||||
|
so_next = so->so_next;
|
||||||
|
|
||||||
|
so->pollfds_idx = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if it's timed out
|
||||||
|
*/
|
||||||
|
if (so->so_expire) {
|
||||||
|
if (so->so_expire <= curtime) {
|
||||||
|
icmp_detach(so);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
slirp->do_slowtimo = true; /* Let socket expire */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (so->so_state & SS_ISFCONNECTED) {
|
||||||
|
GPollFD pfd = {
|
||||||
|
.fd = so->s,
|
||||||
|
.events = G_IO_IN | G_IO_HUP | G_IO_ERR,
|
||||||
|
};
|
||||||
|
so->pollfds_idx = pollfds->len;
|
||||||
|
g_array_append_val(pollfds, pfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slirp_update_timeout(slirp, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void slirp_pollfds_poll(Slirp *slirp, GArray *pollfds, int select_error)
|
||||||
|
{
|
||||||
|
struct socket *so, *so_next;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
curtime = slirp->cb->clock_get_ns() / SCALE_MS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if anything has timed out
|
||||||
|
*/
|
||||||
|
if (slirp->time_fasttimo &&
|
||||||
|
((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) {
|
||||||
|
tcp_fasttimo(slirp);
|
||||||
|
slirp->time_fasttimo = 0;
|
||||||
|
}
|
||||||
|
if (slirp->do_slowtimo &&
|
||||||
|
((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) {
|
||||||
|
ip_slowtimo(slirp);
|
||||||
|
tcp_slowtimo(slirp);
|
||||||
|
slirp->last_slowtimo = curtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check sockets
|
||||||
|
*/
|
||||||
|
if (!select_error) {
|
||||||
|
/*
|
||||||
|
* Check TCP sockets
|
||||||
|
*/
|
||||||
for (so = slirp->tcb.so_next; so != &slirp->tcb;
|
for (so = slirp->tcb.so_next; so != &slirp->tcb;
|
||||||
so = so_next) {
|
so = so_next) {
|
||||||
int events = 0;
|
int revents;
|
||||||
|
|
||||||
so_next = so->so_next;
|
so_next = so->so_next;
|
||||||
|
|
||||||
so->pollfds_idx = -1;
|
revents = 0;
|
||||||
|
if (so->pollfds_idx != -1) {
|
||||||
/*
|
revents = g_array_index(pollfds, GPollFD,
|
||||||
* See if we need a tcp_fasttimo
|
so->pollfds_idx).revents;
|
||||||
*/
|
|
||||||
if (slirp->time_fasttimo == 0 &&
|
|
||||||
so->so_tcpcb->t_flags & TF_DELACK) {
|
|
||||||
slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* NOFDREF can include still connecting to local-host,
|
|
||||||
* newly socreated() sockets etc. Don't want to select these.
|
|
||||||
*/
|
|
||||||
if (so->so_state & SS_NOFDREF || so->s == -1) {
|
if (so->so_state & SS_NOFDREF || so->s == -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set for reading sockets which are accepting
|
* Check for URG data
|
||||||
|
* This will soread as well, so no need to
|
||||||
|
* test for G_IO_IN below if this succeeds
|
||||||
*/
|
*/
|
||||||
if (so->so_state & SS_FACCEPTCONN) {
|
if (revents & G_IO_PRI) {
|
||||||
GPollFD pfd = {
|
ret = sorecvoob(so);
|
||||||
.fd = so->s,
|
if (ret < 0) {
|
||||||
.events = G_IO_IN | G_IO_HUP | G_IO_ERR,
|
/* Socket error might have resulted in the socket being
|
||||||
};
|
* removed, do not try to do anything more with it. */
|
||||||
so->pollfds_idx = pollfds->len;
|
|
||||||
g_array_append_val(pollfds, pfd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set for writing sockets which are connecting
|
|
||||||
*/
|
|
||||||
if (so->so_state & SS_ISFCONNECTING) {
|
|
||||||
GPollFD pfd = {
|
|
||||||
.fd = so->s,
|
|
||||||
.events = G_IO_OUT | G_IO_ERR,
|
|
||||||
};
|
|
||||||
so->pollfds_idx = pollfds->len;
|
|
||||||
g_array_append_val(pollfds, pfd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set for writing if we are connected, can send more, and
|
|
||||||
* we have something to send
|
|
||||||
*/
|
|
||||||
if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
|
|
||||||
events |= G_IO_OUT | G_IO_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set for reading (and urgent data) if we are connected, can
|
|
||||||
* receive more, and we have room for it XXX /2 ?
|
|
||||||
*/
|
|
||||||
if (CONN_CANFRCV(so) &&
|
|
||||||
(so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
|
|
||||||
events |= G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (events) {
|
|
||||||
GPollFD pfd = {
|
|
||||||
.fd = so->s,
|
|
||||||
.events = events,
|
|
||||||
};
|
|
||||||
so->pollfds_idx = pollfds->len;
|
|
||||||
g_array_append_val(pollfds, pfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* UDP sockets
|
|
||||||
*/
|
|
||||||
for (so = slirp->udb.so_next; so != &slirp->udb;
|
|
||||||
so = so_next) {
|
|
||||||
so_next = so->so_next;
|
|
||||||
|
|
||||||
so->pollfds_idx = -1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* See if it's timed out
|
|
||||||
*/
|
|
||||||
if (so->so_expire) {
|
|
||||||
if (so->so_expire <= curtime) {
|
|
||||||
udp_detach(so);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
slirp->do_slowtimo = true; /* Let socket expire */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When UDP packets are received from over the
|
|
||||||
* link, they're sendto()'d straight away, so
|
|
||||||
* no need for setting for writing
|
|
||||||
* Limit the number of packets queued by this session
|
|
||||||
* to 4. Note that even though we try and limit this
|
|
||||||
* to 4 packets, the session could have more queued
|
|
||||||
* if the packets needed to be fragmented
|
|
||||||
* (XXX <= 4 ?)
|
|
||||||
*/
|
|
||||||
if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
|
|
||||||
GPollFD pfd = {
|
|
||||||
.fd = so->s,
|
|
||||||
.events = G_IO_IN | G_IO_HUP | G_IO_ERR,
|
|
||||||
};
|
|
||||||
so->pollfds_idx = pollfds->len;
|
|
||||||
g_array_append_val(pollfds, pfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ICMP sockets
|
|
||||||
*/
|
|
||||||
for (so = slirp->icmp.so_next; so != &slirp->icmp;
|
|
||||||
so = so_next) {
|
|
||||||
so_next = so->so_next;
|
|
||||||
|
|
||||||
so->pollfds_idx = -1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* See if it's timed out
|
|
||||||
*/
|
|
||||||
if (so->so_expire) {
|
|
||||||
if (so->so_expire <= curtime) {
|
|
||||||
icmp_detach(so);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
slirp->do_slowtimo = true; /* Let socket expire */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (so->so_state & SS_ISFCONNECTED) {
|
|
||||||
GPollFD pfd = {
|
|
||||||
.fd = so->s,
|
|
||||||
.events = G_IO_IN | G_IO_HUP | G_IO_ERR,
|
|
||||||
};
|
|
||||||
so->pollfds_idx = pollfds->len;
|
|
||||||
g_array_append_val(pollfds, pfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slirp_update_timeout(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void slirp_pollfds_poll(GArray *pollfds, int select_error)
|
|
||||||
{
|
|
||||||
Slirp *slirp = QTAILQ_FIRST(&slirp_instances);
|
|
||||||
struct socket *so, *so_next;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!slirp) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
curtime = slirp->cb->clock_get_ns() / SCALE_MS;
|
|
||||||
|
|
||||||
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
|
|
||||||
/*
|
|
||||||
* See if anything has timed out
|
|
||||||
*/
|
|
||||||
if (slirp->time_fasttimo &&
|
|
||||||
((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) {
|
|
||||||
tcp_fasttimo(slirp);
|
|
||||||
slirp->time_fasttimo = 0;
|
|
||||||
}
|
|
||||||
if (slirp->do_slowtimo &&
|
|
||||||
((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) {
|
|
||||||
ip_slowtimo(slirp);
|
|
||||||
tcp_slowtimo(slirp);
|
|
||||||
slirp->last_slowtimo = curtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check sockets
|
|
||||||
*/
|
|
||||||
if (!select_error) {
|
|
||||||
/*
|
|
||||||
* Check TCP sockets
|
|
||||||
*/
|
|
||||||
for (so = slirp->tcb.so_next; so != &slirp->tcb;
|
|
||||||
so = so_next) {
|
|
||||||
int revents;
|
|
||||||
|
|
||||||
so_next = so->so_next;
|
|
||||||
|
|
||||||
revents = 0;
|
|
||||||
if (so->pollfds_idx != -1) {
|
|
||||||
revents = g_array_index(pollfds, GPollFD,
|
|
||||||
so->pollfds_idx).revents;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (so->so_state & SS_NOFDREF || so->s == -1) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check sockets for reading
|
||||||
|
*/
|
||||||
|
else if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
|
||||||
/*
|
/*
|
||||||
* Check for URG data
|
* Check for incoming connections
|
||||||
* This will soread as well, so no need to
|
|
||||||
* test for G_IO_IN below if this succeeds
|
|
||||||
*/
|
*/
|
||||||
if (revents & G_IO_PRI) {
|
if (so->so_state & SS_FACCEPTCONN) {
|
||||||
ret = sorecvoob(so);
|
tcp_connect(so);
|
||||||
|
continue;
|
||||||
|
} /* else */
|
||||||
|
ret = soread(so);
|
||||||
|
|
||||||
|
/* Output it if we read something */
|
||||||
|
if (ret > 0) {
|
||||||
|
tcp_output(sototcpcb(so));
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
/* Socket error might have resulted in the socket being
|
||||||
|
* removed, do not try to do anything more with it. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check sockets for writing
|
||||||
|
*/
|
||||||
|
if (!(so->so_state & SS_NOFDREF) &&
|
||||||
|
(revents & (G_IO_OUT | G_IO_ERR))) {
|
||||||
|
/*
|
||||||
|
* Check for non-blocking, still-connecting sockets
|
||||||
|
*/
|
||||||
|
if (so->so_state & SS_ISFCONNECTING) {
|
||||||
|
/* Connected */
|
||||||
|
so->so_state &= ~SS_ISFCONNECTING;
|
||||||
|
|
||||||
|
ret = send(so->s, (const void *) &ret, 0, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/* Socket error might have resulted in the socket being
|
/* XXXXX Must fix, zero bytes is a NOP */
|
||||||
* removed, do not try to do anything more with it. */
|
if (errno == EAGAIN || errno == EWOULDBLOCK ||
|
||||||
continue;
|
errno == EINPROGRESS || errno == ENOTCONN) {
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Check sockets for reading
|
|
||||||
*/
|
|
||||||
else if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
|
|
||||||
/*
|
|
||||||
* Check for incoming connections
|
|
||||||
*/
|
|
||||||
if (so->so_state & SS_FACCEPTCONN) {
|
|
||||||
tcp_connect(so);
|
|
||||||
continue;
|
|
||||||
} /* else */
|
|
||||||
ret = soread(so);
|
|
||||||
|
|
||||||
/* Output it if we read something */
|
/* else failed */
|
||||||
|
so->so_state &= SS_PERSISTENT_MASK;
|
||||||
|
so->so_state |= SS_NOFDREF;
|
||||||
|
}
|
||||||
|
/* else so->so_state &= ~SS_ISFCONNECTING; */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Continue tcp_input
|
||||||
|
*/
|
||||||
|
tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
|
||||||
|
so->so_ffamily);
|
||||||
|
/* continue; */
|
||||||
|
} else {
|
||||||
|
ret = sowrite(so);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
|
/* Call tcp_output in case we need to send a window
|
||||||
|
* update to the guest, otherwise it will be stuck
|
||||||
|
* until it sends a window probe. */
|
||||||
tcp_output(sototcpcb(so));
|
tcp_output(sototcpcb(so));
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
|
||||||
/* Socket error might have resulted in the socket being
|
|
||||||
* removed, do not try to do anything more with it. */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check sockets for writing
|
|
||||||
*/
|
|
||||||
if (!(so->so_state & SS_NOFDREF) &&
|
|
||||||
(revents & (G_IO_OUT | G_IO_ERR))) {
|
|
||||||
/*
|
|
||||||
* Check for non-blocking, still-connecting sockets
|
|
||||||
*/
|
|
||||||
if (so->so_state & SS_ISFCONNECTING) {
|
|
||||||
/* Connected */
|
|
||||||
so->so_state &= ~SS_ISFCONNECTING;
|
|
||||||
|
|
||||||
ret = send(so->s, (const void *) &ret, 0, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
/* XXXXX Must fix, zero bytes is a NOP */
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK ||
|
|
||||||
errno == EINPROGRESS || errno == ENOTCONN) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* else failed */
|
|
||||||
so->so_state &= SS_PERSISTENT_MASK;
|
|
||||||
so->so_state |= SS_NOFDREF;
|
|
||||||
}
|
|
||||||
/* else so->so_state &= ~SS_ISFCONNECTING; */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Continue tcp_input
|
|
||||||
*/
|
|
||||||
tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
|
|
||||||
so->so_ffamily);
|
|
||||||
/* continue; */
|
|
||||||
} else {
|
|
||||||
ret = sowrite(so);
|
|
||||||
if (ret > 0) {
|
|
||||||
/* Call tcp_output in case we need to send a window
|
|
||||||
* update to the guest, otherwise it will be stuck
|
|
||||||
* until it sends a window probe. */
|
|
||||||
tcp_output(sototcpcb(so));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now UDP sockets.
|
|
||||||
* Incoming packets are sent straight away, they're not buffered.
|
|
||||||
* Incoming UDP data isn't buffered either.
|
|
||||||
*/
|
|
||||||
for (so = slirp->udb.so_next; so != &slirp->udb;
|
|
||||||
so = so_next) {
|
|
||||||
int revents;
|
|
||||||
|
|
||||||
so_next = so->so_next;
|
|
||||||
|
|
||||||
revents = 0;
|
|
||||||
if (so->pollfds_idx != -1) {
|
|
||||||
revents = g_array_index(pollfds, GPollFD,
|
|
||||||
so->pollfds_idx).revents;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (so->s != -1 &&
|
|
||||||
(revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
|
|
||||||
sorecvfrom(so);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check incoming ICMP relies.
|
|
||||||
*/
|
|
||||||
for (so = slirp->icmp.so_next; so != &slirp->icmp;
|
|
||||||
so = so_next) {
|
|
||||||
int revents;
|
|
||||||
|
|
||||||
so_next = so->so_next;
|
|
||||||
|
|
||||||
revents = 0;
|
|
||||||
if (so->pollfds_idx != -1) {
|
|
||||||
revents = g_array_index(pollfds, GPollFD,
|
|
||||||
so->pollfds_idx).revents;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (so->s != -1 &&
|
|
||||||
(revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
|
|
||||||
icmp_receive(so);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if_start(slirp);
|
/*
|
||||||
|
* Now UDP sockets.
|
||||||
|
* Incoming packets are sent straight away, they're not buffered.
|
||||||
|
* Incoming UDP data isn't buffered either.
|
||||||
|
*/
|
||||||
|
for (so = slirp->udb.so_next; so != &slirp->udb;
|
||||||
|
so = so_next) {
|
||||||
|
int revents;
|
||||||
|
|
||||||
|
so_next = so->so_next;
|
||||||
|
|
||||||
|
revents = 0;
|
||||||
|
if (so->pollfds_idx != -1) {
|
||||||
|
revents = g_array_index(pollfds, GPollFD,
|
||||||
|
so->pollfds_idx).revents;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (so->s != -1 &&
|
||||||
|
(revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
|
||||||
|
sorecvfrom(so);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check incoming ICMP relies.
|
||||||
|
*/
|
||||||
|
for (so = slirp->icmp.so_next; so != &slirp->icmp;
|
||||||
|
so = so_next) {
|
||||||
|
int revents;
|
||||||
|
|
||||||
|
so_next = so->so_next;
|
||||||
|
|
||||||
|
revents = 0;
|
||||||
|
if (so->pollfds_idx != -1) {
|
||||||
|
revents = g_array_index(pollfds, GPollFD,
|
||||||
|
so->pollfds_idx).revents;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (so->s != -1 &&
|
||||||
|
(revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
|
||||||
|
icmp_receive(so);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if_start(slirp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
|
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
|
||||||
|
|
|
@ -26,7 +26,6 @@ stub-obj-y += qtest.o
|
||||||
stub-obj-y += replay.o
|
stub-obj-y += replay.o
|
||||||
stub-obj-y += runstate-check.o
|
stub-obj-y += runstate-check.o
|
||||||
stub-obj-y += set-fd-handler.o
|
stub-obj-y += set-fd-handler.o
|
||||||
stub-obj-y += slirp.o
|
|
||||||
stub-obj-y += sysbus.o
|
stub-obj-y += sysbus.o
|
||||||
stub-obj-y += tpm.o
|
stub-obj-y += tpm.o
|
||||||
stub-obj-y += trace-control.o
|
stub-obj-y += trace-control.o
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#include "qemu/osdep.h"
|
|
||||||
#include "qemu-common.h"
|
|
||||||
#include "qemu/host-utils.h"
|
|
||||||
#include "slirp/libslirp.h"
|
|
||||||
|
|
||||||
void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void slirp_pollfds_poll(GArray *pollfds, int select_error)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
|
@ -469,25 +469,42 @@ static int os_host_main_loop_wait(int64_t timeout)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static NotifierList main_loop_poll_notifiers =
|
||||||
|
NOTIFIER_LIST_INITIALIZER(main_loop_poll_notifiers);
|
||||||
|
|
||||||
|
void main_loop_poll_add_notifier(Notifier *notify)
|
||||||
|
{
|
||||||
|
notifier_list_add(&main_loop_poll_notifiers, notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main_loop_poll_remove_notifier(Notifier *notify)
|
||||||
|
{
|
||||||
|
notifier_remove(notify);
|
||||||
|
}
|
||||||
|
|
||||||
void main_loop_wait(int nonblocking)
|
void main_loop_wait(int nonblocking)
|
||||||
{
|
{
|
||||||
|
MainLoopPoll mlpoll = {
|
||||||
|
.state = MAIN_LOOP_POLL_FILL,
|
||||||
|
.timeout = UINT32_MAX,
|
||||||
|
.pollfds = gpollfds,
|
||||||
|
};
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t timeout = UINT32_MAX;
|
|
||||||
int64_t timeout_ns;
|
int64_t timeout_ns;
|
||||||
|
|
||||||
if (nonblocking) {
|
if (nonblocking) {
|
||||||
timeout = 0;
|
mlpoll.timeout = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* poll any events */
|
/* poll any events */
|
||||||
g_array_set_size(gpollfds, 0); /* reset for new iteration */
|
g_array_set_size(gpollfds, 0); /* reset for new iteration */
|
||||||
/* XXX: separate device handlers from system ones */
|
/* XXX: separate device handlers from system ones */
|
||||||
slirp_pollfds_fill(gpollfds, &timeout);
|
notifier_list_notify(&main_loop_poll_notifiers, &mlpoll);
|
||||||
|
|
||||||
if (timeout == UINT32_MAX) {
|
if (mlpoll.timeout == UINT32_MAX) {
|
||||||
timeout_ns = -1;
|
timeout_ns = -1;
|
||||||
} else {
|
} else {
|
||||||
timeout_ns = (uint64_t)timeout * (int64_t)(SCALE_MS);
|
timeout_ns = (uint64_t)mlpoll.timeout * (int64_t)(SCALE_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout_ns = qemu_soonest_timeout(timeout_ns,
|
timeout_ns = qemu_soonest_timeout(timeout_ns,
|
||||||
|
@ -495,7 +512,8 @@ void main_loop_wait(int nonblocking)
|
||||||
&main_loop_tlg));
|
&main_loop_tlg));
|
||||||
|
|
||||||
ret = os_host_main_loop_wait(timeout_ns);
|
ret = os_host_main_loop_wait(timeout_ns);
|
||||||
slirp_pollfds_poll(gpollfds, (ret < 0));
|
mlpoll.state = ret < 0 ? MAIN_LOOP_POLL_ERR : MAIN_LOOP_POLL_OK;
|
||||||
|
notifier_list_notify(&main_loop_poll_notifiers, &mlpoll);
|
||||||
|
|
||||||
/* CPU thread can infinitely wait for event after
|
/* CPU thread can infinitely wait for event after
|
||||||
missing the warp */
|
missing the warp */
|
||||||
|
|
Loading…
Reference in New Issue