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:
Marc-André Lureau 2019-01-17 15:43:55 +04:00 committed by Samuel Thibault
parent 625a526b32
commit 1ab67b98cd
7 changed files with 374 additions and 350 deletions

View File

@ -302,4 +302,19 @@ void qemu_fd_register(int fd);
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
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

View File

@ -86,6 +86,7 @@ typedef struct SlirpState {
NetClientState nc;
QTAILQ_ENTRY(SlirpState) entry;
Slirp *slirp;
Notifier poll_notifier;
Notifier exit_notifier;
#ifndef _WIN32
gchar *smb_dir;
@ -144,6 +145,7 @@ static void net_slirp_cleanup(NetClientState *nc)
SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
g_slist_free_full(s->fwd, slirp_free_fwd);
main_loop_poll_remove_notifier(&s->poll_notifier);
slirp_cleanup(s->slirp);
if (s->exit_notifier.notify) {
qemu_remove_exit_notifier(&s->exit_notifier);
@ -209,6 +211,25 @@ static const SlirpCb slirp_cb = {
.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,
const char *name, int restricted,
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);
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) {
if (config->flags & SLIRP_CFG_HOSTFWD) {
if (slirp_hostfwd(s, config->str, errp) < 0) {

View File

@ -63,9 +63,9 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
void *opaque);
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);

View File

@ -368,9 +368,8 @@ void slirp_cleanup(Slirp *slirp)
#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)
static void slirp_update_timeout(uint32_t *timeout)
static void slirp_update_timeout(Slirp *slirp, uint32_t *timeout)
{
Slirp *slirp;
uint32_t t;
if (*timeout <= TIMEOUT_FAST) {
@ -382,7 +381,6 @@ static void slirp_update_timeout(uint32_t *timeout)
/* If we have tcp timeout with slirp, then we will fill @timeout with
* more precise value.
*/
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
if (slirp->time_fasttimo) {
*timeout = TIMEOUT_FAST;
return;
@ -390,24 +388,17 @@ static void slirp_update_timeout(uint32_t *timeout)
if (slirp->do_slowtimo) {
t = MIN(TIMEOUT_SLOW, 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;
if (QTAILQ_EMPTY(&slirp_instances)) {
return;
}
/*
* First, TCP sockets
*/
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
/*
* *_slowtimo needs calling if there are IP fragments
* in the fragment queue, or there are TCP connections active
@ -415,8 +406,7 @@ void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
(&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
for (so = slirp->tcb.so_next; so != &slirp->tcb;
so = so_next) {
for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) {
int events = 0;
so_next = so->so_next;
@ -495,8 +485,7 @@ void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
/*
* UDP sockets
*/
for (so = slirp->udb.so_next; so != &slirp->udb;
so = so_next) {
for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
so_next = so->so_next;
so->pollfds_idx = -1;
@ -536,8 +525,7 @@ void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
/*
* ICMP sockets
*/
for (so = slirp->icmp.so_next; so != &slirp->icmp;
so = so_next) {
for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
so_next = so->so_next;
so->pollfds_idx = -1;
@ -563,23 +551,17 @@ void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
g_array_append_val(pollfds, pfd);
}
}
}
slirp_update_timeout(timeout);
slirp_update_timeout(slirp, timeout);
}
void slirp_pollfds_poll(GArray *pollfds, int select_error)
void slirp_pollfds_poll(Slirp *slirp, 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
*/
@ -745,7 +727,6 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error)
}
if_start(slirp);
}
}
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)

View File

@ -26,7 +26,6 @@ stub-obj-y += qtest.o
stub-obj-y += replay.o
stub-obj-y += runstate-check.o
stub-obj-y += set-fd-handler.o
stub-obj-y += slirp.o
stub-obj-y += sysbus.o
stub-obj-y += tpm.o
stub-obj-y += trace-control.o

View File

@ -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)
{
}

View File

@ -469,25 +469,42 @@ static int os_host_main_loop_wait(int64_t timeout)
}
#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)
{
MainLoopPoll mlpoll = {
.state = MAIN_LOOP_POLL_FILL,
.timeout = UINT32_MAX,
.pollfds = gpollfds,
};
int ret;
uint32_t timeout = UINT32_MAX;
int64_t timeout_ns;
if (nonblocking) {
timeout = 0;
mlpoll.timeout = 0;
}
/* poll any events */
g_array_set_size(gpollfds, 0); /* reset for new iteration */
/* 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;
} 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,
@ -495,7 +512,8 @@ void main_loop_wait(int nonblocking)
&main_loop_tlg));
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
missing the warp */