Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/tools/virtio/ringtest/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 6 kB image not shown  

Quelle  virtio_ring_0_9.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2016 Red Hat, Inc.
 * Author: Michael S. Tsirkin <mst@redhat.com>
 *
 * Partial implementation of virtio 0.9. event index is used for signalling,
 * unconditionally. Design roughly follows linux kernel implementation in order
 * to be able to judge its performance.
 */

#define _GNU_SOURCE
#include "main.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <linux/virtio_ring.h>

struct data {
 void *data;
} *data;

struct vring ring;

/* enabling the below activates experimental ring polling code
 * (which skips index reads on consumer in favor of looking at
 * high bits of ring id ^ 0x8000).
 */

/* #ifdef RING_POLL */
/* enabling the below activates experimental in-order code
 * (which skips ring updates and reads and writes len in descriptor).
 */

/* #ifdef INORDER */

#if defined(RING_POLL) && defined(INORDER)
#error "RING_POLL and INORDER are mutually exclusive"
#endif

/* how much padding is needed to avoid false cache sharing */
#define HOST_GUEST_PADDING 0x80

struct guest {
 unsigned short avail_idx;
 unsigned short last_used_idx;
 unsigned short num_free;
 unsigned short kicked_avail_idx;
#ifndef INORDER
 unsigned short free_head;
#else
 unsigned short reserved_free_head;
#endif
 unsigned char reserved[HOST_GUEST_PADDING - 10];
} guest;

struct host {
 /* we do not need to track last avail index
 * unless we have more than one in flight.
 */

 unsigned short used_idx;
 unsigned short called_used_idx;
 unsigned char reserved[HOST_GUEST_PADDING - 4];
} host;

/* implemented by ring */
void alloc_ring(void)
{
 int ret;
 int i;
 void *p;

 ret = posix_memalign(&p, 0x1000, vring_size(ring_size, 0x1000));
 if (ret) {
  perror("Unable to allocate ring buffer.\n");
  exit(3);
 }
 memset(p, 0, vring_size(ring_size, 0x1000));
 vring_init(&ring, ring_size, p, 0x1000);

 guest.avail_idx = 0;
 guest.kicked_avail_idx = -1;
 guest.last_used_idx = 0;
#ifndef INORDER
 /* Put everything in free lists. */
 guest.free_head = 0;
#endif
 for (i = 0; i < ring_size - 1; i++)
  ring.desc[i].next = i + 1;
 host.used_idx = 0;
 host.called_used_idx = -1;
 guest.num_free = ring_size;
 data = malloc(ring_size * sizeof *data);
 if (!data) {
  perror("Unable to allocate data buffer.\n");
  exit(3);
 }
 memset(data, 0, ring_size * sizeof *data);
}

/* guest side */
int add_inbuf(unsigned len, void *buf, void *datap)
{
 unsigned head;
#ifndef INORDER
 unsigned avail;
#endif
 struct vring_desc *desc;

 if (!guest.num_free)
  return -1;

#ifdef INORDER
 head = (ring_size - 1) & (guest.avail_idx++);
#else
 head = guest.free_head;
#endif
 guest.num_free--;

 desc = ring.desc;
 desc[head].flags = VRING_DESC_F_NEXT;
 desc[head].addr = (unsigned long)(void *)buf;
 desc[head].len = len;
 /* We do it like this to simulate the way
 * we'd have to flip it if we had multiple
 * descriptors.
 */

 desc[head].flags &= ~VRING_DESC_F_NEXT;
#ifndef INORDER
 guest.free_head = desc[head].next;
#endif

 data[head].data = datap;

#ifdef RING_POLL
 /* Barrier A (for pairing) */
 smp_release();
 avail = guest.avail_idx++;
 ring.avail->ring[avail & (ring_size - 1)] =
  (head | (avail & ~(ring_size - 1))) ^ 0x8000;
#else
#ifndef INORDER
 /* Barrier A (for pairing) */
 smp_release();
 avail = (ring_size - 1) & (guest.avail_idx++);
 ring.avail->ring[avail] = head;
#endif
 /* Barrier A (for pairing) */
 smp_release();
#endif
 ring.avail->idx = guest.avail_idx;
 return 0;
}

