// 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 "aemu/base/c_header.h"
#include "aemu/base/export.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.
    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,
    uint64_t timeout_us);
bool ring_buffer_wait_read(
    const struct ring_buffer* r,
    const struct ring_buffer_view* v,
    uint32_t bytes,
    uint64_t timeout_us);

// 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);
uint32_t ring_buffer_available_write(
    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();
ANDROID_END_HEADER
