// 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 "base/export.h" #include #include #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();