[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v3 3/4] vhost-user-rng: backend: Add RNG vhost-user daemon im
From: |
Alex Bennée |
Subject: |
Re: [PATCH v3 3/4] vhost-user-rng: backend: Add RNG vhost-user daemon implementation |
Date: |
Wed, 21 Jul 2021 21:14:31 +0100 |
User-agent: |
mu4e 1.5.14; emacs 28.0.50 |
Mathieu Poirier <mathieu.poirier@linaro.org> writes:
> This patch provides the vhost-user backend implementation to work
> in tandem with the vhost-user-rng implementation of the QEMU VMM.
>
> It uses the vhost-user API so that other VMM can re-use the interface
> without having to write the driver again.
>
> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Try the following patch which creates a nested main loop and runs it
until the g_timeout_add fires again.
--8<---------------cut here---------------start------------->8---
tools/virtio/vhost-user-rng: avoid mutex by using nested main loop
As we are blocking anyway all we really need to do is run a main loop
until the timer fires and the data is consumed.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
1 file changed, 30 insertions(+), 76 deletions(-)
tools/vhost-user-rng/main.c | 106 +++++++++++++-------------------------------
modified tools/vhost-user-rng/main.c
@@ -42,13 +42,10 @@
typedef struct {
VugDev dev;
- struct itimerspec ts;
- timer_t rate_limit_timer;
- pthread_mutex_t rng_mutex;
- pthread_cond_t rng_cond;
int64_t quota_remaining;
- bool activate_timer;
+ guint timer;
GMainLoop *loop;
+ GMainLoop *blocked;
} VuRNG;
static gboolean print_cap, verbose;
@@ -59,66 +56,26 @@ static gint source_fd, socket_fd = -1;
static uint32_t period_ms = 1 << 16;
static uint64_t max_bytes = INT64_MAX;
-static void check_rate_limit(union sigval sv)
+static gboolean check_rate_limit(gpointer user_data)
{
- VuRNG *rng = sv.sival_ptr;
- bool wakeup = false;
+ VuRNG *rng = (VuRNG *) user_data;
- pthread_mutex_lock(&rng->rng_mutex);
- /*
- * The timer has expired and the guest has used all available
- * entropy, which means function vu_rng_handle_request() is waiting
- * on us. As such wake it up once we're done here.
- */
- if (rng->quota_remaining == 0) {
- wakeup = true;
+ if (rng->blocked) {
+ g_info("%s: called while blocked", __func__);
+ g_main_loop_quit(rng->blocked);
}
-
/*
* Reset the entropy available to the guest and tell function
* vu_rng_handle_requests() to start the timer before using it.
*/
rng->quota_remaining = max_bytes;
- rng->activate_timer = true;
- pthread_mutex_unlock(&rng->rng_mutex);
-
- if (wakeup) {
- pthread_cond_signal(&rng->rng_cond);
- }
-}
-
-static void setup_timer(VuRNG *rng)
-{
- struct sigevent sev;
- int ret;
-
- memset(&rng->ts, 0, sizeof(struct itimerspec));
- rng->ts.it_value.tv_sec = period_ms / 1000;
- rng->ts.it_value.tv_nsec = (period_ms % 1000) * 1000000;
-
- /*
- * Call function check_rate_limit() as if it was the start of
- * a new thread when the timer expires.
- */
- sev.sigev_notify = SIGEV_THREAD;
- sev.sigev_notify_function = check_rate_limit;
- sev.sigev_value.sival_ptr = rng;
- /* Needs to be NULL if defaults attributes are to be used. */
- sev.sigev_notify_attributes = NULL;
- ret = timer_create(CLOCK_MONOTONIC, &sev, &rng->rate_limit_timer);
- if (ret < 0) {
- fprintf(stderr, "timer_create() failed\n");
- }
-
+ return true;
}
-
/* Virtio helpers */
static uint64_t rng_get_features(VuDev *dev)
{
- if (verbose) {
- g_info("%s: replying", __func__);
- }
+ g_info("%s: replying", __func__);
return 0;
}
@@ -137,7 +94,7 @@ static void vu_rng_handle_requests(VuDev *dev, int qidx)
VuVirtq *vq = vu_get_queue(dev, qidx);
VuVirtqElement *elem;
size_t to_read;
- int len, ret;
+ int len;
for (;;) {
/* Get element in the vhost virtqueue */
@@ -149,24 +106,21 @@ static void vu_rng_handle_requests(VuDev *dev, int qidx)
/* Get the amount of entropy to read from the vhost server */
to_read = elem->in_sg[0].iov_len;
- pthread_mutex_lock(&rng->rng_mutex);
-
/*
* We have consumed all entropy available for this time slice.
* Wait for the timer (check_rate_limit()) to tell us about the
* start of a new time slice.
*/
if (rng->quota_remaining == 0) {
- pthread_cond_wait(&rng->rng_cond, &rng->rng_mutex);
- }
-
- /* Start the timer if the last time slice has expired */
- if (rng->activate_timer == true) {
- rng->activate_timer = false;
- ret = timer_settime(rng->rate_limit_timer, 0, &rng->ts, NULL);
- if (ret < 0) {
- fprintf(stderr, "timer_settime() failed\n");
- }
+ g_assert(!rng->blocked);
+ rng->blocked = g_main_loop_new(g_main_loop_get_context(rng->loop),
false);
+ g_info("attempting to consume %ld bytes but no quota left (%s)",
+ to_read,
+ g_main_loop_is_running(rng->loop) ? "running" : "not
running");
+ g_main_loop_run(rng->blocked);
+ g_info("return from blocked loop: %ld", rng->quota_remaining);
+ g_main_loop_unref(rng->blocked);
+ rng->blocked = false;
}
/* Make sure we don't read more than it's available */
@@ -183,8 +137,6 @@ static void vu_rng_handle_requests(VuDev *dev, int qidx)
rng->quota_remaining -= len;
- pthread_mutex_unlock(&rng->rng_mutex);
-
vu_queue_push(dev, vq, elem, len);
free(elem);
}
@@ -373,6 +325,7 @@ int main(int argc, char *argv[])
* can add it's GSource watches.
*/
rng.loop = g_main_loop_new(NULL, FALSE);
+ rng.blocked = NULL;
if (!vug_init(&rng.dev, 1, g_socket_get_fd(socket),
panic, &vuiface)) {
@@ -380,24 +333,25 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
- rng.quota_remaining = max_bytes;
- rng.activate_timer = true;
- pthread_mutex_init(&rng.rng_mutex, NULL);
- pthread_cond_init(&rng.rng_cond, NULL);
- setup_timer(&rng);
-
if (verbose) {
- g_info("period_ms: %d tv_sec: %ld tv_nsec: %lu\n",
- period_ms, rng.ts.it_value.tv_sec, rng.ts.it_value.tv_nsec);
+ g_log_set_handler(NULL, G_LOG_LEVEL_MASK, g_log_default_handler, NULL);
+ g_setenv("G_MESSAGES_DEBUG", "all", true);
+ } else {
+ g_log_set_handler(NULL,
+ G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL |
G_LOG_LEVEL_ERROR,
+ g_log_default_handler, NULL);
}
+ rng.quota_remaining = max_bytes;
+ rng.timer = g_timeout_add(period_ms, check_rate_limit, &rng);
+ g_info("period_ms: %"PRId32", timer %d\n", period_ms, rng.timer);
+
g_message("entering main loop, awaiting messages");
g_main_loop_run(rng.loop);
g_message("finished main loop, cleaning up");
g_main_loop_unref(rng.loop);
vug_deinit(&rng.dev);
- timer_delete(rng.rate_limit_timer);
close(source_fd);
unlink(socket_path);
}
--8<---------------cut here---------------end--------------->8---
--
Alex Bennée