1 /*
2  * Copyright (C) 2010-2020 Red Hat, Inc.
3  *
4  * Author: Angus Salkeld <asalkeld@redhat.com>
5  *
6  * This file is part of libqb.
7  *
8  * libqb is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * libqb is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 #ifndef QB_RB_H_DEFINED
22 #define QB_RB_H_DEFINED
23 
24 /* *INDENT-OFF* */
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 /* *INDENT-ON* */
29 
30 #include <sys/types.h>
31 #include <stdint.h>
32 
33 /**
34  * @file qbrb.h
35  * This implements a ring buffer that works in "chunks", not bytes.
36  * So you write/read a complete chunk or not at all.
37  * There are two types of ring buffer: normal and overwrite.
38  * Overwrite will reclaim the oldest chunks inorder to make way for new ones,
39  * the normal version will refuse to write a new chunk if the ring buffer
40  * is full.
41  *
42  * This implementation is capable of working across processes, but one process
43  * must only write and the other process read.
44  *
45  * The read process will do the following:
46  * @code
47  *	rb = qb_rb_open("test2", 2000, QB_RB_FLAG_SHARED_PROCESS|QB_RB_FLAG_CREATE);
48  *	for (i = 0; i < 200; i++) {
49  * try_read_again:
50  *		l = qb_rb_chunk_read(rb, (void *)out, 32, 1000);
51  *		if (l < 0) {
52  *			goto try_read_again;
53  *		}
54  *	}
55  *	...
56  *	qb_rb_close(rb);
57  *
58  * @endcode
59  *
60  * The write process will do the following:
61  * @code
62  *	rb = qb_rb_open("test2", 2000, QB_RB_FLAG_SHARED_PROCESS);
63  *	for (i = 0; i < 200; i++) {
64  * try_write_again:
65  *		l = qb_rb_chunk_write(rb, &v, sizeof(v));
66  *		if (l < sizeof(v)) {
67  *			goto try_write_again;
68  *		}
69  *	}
70  *	...
71  *	qb_rb_close(rb);
72  * @endcode
73  *
74  * @author Angus Salkeld <asalkeld@redhat.com>
75  */
76 
77 /**
78  * Create a ring buffer (rather than open and existing one).
79  * @see qb_rb_open()
80  */
81 #define QB_RB_FLAG_CREATE		0x01
82 /**
83  * New calls to qb_rb_chunk_write() will call qb_rb_chunk_reclaim()
84  * if there is not enough space.
85  * If this is not set then new writes will be refused.
86  * @see qb_rb_open()
87  */
88 #define QB_RB_FLAG_OVERWRITE		0x02
89 /**
90  * The ringbuffer will be shared between pthreads not processes.
91  * This effects the type of locks/semaphores that are used.
92  * @see qb_rb_open()
93  */
94 #define QB_RB_FLAG_SHARED_THREAD	0x04
95 /**
96  * The ringbuffer will be shared between processes.
97  * This effects the type of locks/semaphores that are used.
98  * @see qb_rb_open()
99  */
100 #define QB_RB_FLAG_SHARED_PROCESS	0x08
101 
102 /**
103  * Don't use semaphores, only atomic ops.
104  * This mean that the timeout passed into qb_rb_chunk_read()
105  * will be ignored.
106  */
107 #define QB_RB_FLAG_NO_SEMAPHORE		0x10
108 
109 struct qb_ringbuffer_s;
110 typedef struct qb_ringbuffer_s qb_ringbuffer_t;
111 
112 /**
113  * Create the ring buffer with the given type.
114  *
115  * This creates allocates a ring buffer in shared memory.
116  *
117  * @param name the unique name of this ringbuffer.
118  * @param size the requested size.
119  * @param flags or'ed flags
120  * @param shared_user_data_size size for a shared data area.
121  * @note the actual size will be rounded up to the next page size.
122  * @return a new ring buffer or NULL if there was a problem.
123  * @see QB_RB_FLAG_CREATE, QB_RB_FLAG_OVERWRITE, QB_RB_FLAG_SHARED_THREAD, QB_RB_FLAG_SHARED_PROCESS
124  */
125 qb_ringbuffer_t *qb_rb_open(const char *name, size_t size, uint32_t flags,
126 			    size_t shared_user_data_size);
127 
128 /**
129  * Dereference the ringbuffer and, if we are the last user, destroy it.
130  *
131  * All files, mmaped memory, semaphores and locks will be destroyed.
132  *
133  * @param rb ringbuffer instance
134  */
135 void qb_rb_close(qb_ringbuffer_t * rb);
136 
137 /**
138  * Get the name of the ringbuffer.
139  * @param rb ringbuffer instance
140  * @return name.
141  */
142 char *qb_rb_name_get(qb_ringbuffer_t * rb);
143 
144 /**
145  * Get a point to user shared data area.
146  *
147  * @note this is of size "shared_user_data_size" passed into qb_rb_open()
148  *
149  * @param rb ringbuffer instance
150  * @return pointer to shared data.
151  */
152 void *qb_rb_shared_user_data_get(qb_ringbuffer_t * rb);
153 
154 /**
155  * Write a chunk to the ring buffer.
156  *
157  * This simply calls qb_rb_chunk_alloc() and then
158  * qb_rb_chunk_commit().
159  *
160  * @param rb ringbuffer instance
161  * @param data (in) the data to write
162  * @param len (in) the size of the chunk.
163  * @return the amount of bytes actually buffered (either len or -1).
164  *
165  * @see qb_rb_chunk_alloc()
166  * @see qb_rb_chunk_commit()
167  */
168 ssize_t qb_rb_chunk_write(qb_ringbuffer_t * rb, const void *data, size_t len);
169 
170 /**
171  * Allocate space for a chunk of the given size.
172  *
173  * If type == QB_RB_FLAG_OVERWRITE and NULL is returned, memory corruption of
174  * the memory file has occurred. The ringbuffer should be destroyed.
175  * If type == QB_RB_NORMAL then when there is not enough space it will
176  * return NULL.
177  *
178  * @param rb ringbuffer instance
179  * @param len (in) the size to allocate.
180  * @return pointer to chunk to write to, or NULL (if no space).
181  *
182  * @see qb_rb_chunk_alloc()
183  */
184 void *qb_rb_chunk_alloc(qb_ringbuffer_t * rb, size_t len);
185 
186 /**
187  * Finalize the chunk.
188  * @param rb ringbuffer instance
189  * @param len (in) the size of the chunk.
190  */
191 int32_t qb_rb_chunk_commit(qb_ringbuffer_t * rb, size_t len);
192 
193 /**
194  * Read (without reclaiming) the last chunk.
195  *
196  * This function is a way of accessing the next chunk without a memcpy().
197  * You can read the chunk data in place.
198  *
199  * @note This function will not "pop" the chunk, you will need to call
200  * qb_rb_chunk_reclaim().
201  * @param rb ringbuffer instance
202  * @param data_out (out) a pointer to the next chunk to read (not copied).
203  * @param ms_timeout (in) time to wait for new data.
204  *
205  * @return the size of the chunk (0 if buffer empty).
206  */
207 ssize_t qb_rb_chunk_peek(qb_ringbuffer_t * rb, void **data_out,
208 			 int32_t ms_timeout);
209 
210 /**
211  * Reclaim the oldest chunk.
212  * You will need to call this if using qb_rb_chunk_peek().
213  * @param rb ringbuffer instance
214  */
215 void qb_rb_chunk_reclaim(qb_ringbuffer_t * rb);
216 
217 /**
218  * Read the oldest chunk into data_out.
219  *
220  * This is the same as qb_rb_chunk_peek() memcpy() and qb_rb_chunk_reclaim().
221  *
222  * @param rb ringbuffer instance
223  * @param data_out (in/out) the chunk will be memcpy'ed into this.
224  * @param len (in) the size of data_out.
225  * @param ms_timeout the amount od time to wait for new data.
226  * @return the size of the chunk, or error.
227  */
228 ssize_t qb_rb_chunk_read(qb_ringbuffer_t * rb, void *data_out, size_t len,
229 			 int32_t ms_timeout);
230 
231 /**
232  * Get the reference count.
233  *
234  * @param rb ringbuffer instance
235  * @return the number of references
236  */
237 int32_t qb_rb_refcount_get(qb_ringbuffer_t * rb);
238 
239 /**
240  * The amount of free space in the ring buffer.
241  *
242  * @note Some of this space will be consumed by the chunk headers.
243  * @param rb ringbuffer instance
244  */
245 ssize_t qb_rb_space_free(qb_ringbuffer_t * rb);
246 
247 /**
248  * The total amount of data in the buffer.
249  *
250  * @note This includes the chunk headers (8 bytes per chunk).
251  * @param rb ringbuffer instance
252  */
253 ssize_t qb_rb_space_used(qb_ringbuffer_t * rb);
254 
255 /**
256  * The total number of chunks in the buffer.
257  *
258  * @param rb ringbuffer instance
259  */
260 ssize_t qb_rb_chunks_used(qb_ringbuffer_t * rb);
261 
262 /**
263  * Write the contents of the Ring Buffer to file.
264  * @param fd open file to write the ringbuffer data to.
265  * @param rb ringbuffer instance
266  * @see qb_rb_create_from_file()
267  */
268 ssize_t qb_rb_write_to_file(qb_ringbuffer_t * rb, int32_t fd);
269 
270 /**
271  * Load the saved ring buffer from file into temporary memory.
272  * @param fd file with saved ringbuffer data.
273  * @param flags same flags as passed into qb_rb_open()
274  * @return new ringbuffer instance
275  * @see qb_rb_write_to_file()
276  */
277 qb_ringbuffer_t *qb_rb_create_from_file(int32_t fd, uint32_t flags);
278 
279 /**
280  * Like 'chown', it changes the owner and group of the ringbuffer's
281  * resources.
282  * @param owner uid of the owner to change to
283  * @param group gid of the group to change to
284  * @param rb ringbuffer instance
285  * @return status (0 = ok, -errno for error)
286  */
287 int32_t qb_rb_chown(qb_ringbuffer_t * rb, uid_t owner, gid_t group);
288 
289 /**
290  * Like 'chmod', it changes the mode of the ringbuffer's resources.
291  * @param mode mode to change to
292  * @param rb ringbuffer instance
293  * @retval 0 == ok
294  * @retval -errno for error
295  */
296 int32_t qb_rb_chmod(qb_ringbuffer_t * rb, mode_t mode);
297 
298 /* *INDENT-OFF* */
299 #ifdef __cplusplus
300 }
301 #endif /* __cplusplus */
302 /* *INDENT-ON* */
303 
304 #endif /* QB_RB_H_DEFINED */
305