1#ifndef AWS_COMMON_RING_BUFFER_H
2#define AWS_COMMON_RING_BUFFER_H
3/*
4 * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License").
7 * You may not use this file except in compliance with the License.
8 * A copy of the License is located at
9 *
10 * http://aws.amazon.com/apache2.0
11 *
12 * or in the "license" file accompanying this file. This file is distributed
13 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14 * express or implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 */
17
18#include <aws/common/atomics.h>
19
20/**
21 * Lockless ring buffer implementation that is thread safe assuming a single thread acquires and a single thread
22 * releases. For any other use case (other than the single-threaded use-case), you must manage thread-safety manually.
23 *
24 * Also, a very important note: release must happen in the same order as acquire. If you do not your application, and
25 * possibly computers within a thousand mile radius, may die terrible deaths, and the local drinking water will be
26 * poisoned for generations with fragments of what is left of your radioactive corrupted memory.
27 */
28struct aws_ring_buffer {
29 struct aws_allocator *allocator;
30 uint8_t *allocation;
31 struct aws_atomic_var head;
32 struct aws_atomic_var tail;
33 uint8_t *allocation_end;
34};
35
36struct aws_byte_buf;
37
38AWS_EXTERN_C_BEGIN
39
40/**
41 * Initializes a ring buffer with an allocation of size `size`. Returns AWS_OP_SUCCESS on a successful initialization,
42 * AWS_OP_ERR otherwise.
43 */
44AWS_COMMON_API int aws_ring_buffer_init(struct aws_ring_buffer *ring_buf, struct aws_allocator *allocator, size_t size);
45
46/*
47 * Checks whether atomic_ptr correctly points to a memory location within the bounds of the aws_ring_buffer
48 */
49AWS_STATIC_IMPL bool aws_ring_buffer_check_atomic_ptr(
50 const struct aws_ring_buffer *ring_buf,
51 const uint8_t *atomic_ptr);
52/**
53 * Checks whether the ring buffer is empty
54 */
55AWS_STATIC_IMPL bool aws_ring_buffer_is_empty(const struct aws_ring_buffer *ring_buf);
56
57/**
58 * Evaluates the set of properties that define the shape of all valid aws_ring_buffer structures.
59 * It is also a cheap check, in the sense it run in constant time (i.e., no loops or recursion).
60 */
61AWS_STATIC_IMPL bool aws_ring_buffer_is_valid(const struct aws_ring_buffer *ring_buf);
62
63/**
64 * Cleans up the ring buffer's resources.
65 */
66AWS_COMMON_API void aws_ring_buffer_clean_up(struct aws_ring_buffer *ring_buf);
67
68/**
69 * Attempts to acquire `requested_size` buffer and stores the result in `dest` if successful. Returns AWS_OP_SUCCESS if
70 * the requested size was available for use, AWS_OP_ERR otherwise.
71 */
72AWS_COMMON_API int aws_ring_buffer_acquire(
73 struct aws_ring_buffer *ring_buf,
74 size_t requested_size,
75 struct aws_byte_buf *dest);
76
77/**
78 * Attempts to acquire `requested_size` buffer and stores the result in `dest` if successful. If not available, it will
79 * attempt to acquire anywhere from 1 byte to `requested_size`. Returns AWS_OP_SUCCESS if some buffer space is available
80 * for use, AWS_OP_ERR otherwise.
81 */
82AWS_COMMON_API int aws_ring_buffer_acquire_up_to(
83 struct aws_ring_buffer *ring_buf,
84 size_t minimum_size,
85 size_t requested_size,
86 struct aws_byte_buf *dest);
87
88/**
89 * Releases `buf` back to the ring buffer for further use. RELEASE MUST HAPPEN in the SAME ORDER AS ACQUIRE.
90 * If you do not, your application, and possibly computers within a thousand mile radius, may die terrible deaths,
91 * and the local drinking water will be poisoned for generations
92 * with fragments of what is left of your radioactive corrupted memory.
93 */
94AWS_COMMON_API void aws_ring_buffer_release(struct aws_ring_buffer *ring_buffer, struct aws_byte_buf *buf);
95
96/**
97 * Returns true if the memory in `buf` was vended by this ring buffer, false otherwise.
98 * Make sure `buf->buffer` and `ring_buffer->allocation` refer to the same memory region.
99 */
100AWS_COMMON_API bool aws_ring_buffer_buf_belongs_to_pool(
101 const struct aws_ring_buffer *ring_buffer,
102 const struct aws_byte_buf *buf);
103
104/**
105 * Initializes the supplied allocator to be based on the provided ring buffer. Allocations must be allocated
106 * and freed in the same order, or the ring buffer will assert.
107 */
108AWS_COMMON_API int aws_ring_buffer_allocator_init(struct aws_allocator *allocator, struct aws_ring_buffer *ring_buffer);
109
110/**
111 * Cleans up a ring buffer allocator instance. Does not clean up the ring buffer.
112 */
113AWS_COMMON_API void aws_ring_buffer_allocator_clean_up(struct aws_allocator *allocator);
114
115#ifndef AWS_NO_STATIC_IMPL
116# include <aws/common/ring_buffer.inl>
117#endif /* AWS_NO_STATIC_IMPL */
118
119AWS_EXTERN_C_END
120
121#endif /* AWS_COMMON_RING_BUFFER_H */
122