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