// 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. #include "android/base/ring_buffer.h" #include #include #ifdef _MSC_VER #include "msvc-posix.h" #else #include #endif #if (defined(__i386__) || defined(__x86_64__)) #define RING_BUFFER_X86 1 #else #define RING_BUFFER_X86 0 #endif #if RING_BUFFER_X86 #include #endif #ifdef _WIN32 #include #else #include #include #endif #define RING_BUFFER_MASK (RING_BUFFER_SIZE - 1) #define RING_BUFFER_VERSION 1 static inline void ring_buffer_pause() { #if RING_BUFFER_X86 _mm_pause(); #else // TODO(lfy) analog of pause on ARM #endif } void ring_buffer_init(struct ring_buffer* r) { r->guest_version = 1; r->write_pos = 0; r->read_pos = 0; r->read_live_count = 0; r->read_yield_count = 0; r->read_sleep_us_count = 0; r->state = 0; } static uint32_t get_ring_pos(uint32_t index) { return index & RING_BUFFER_MASK; } bool ring_buffer_can_write(const struct ring_buffer* r, uint32_t bytes) { uint32_t read_view; __atomic_load(&r->read_pos, &read_view, __ATOMIC_SEQ_CST); return get_ring_pos(read_view - r->write_pos - 1) >= bytes; } bool ring_buffer_can_read(const struct ring_buffer* r, uint32_t bytes) { uint32_t write_view; __atomic_load(&r->write_pos, &write_view, __ATOMIC_SEQ_CST); return get_ring_pos(write_view - r->read_pos) >= bytes; } long ring_buffer_write( struct ring_buffer* r, const void* data, uint32_t step_size, uint32_t steps) { const uint8_t* data_bytes = (const uint8_t*)data; uint32_t i; for (i = 0; i < steps; ++i) { if (!ring_buffer_can_write(r, step_size)) { errno = -EAGAIN; return (long)i; } // Needs to be split up into 2 writes for the edge case. uint32_t available_at_end = RING_BUFFER_SIZE - get_ring_pos(r->write_pos); if (step_size > available_at_end) { uint32_t remaining = step_size - available_at_end; memcpy( &r->buf[get_ring_pos(r->write_pos)], data_bytes + i * step_size, available_at_end); memcpy( &r->buf[get_ring_pos(r->write_pos + available_at_end)], data_bytes + i * step_size + available_at_end, remaining); } else { memcpy( &r->buf[get_ring_pos(r->write_pos)], data_bytes + i * step_size, step_size); } __atomic_add_fetch(&r->write_pos, step_size, __ATOMIC_SEQ_CST); } errno = 0; return (long)steps; } long ring_buffer_read( struct ring_buffer* r, void* data, uint32_t step_size, uint32_t steps) { uint8_t* data_bytes = (uint8_t*)data; uint32_t i; for (i = 0; i < steps; ++i) { if (!ring_buffer_can_read(r, step_size)) { errno = -EAGAIN; return (long)i; } // Needs to be split up into 2 reads for the edge case. uint32_t available_at_end = RING_BUFFER_SIZE - get_ring_pos(r->read_pos); if (step_size > available_at_end) { uint32_t remaining = step_size - available_at_end; memcpy( data_bytes + i * step_size, &r->buf[get_ring_pos(r->read_pos)], available_at_end); memcpy( data_bytes + i * step_size + available_at_end, &r->buf[get_ring_pos(r->read_pos + available_at_end)], remaining); } else { memcpy( data_bytes + i * step_size, &r->buf[get_ring_pos(r->read_pos)], step_size); } __atomic_add_fetch(&r->read_pos, step_size, __ATOMIC_SEQ_CST); } errno = 0; return (long)steps; } long ring_buffer_advance_write( struct ring_buffer* r, uint32_t step_size, uint32_t steps) { uint32_t i; for (i = 0; i < steps; ++i) { if (!ring_buffer_can_write(r, step_size)) { errno = -EAGAIN; return (long)i; } __atomic_add_fetch(&r->write_pos, step_size, __ATOMIC_SEQ_CST); } errno = 0; return (long)steps; } long ring_buffer_advance_read( struct ring_buffer* r, uint32_t step_size, uint32_t steps) { uint32_t i; for (i = 0; i < steps; ++i) { if (!ring_buffer_can_read(r, step_size)) { errno = -EAGAIN; return (long)i; } __atomic_add_fetch(&r->read_pos, step_size, __ATOMIC_SEQ_CST); } errno = 0; return (long)steps; } uint32_t ring_buffer_calc_shift(uint32_t size) { uint32_t shift = 0; while ((1 << shift) < size) { ++shift; } // if size is not a power of 2, if ((1 << shift) > size) { --shift; } return shift; } void ring_buffer_view_init( struct ring_buffer* r, struct ring_buffer_view* v, uint8_t* buf, uint32_t size) { uint32_t shift = ring_buffer_calc_shift(size); ring_buffer_init(r); v->buf = buf; v->size = (1 << shift); v->mask = (1 << shift) - 1; } void ring_buffer_init_view_only( struct ring_buffer_view* v, uint8_t* buf, uint32_t size) { uint32_t shift = ring_buffer_calc_shift(size); v->buf = buf; v->size = (1 << shift); v->mask = (1 << shift) - 1; } uint32_t ring_buffer_view_get_ring_pos( const struct ring_buffer_view* v, uint32_t index) { return index & v->mask; } bool ring_buffer_view_can_write( const struct ring_buffer* r, const struct ring_buffer_view* v, uint32_t bytes) { uint32_t read_view; __atomic_load(&r->read_pos, &read_view, __ATOMIC_SEQ_CST); return ring_buffer_view_get_ring_pos( v, read_view - r->write_pos - 1) >= bytes; } bool ring_buffer_view_can_read( const struct ring_buffer* r, const struct ring_buffer_view* v, uint32_t bytes) { uint32_t write_view; __atomic_load(&r->write_pos, &write_view, __ATOMIC_SEQ_CST); return ring_buffer_view_get_ring_pos( v, write_view - r->read_pos) >= bytes; } uint32_t ring_buffer_available_read( const struct ring_buffer* r, const struct ring_buffer_view* v) { uint32_t write_view; __atomic_load(&r->write_pos, &write_view, __ATOMIC_SEQ_CST); if (v) { return ring_buffer_view_get_ring_pos( v, write_view - r->read_pos); } else { return get_ring_pos(write_view - r->read_pos); } } int ring_buffer_copy_contents( const struct ring_buffer* r, const struct ring_buffer_view* v, uint32_t wanted_bytes, uint8_t* res) { uint32_t total_available = ring_buffer_available_read(r, v); uint32_t available_at_end = 0; if (v) { available_at_end = v->size - ring_buffer_view_get_ring_pos(v, r->read_pos); } else { available_at_end = RING_BUFFER_SIZE - get_ring_pos(r->write_pos); } if (total_available < wanted_bytes) { return -1; } if (v) { if (wanted_bytes > available_at_end) { uint32_t remaining = wanted_bytes - available_at_end; memcpy(res, &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos)], available_at_end); memcpy(res + available_at_end, &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos + available_at_end)], remaining); } else { memcpy(res, &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos)], wanted_bytes); } } else { if (wanted_bytes > available_at_end) { uint32_t remaining = wanted_bytes - available_at_end; memcpy(res, &r->buf[get_ring_pos(r->read_pos)], available_at_end); memcpy(res + available_at_end, &r->buf[get_ring_pos(r->read_pos + available_at_end)], remaining); } else { memcpy(res, &r->buf[get_ring_pos(r->read_pos)], wanted_bytes); } } return 0; } long ring_buffer_view_write( struct ring_buffer* r, struct ring_buffer_view* v, const void* data, uint32_t step_size, uint32_t steps) { uint8_t* data_bytes = (uint8_t*)data; uint32_t i; for (i = 0; i < steps; ++i) { if (!ring_buffer_view_can_write(r, v, step_size)) { errno = -EAGAIN; return (long)i; } // Needs to be split up into 2 writes for the edge case. uint32_t available_at_end = v->size - ring_buffer_view_get_ring_pos(v, r->write_pos); if (step_size > available_at_end) { uint32_t remaining = step_size - available_at_end; memcpy( &v->buf[ring_buffer_view_get_ring_pos(v, r->write_pos)], data_bytes + i * step_size, available_at_end); memcpy( &v->buf[ring_buffer_view_get_ring_pos(v, r->write_pos + available_at_end)], data_bytes + i * step_size + available_at_end, remaining); } else { memcpy( &v->buf[ring_buffer_view_get_ring_pos(v, r->write_pos)], data_bytes + i * step_size, step_size); } __atomic_add_fetch(&r->write_pos, step_size, __ATOMIC_SEQ_CST); } errno = 0; return (long)steps; } long ring_buffer_view_read( struct ring_buffer* r, struct ring_buffer_view* v, void* data, uint32_t step_size, uint32_t steps) { uint8_t* data_bytes = (uint8_t*)data; uint32_t i; for (i = 0; i < steps; ++i) { if (!ring_buffer_view_can_read(r, v, step_size)) { errno = -EAGAIN; return (long)i; } // Needs to be split up into 2 reads for the edge case. uint32_t available_at_end = v->size - ring_buffer_view_get_ring_pos(v, r->read_pos); if (step_size > available_at_end) { uint32_t remaining = step_size - available_at_end; memcpy( data_bytes + i * step_size, &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos)], available_at_end); memcpy( data_bytes + i * step_size + available_at_end, &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos + available_at_end)], remaining); } else { memcpy(data_bytes + i * step_size, &v->buf[ring_buffer_view_get_ring_pos(v, r->read_pos)], step_size); } __atomic_add_fetch(&r->read_pos, step_size, __ATOMIC_SEQ_CST); } errno = 0; return (long)steps; } void ring_buffer_yield() { } bool ring_buffer_wait_write( const struct ring_buffer* r, const struct ring_buffer_view* v, uint32_t bytes) { bool can_write = v ? ring_buffer_view_can_write(r, v, bytes) : ring_buffer_can_write(r, bytes); while (!can_write) { ring_buffer_yield(); can_write = v ? ring_buffer_view_can_write(r, v, bytes) : ring_buffer_can_write(r, bytes); } return true; } bool ring_buffer_wait_read( const struct ring_buffer* r, const struct ring_buffer_view* v, uint32_t bytes) { bool can_read = v ? ring_buffer_view_can_read(r, v, bytes) : ring_buffer_can_read(r, bytes); while (!can_read) { ring_buffer_yield(); can_read = v ? ring_buffer_view_can_read(r, v, bytes) : ring_buffer_can_read(r, bytes); } ((struct ring_buffer*)r)->read_live_count++; return true; } static uint32_t get_step_size( struct ring_buffer_view* v, uint32_t bytes) { uint32_t available = v ? (v->size >> 1) : (RING_BUFFER_SIZE >> 1); uint32_t res = available < bytes ? available : bytes; return res; } void ring_buffer_write_fully( struct ring_buffer* r, struct ring_buffer_view* v, const void* data, uint32_t bytes) { ring_buffer_write_fully_with_abort(r, v, data, bytes, 0, 0); } void ring_buffer_read_fully( struct ring_buffer* r, struct ring_buffer_view* v, void* data, uint32_t bytes) { ring_buffer_read_fully_with_abort(r, v, data, bytes, 0, 0); } 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 candidate_step = get_step_size(v, bytes); uint32_t processed = 0; uint8_t* dst = (uint8_t*)data; while (processed < bytes) { if (bytes - processed < candidate_step) { candidate_step = bytes - processed; } long processed_here = 0; ring_buffer_wait_write(r, v, candidate_step); if (v) { processed_here = ring_buffer_view_write(r, v, dst + processed, candidate_step, 1); } else { processed_here = ring_buffer_write(r, dst + processed, candidate_step, 1); } processed += processed_here ? candidate_step : 0; if (abort_ptr && (abort_value == *abort_ptr)) { return processed; } } return processed; } 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 candidate_step = get_step_size(v, bytes); uint32_t processed = 0; uint8_t* dst = (uint8_t*)data; while (processed < bytes) { ring_buffer_pause(); if (bytes - processed < candidate_step) { candidate_step = bytes - processed; } long processed_here = 0; ring_buffer_wait_read(r, v, candidate_step); if (v) { processed_here = ring_buffer_view_read(r, v, dst + processed, candidate_step, 1); } else { processed_here = ring_buffer_read(r, dst + processed, candidate_step, 1); } processed += processed_here ? candidate_step : 0; if (abort_ptr && (abort_value == *abort_ptr)) { return processed; } } return processed; } void ring_buffer_sync_init(struct ring_buffer* r) { __atomic_store_n(&r->state, RING_BUFFER_SYNC_PRODUCER_IDLE, __ATOMIC_SEQ_CST); } bool ring_buffer_producer_acquire(struct ring_buffer* r) { uint32_t expected_idle = RING_BUFFER_SYNC_PRODUCER_IDLE; bool success = __atomic_compare_exchange_n( &r->state, &expected_idle, RING_BUFFER_SYNC_PRODUCER_ACTIVE, false /* strong */, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return success; } bool ring_buffer_producer_acquire_from_hangup(struct ring_buffer* r) { uint32_t expected_hangup = RING_BUFFER_SYNC_CONSUMER_HUNG_UP; bool success = __atomic_compare_exchange_n( &r->state, &expected_hangup, RING_BUFFER_SYNC_PRODUCER_ACTIVE, false /* strong */, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return success; } void ring_buffer_producer_wait_hangup(struct ring_buffer* r) { while (__atomic_load_n(&r->state, __ATOMIC_SEQ_CST) != RING_BUFFER_SYNC_CONSUMER_HUNG_UP) { ring_buffer_yield(); } } void ring_buffer_producer_idle(struct ring_buffer* r) { __atomic_store_n(&r->state, RING_BUFFER_SYNC_PRODUCER_IDLE, __ATOMIC_SEQ_CST); } bool ring_buffer_consumer_hangup(struct ring_buffer* r) { uint32_t expected_idle = RING_BUFFER_SYNC_PRODUCER_IDLE; bool success = __atomic_compare_exchange_n( &r->state, &expected_idle, RING_BUFFER_SYNC_CONSUMER_HANGING_UP, false /* strong */, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return success; } void ring_buffer_consumer_wait_producer_idle(struct ring_buffer* r) { while (__atomic_load_n(&r->state, __ATOMIC_SEQ_CST) != RING_BUFFER_SYNC_PRODUCER_IDLE) { ring_buffer_yield(); } } void ring_buffer_consumer_hung_up(struct ring_buffer* r) { __atomic_store_n(&r->state, RING_BUFFER_SYNC_CONSUMER_HUNG_UP, __ATOMIC_SEQ_CST); }