blob: 7cc56ad2e4bd704ca6e0994e7551f24331b1953f [file] [log] [blame]
// Copyright 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "android/utils/compiler.h"
ANDROID_BEGIN_HEADER
#include <stdbool.h>
#include <stdint.h>
#define RING_BUFFER_SHIFT 11
#define RING_BUFFER_SIZE (1 << RING_BUFFER_SHIFT)
#define NUM_CONFIG_FIELDS 32
// Single producer/consumer ring buffer struct that can be shared
// between host and guest as-is.
struct ring_buffer {
uint32_t host_version;
uint32_t guest_version;
uint32_t write_pos; // Atomically updated for the consumer
uint32_t unused0[13]; // Separate cache line
uint32_t read_pos; // Atomically updated for the producer
uint32_t read_live_count;
uint32_t read_yield_count;
uint32_t read_sleep_us_count;
uint32_t unused1[12]; // Separate cache line
uint8_t buf[RING_BUFFER_SIZE];
uint32_t state; // An atomically updated variable from both
// producer and consumer for other forms of
// coordination.
// Configuration fields
uint32_t config[NUM_CONFIG_FIELDS];
};
void ring_buffer_init(struct ring_buffer* r);
// Writes or reads step_size at a time. Sets errno=EAGAIN if full or empty.
// Returns the number of step_size steps read.
long ring_buffer_write(
struct ring_buffer* r, const void* data, uint32_t step_size, uint32_t steps);
long ring_buffer_read(
struct ring_buffer* r, void* data, uint32_t step_size, uint32_t steps);
// Like ring_buffer_write / ring_buffer_read, but merely advances the counters
// without reading or writing anything. Returns the number of step_size steps
// advanced.
long ring_buffer_advance_write(
struct ring_buffer* r, uint32_t step_size, uint32_t steps);
long ring_buffer_advance_read(
struct ring_buffer* r, uint32_t step_size, uint32_t steps);
// If we want to work with dynamically allocated buffers, a separate struct is
// needed; the host and guest are in different address spaces and thus have
// different views of the same memory, with the host and guest having different
// copies of this struct.
struct ring_buffer_view {
uint8_t* buf;
uint32_t size;
uint32_t mask;
};
// Convenience struct that holds a pointer to a ring along with a view. It's a
// common pattern for the ring and the buffer of the view to be shared between
// two entities (in this case, usually guest and host).
struct ring_buffer_with_view {
struct ring_buffer* ring;
struct ring_buffer_view view;
};
// Calculates the highest power of 2 so that
// (1 << shift) <= size.
uint32_t ring_buffer_calc_shift(uint32_t size);
// Initializes ring buffer with view using |buf|. If |size| is not a power of
// two, then the buffer will assume a size equal to the greater power of two
// less than |size|.
void ring_buffer_view_init(
struct ring_buffer* r,
struct ring_buffer_view* v,
uint8_t* buf,
uint32_t size);
void ring_buffer_init_view_only(
struct ring_buffer_view* v,
uint8_t* buf,
uint32_t size);
// Read/write functions with the view.
long ring_buffer_view_write(
struct ring_buffer* r,
struct ring_buffer_view* v,
const void* data, uint32_t step_size, uint32_t steps);
long ring_buffer_view_read(
struct ring_buffer* r,
struct ring_buffer_view* v,
void* data, uint32_t step_size, uint32_t steps);
// Usage of ring_buffer as a waitable object.
// These functions will back off if spinning too long.
//
// if |v| is null, it is assumed that the statically allocated ring buffer is
// used.
//
// Returns true if ring buffer became available, false if timed out.
bool ring_buffer_wait_write(
const struct ring_buffer* r,
const struct ring_buffer_view* v,
uint32_t bytes);
bool ring_buffer_wait_read(
const struct ring_buffer* r,
const struct ring_buffer_view* v,
uint32_t bytes);
// read/write fully, blocking if there is nothing to read/write.
void ring_buffer_write_fully(
struct ring_buffer* r,
struct ring_buffer_view* v,
const void* data,
uint32_t bytes);
void ring_buffer_read_fully(
struct ring_buffer* r,
struct ring_buffer_view* v,
void* data,
uint32_t bytes);
// Like read/write fully, but with an abort value. The value is read from
// |abortPtr| each time. If |abortPtr| is null, then behaves the same
// as ring_buffer_(read|write)_fully.
// Returns the actual number of bytes sent or received.
uint32_t ring_buffer_write_fully_with_abort(
struct ring_buffer* r,
struct ring_buffer_view* v,
const void* data,
uint32_t bytes,
uint32_t abort_value,
const volatile uint32_t* abort_ptr);
uint32_t ring_buffer_read_fully_with_abort(
struct ring_buffer* r,
struct ring_buffer_view* v,
void* data,
uint32_t bytes,
uint32_t abort_value,
const volatile uint32_t* abort_ptr);
uint32_t ring_buffer_view_get_ring_pos(
const struct ring_buffer_view* v,
uint32_t index);
bool ring_buffer_can_write(
const struct ring_buffer* r, uint32_t bytes);
bool ring_buffer_can_read(
const struct ring_buffer* r, uint32_t bytes);
bool ring_buffer_view_can_write(
const struct ring_buffer* r,
const struct ring_buffer_view* v,
uint32_t bytes);
bool ring_buffer_view_can_read(
const struct ring_buffer* r,
const struct ring_buffer_view* v,
uint32_t bytes);
uint32_t ring_buffer_available_read(
const struct ring_buffer* r,
const struct ring_buffer_view* v);
// Copies out contents from the consumer side of
// ring buffer/view |r,v|.
// If there is less available read than |wanted_bytes|,
// returns -1.
// On success, returns 0.
int ring_buffer_copy_contents(
const struct ring_buffer* r,
const struct ring_buffer_view* v,
uint32_t wanted_bytes,
uint8_t* res);
// Lockless synchronization where the consumer is allowed to hang up and go to
// sleep. This can be considered a sort of asymmetric lock for two threads,
// where the consumer can be more sleepy. It captures the pattern we usually use
// for emulator devices; the guest asks the host for something, and some host
// thread services the request and goes back to sleep.
enum ring_buffer_sync_state {
RING_BUFFER_SYNC_PRODUCER_IDLE = 0,
RING_BUFFER_SYNC_PRODUCER_ACTIVE = 1,
RING_BUFFER_SYNC_CONSUMER_HANGING_UP = 2,
RING_BUFFER_SYNC_CONSUMER_HUNG_UP = 3,
};
// Sync state is RING_BUFFER_SYNC_PRODUCER_IDLE.
void ring_buffer_sync_init(struct ring_buffer* r);
// Tries to acquire the channel for sending.
// Returns false if the consumer was in the middle of hanging up,
// true if the producer successfully acquired the channel
// (put it in the RING_BUFFER_SYNC_PRODUCER_ACTIVE state).
bool ring_buffer_producer_acquire(struct ring_buffer* r);
// Same as above, but acquires from RING_BUFFER_SYNC_CONSUMER_HUNG_UP.
bool ring_buffer_producer_acquire_from_hangup(struct ring_buffer* r);
// Waits until the consumer hangs up.
void ring_buffer_producer_wait_hangup(struct ring_buffer* r);
// Sets the state back to RING_BUFFER_SYNC_PRODUCER_IDLE.
void ring_buffer_producer_idle(struct ring_buffer* r);
// There is no symmetric consumer acquire because the consumer can consume with
// the ring buffer being in any state (albeit with long waiting if the producer
// does not send anything)
// Tries to acquire the channel on the consumer side for
// hanging up. Returns false if the producer is in the middle of sending,
// true if the consumer successfully hung up the channel
// (put it in the RING_BUFFER_SYNC_CONSUMER_HUNG_UP state).
bool ring_buffer_consumer_hangup(struct ring_buffer* r);
// Waits until the producer has set the state to
// RING_BUFFER_SYNC_PRODUCER_IDLE.
void ring_buffer_consumer_wait_producer_idle(struct ring_buffer* r);
// Sets the state to hung up.
void ring_buffer_consumer_hung_up(struct ring_buffer* r);
// Convenient function to reschedule thread
void ring_buffer_yield(void);
ANDROID_END_HEADER