void *get_buf(unsigned *lenp, void **bufp)
{
 unsigned head;
 unsigned index;
 void *datap;

#ifdef RING_POLL
 head = (ring_size - 1) & guest.last_used_idx;
 index = ring.used->ring[head].id;
 if ((index ^ guest.last_used_idx ^ 0x8000) & ~(ring_size - 1))
  return NULL;
 /* Barrier B (for pairing) */
 smp_acquire();
 index &= ring_size - 1;
#else
 if (ring.used->idx == guest.last_used_idx)
  return NULL;
 /* Barrier B (for pairing) */
 smp_acquire();
#ifdef INORDER
 head = (ring_size - 1) & guest.last_used_idx;
 index = head;
#else
 head = (ring_size - 1) & guest.last_used_idx;
 index = ring.used->ring[head].id;
#endif

#endif
#ifdef INORDER
 *lenp = ring.desc[index].len;
#else
 *lenp = ring.used->ring[head].len;
#endif
 datap = data[index].data;
 *bufp = (void*)(unsigned long)ring.desc[index].addr;
 data[index].data = NULL;
#ifndef INORDER
 ring.desc[index].next = guest.free_head;
 guest.free_head = index;
#endif
 guest.num_free++;
 guest.last_used_idx++;
 return datap;
}

bool used_empty()
{
 unsigned short last_used_idx = guest.last_used_idx;
#ifdef RING_POLL
 unsigned short head = last_used_idx & (ring_size - 1);
 unsigned index = ring.used->ring[head].id;

 return (index ^ last_used_idx ^ 0x8000) & ~(ring_size - 1);
#else
 return ring.used->idx == last_used_idx;
#endif
}

void disable_call()
{
 /* Doing nothing to disable calls might cause
 * extra interrupts, but reduces the number of cache misses.
 */

}

bool enable_call()
{
 vring_used_event(&ring) = guest.last_used_idx;
 /* Flush call index write */
 /* Barrier D (for pairing) */
 smp_mb();
 return used_empty();
}

void kick_available(void)
{
 bool need;

 /* Flush in previous flags write */
 /* Barrier C (for pairing) */
 smp_mb();
 need = vring_need_event(vring_avail_event(&ring),
    guest.avail_idx,
    guest.kicked_avail_idx);

 guest.kicked_avail_idx = guest.avail_idx;
 if (need)
  kick();
}

/* host side */
void disable_kick()
{
 /* Doing nothing to disable kicks might cause
 * extra interrupts, but reduces the number of cache misses.
 */

}

bool enable_kick()
{
 vring_avail_event(&ring) = host.used_idx;
 /* Barrier C (for pairing) */
 smp_mb();
 return avail_empty();
}

bool avail_empty()
{
 unsigned head = host.used_idx;
#ifdef RING_POLL
 unsigned index = ring.avail->ring[head & (ring_size - 1)];

 return ((index ^ head ^ 0x8000) & ~(ring_size - 1));
#else
 return head == ring.avail->idx;
#endif
}

bool use_buf(unsigned *lenp, void **bufp)
{
 unsigned used_idx = host.used_idx;
 struct vring_desc *desc;
 unsigned head;

#ifdef RING_POLL
 head = ring.avail->ring[used_idx & (ring_size - 1)];
 if ((used_idx ^ head ^ 0x8000) & ~(ring_size - 1))
  return false;
 /* Barrier A (for pairing) */
 smp_acquire();

 used_idx &= ring_size - 1;
 desc = &ring.desc[head & (ring_size - 1)];
#else
 if (used_idx == ring.avail->idx)
  return false;

 /* Barrier A (for pairing) */
 smp_acquire();

 used_idx &= ring_size - 1;
#ifdef INORDER
 head = used_idx;
#else
 head = ring.avail->ring[used_idx];
#endif
 desc = &ring.desc[head];
#endif

 *lenp = desc->len;
 *bufp = (void *)(unsigned long)desc->addr;

#ifdef INORDER
 desc->len = desc->len - 1;
#else
 /* now update used ring */
 ring.used->ring[used_idx].id = head;
 ring.used->ring[used_idx].len = desc->len - 1;
#endif
 /* Barrier B (for pairing) */
 smp_release();
 host.used_idx++;
 ring.used->idx = host.used_idx;
 
 return true;
}

void call_used(void)
{
 bool need;

 /* Flush in previous flags write */
 /* Barrier D (for pairing) */
 smp_mb();
 need = vring_need_event(vring_used_event(&ring),
    host.used_idx,
    host.called_used_idx);

 host.called_used_idx = host.used_idx;
 if (need)
  call();
}

Messung V0.5
C=90 H=82 G=86

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.