Libtrap: Internal development docs  0.11.7
trap_buffer.h
Go to the documentation of this file.
1 /**
2  * \file trap_buffer.h
3  * \brief TRAP ring buffer data structure
4  * \author Tomas Cejka <cejkat@cesnet.cz>
5  * \date 2016
6  */
7 /*
8  * Copyright (C) 2016 CESNET
9  *
10  * LICENSE TERMS
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  * notice, this list of conditions and the following disclaimer in
19  * the documentation and/or other materials provided with the
20  * distribution.
21  * 3. Neither the name of the Company nor the names of its contributors
22  * may be used to endorse or promote products derived from this
23  * software without specific prior written permission.
24  *
25  * ALTERNATIVELY, provided that this notice is retained in full, this
26  * product may be distributed under the terms of the GNU General Public
27  * License (GPL) version 2 or later, in which case the provisions
28  * of the GPL apply INSTEAD OF those given above.
29  *
30  * This software is provided ``as is'', and any express or implied
31  * warranties, including, but not limited to, the implied warranties of
32  * merchantability and fitness for a particular purpose are disclaimed.
33  * In no event shall the company or contributors be liable for any
34  * direct, indirect, incidental, special, exemplary, or consequential
35  * damages (including, but not limited to, procurement of substitute
36  * goods or services; loss of use, data, or profits; or business
37  * interruption) however caused and on any theory of liability, whether
38  * in contract, strict liability, or tort (including negligence or
39  * otherwise) arising in any way out of the use of this software, even
40  * if advised of the possibility of such damage.
41  *
42  */
43 
44 #ifndef TRAP_BUFFER_H
45 #define TRAP_BUFFER_H
46 
47 #include <pthread.h>
48 #include <stdint.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <arpa/inet.h>
52 
53 #define TB_SUCCESS 0
54 #define TB_ERROR 1
55 #define TB_FULL 2
56 #define TB_USED_NEWBLOCK 3
57 #define TB_EMPTY 4
58 
59 
61  /**
62  * Size of stored data, it must be always <= (blocksize - sizeof(size)).
63  *
64  * If the size is 0, the block is free.
65  */
66  uint32_t size;
67  /**
68  * Pointer to the beginning of data stored in this block
69  */
70  char data[0];
71 };
72 
73 typedef struct tb_block_s {
74  /**
75  * Pointer to the space for adding new data (to the header of message)
76  */
77  char *write_data;
78 
79  /**
80  * Pointer to the space for adding new data (to the header of message)
81  */
82  char *read_data;
83 
84  /**
85  * Reference counter with non-zero value means that the block is used and cannot be freed.
86  */
87  uint16_t refcount;
88 
89  /**
90  * Lock the block
91  */
92  pthread_mutex_t lock;
93 
94  /**
95  * Pointer to data in the block (to the header of the first message)
96  */
97  struct tb_block_data_s data[0];
98 } tb_block_t;
99 
100 typedef struct trap_buffer_s {
101  /**
102  * Pointer to internal memory containing the whole ring buffer.
103  */
104  char *mem;
105 
106  /**
107  * Pointer to current block
108  */
110 
111  /**
112  * Array of pointers to blocks.
113  */
115  /**
116  * Index of current block to spare computation when moving to next block
117  */
119 
120  /**
121  * Pointer to current block
122  */
124 
125  /**
126  * Index of current block to spare computation when moving to next block
127  */
129 
130  /**
131  * Maximal size of tb_block_data_s element (containing data + 32b header).
132  */
133  uint32_t blocksize;
134 
135  /**
136  * Number of blocks in the buffer.
137  */
138  uint16_t nblocks;
139 
140  /**
141  * Lock the buffer
142  */
143  pthread_mutex_t lock;
144 } trap_buffer_t;
145 
146 /**
147  * \defgroup trap_buffer_general General API
148  * @{
149  */
150 
151 /**
152  * Create a new buffer that will work wit nblocks of block_size.
153  * \param[in] nblocks Number of blocks that will be stored in the ring buffer.
154  * \param[in] blocksize Maximal size of each block.
155  * \return Pointer to the buffer struct, NULL on error.
156  */
157 trap_buffer_t *tb_init(uint16_t nblocks, uint32_t blocksize);
158 
159 /**
160  * Free memory and set the pointer to NULL.
161  * \param[in] tb Pointer to the TRAP buffer.
162  */
163 void tb_destroy(trap_buffer_t **tb);
164 
165 /**
166  * Lock buffer before manipulation.
167  * \param[in] tb Pointer to the TRAP buffer.
168  */
169 int tb_lock(trap_buffer_t *tb);
170 
171 /**
172  * Unlock buffer after manipulation.
173  * \param[in] tb Pointer to the TRAP buffer.
174  */
175 int tb_unlock(trap_buffer_t *tb);
176 
177 /**
178  * Lock block before manipulation.
179  * \param[in] bl Pointer to the TRAP buffer.
180  */
181 int tb_block_lock(tb_block_t *bl);
182 
183 /**
184  * Unlock block after manipulation.
185  */
186 int tb_block_unlock(tb_block_t *bl);
187 
188 /**
189  * Check if the current block is free.
190  *
191  * \param[in] bl Pointer to the block.
192  * \return TB_SUCCESS when the current block is free, TB_FULL if it contains at least one message.
193  */
194 int tb_isblockfree(tb_block_t *bl);
195 
196 /**
197  * @}
198  */
199 
200 /**
201  * \defgroup trap_buffer_send Output IFC
202  * A set of functions used for output IFC (module sends messages).
203  * @{
204  */
205 /**
206  * Push message into the current block
207  * \param[in] tb Pointer to the buffer.
208  * \param[in] data Pointer to the message to send.
209  * \param[in] size Size of the message to send.
210  * \return TB_SUCCESS or TB_USED_NEWBLOCK when the message was stored
211  * successfuly, TB_FULL when there is no place for the message.
212  * TB_USED_NEWBLOCK indicates that the current block was changed.
213  * TB_ERROR means that size is bigger than block size.
214  */
215 int tb_pushmess(trap_buffer_t *tb, const void *data, uint16_t size);
216 
217 /**
218  * Push message (consisting of d1 and d2 parts) into the current block
219  * \param[in] tb Pointer to the buffer.
220  * \param[in] d1 Pointer to the 1st part of the message to send.
221  * \param[in] s1 Size of the 1st part of the message to send.
222  * \param[in] d2 Pointer to the 2nd part of the message to send.
223  * \param[in] s2 Size of the 2nd part of the message to send.
224  * \return TB_SUCCESS or TB_USED_NEWBLOCK when the message was stored
225  * successfuly, TB_FULL when there is no place for the message.
226  * TB_USED_NEWBLOCK indicates that the current block was changed.
227  * TB_ERROR means that size is bigger than block size.
228  */
229 int tb_pushmess2(trap_buffer_t *tb, const void *d1, uint16_t s1, const void *d2, uint16_t s2);
230 
231 /**
232  * Go through all blocks and those which are not used (refcount) mark as free.
233  *
234  * \param[in] tb Pointer to the TRAP buffer.
235  */
237 
238 /**
239  * Move to the next block for writing.
240  *
241  * This function moves cur_block pointer to the next block (it overflows after nblocks).
242  * \param[in] tb Pointer to the TRAP buffer
243  */
245 
246 /**
247  * Move to the first block for writing.
248  *
249  * This function moves cur_block pointer to the first block.
250  * \param[in] tb Pointer to the TRAP buffer
251  */
253 
254 /**
255  * Lock the current free block for getting its content.
256  *
257  * After this code, it is possible to read size and data from bl.
258  * See TB_FLUSH_START() for unlocking the block.
259  *
260  * Pseudocode:
261  * trap_buffer_t *b = tb_init(10, 100000);
262  * tb_block_t *bl;
263  * TB_FILL_START(b, &bl, res);
264  * if (res == TB_SUCCESS) {
265  * s = recv(...);
266  * TB_FILL_END(b, bl, s);
267  * }
268  *
269  * \param[in] wrb Pointer to the buffer.
270  * \param[out] bl Pointer to block (tb_block_t **bl).
271  * \param[out] res Result of TB_FILL_START(), it is set to TB_SUCCESS or TB_FULL.
272  */
273 #define TB_FLUSH_START(wrb, bl, res) do { \
274  tb_lock(wrb); \
275  (*bl) = wrb->cur_rd_block; \
276  tb_block_lock(*bl); \
277  if (tb_isblockfree(*bl) != TB_FULL) { \
278  /* current block is not free, we must unlock and wait */ \
279  tb_block_unlock(*bl); \
280  res = TB_EMPTY; \
281  } else { \
282  res = TB_FULL; \
283  } \
284  tb_unlock(wrb); \
285  } while (0)
286 
287 /**
288  * Unlock the current free block after writing its content.
289  *
290  * It MUST NOT be called when TB_FILL_START() returned TB_FULL.
291  *
292  * \param[in] rdb Pointer to the buffer.
293  * \param[in] bl Pointer to block (tb_block_t *bl).
294  * \param[in] s Size of data written into the block. This will be set into header.
295  */
296 #define TB_FLUSH_END(rdb, bl, s) do { \
297  if (bl->refcount == 0) { \
298  /* block can be marked as empty for next pushmess() */ \
299  bl->data->size = 0; \
300  tb_next_rd_block(rdb); \
301  } \
302  tb_block_unlock(bl); \
303  } while (0)
304 
305 /**
306  * @}
307  */
308 
309 /**
310  * \defgroup trap_buffer_recv Input IFC
311  * A set of functions used for input IFC (module receives messages).
312  * @{
313  */
314 
315 /**
316  * Get message from buffer.
317  * \param[in] tb Pointer to the buffer.
318  * \param[out] data Pointer to read message.
319  * \param[out] size Size of read message.
320  * \return TB_SUCCESS or TB_USED_NEWBLOCK when the message was read
321  * successfuly, TB_EMPTY when there is no message in the buffer to read.
322  * TB_USED_NEWBLOCK indicates that the current block was changed
323  */
324 int tb_getmess(trap_buffer_t *tb, const void **data, uint16_t *size);
325 
326 /**
327  * Move to the first block for reading.
328  *
329  * This function moves cur_block pointer to the first block.
330  * \param[in] tb Pointer to the buffer.
331  */
333 
334 
335 /**
336  * Move to the next block for reading.
337  *
338  * This function moves cur_block pointer to the next block (it overflows after nblocks).
339  * \param[in] tb Pointer to the buffer.
340  */
342 
343 /**
344  * Lock the current free block for writing its content.
345  *
346  * After this code, it is possible to write size and data into bl.
347  * See TB_FILL_END() for unlocking the block.
348  *
349  * Pseudocode:
350  * trap_buffer_t *b = tb_init(10, 100000);
351  * tb_block_t *bl;
352  * TB_FILL_START(b, &bl, res);
353  * if (res == TB_SUCCESS) {
354  * s = recv(...);
355  * TB_FILL_END(b, bl, s);
356  * }
357  *
358  * \param[in] rdb Pointer to the buffer.
359  * \param[out] bl Pointer to block (tb_block_t **bl).
360  * \param[out] res Result of TB_FILL_START(), it is set to TB_SUCCESS or TB_FULL.
361  */
362 #define TB_FILL_START(rdb, bl, res) do { \
363  tb_lock(rdb); \
364  (*bl) = rdb->cur_wr_block; \
365  tb_block_lock(*bl); \
366  if (tb_isblockfree(*bl) == TB_SUCCESS) { \
367  tb_next_wr_block(rdb); \
368  (res) = TB_SUCCESS; \
369  } else { \
370  /* current block is not free, we must unlock and wait */ \
371  tb_block_unlock(*bl); \
372  (res) = TB_FULL; \
373  } \
374  tb_unlock(rdb); \
375  } while (0)
376 
377 /**
378  * Unlock the current free block after writing its content.
379  *
380  * It MUST NOT be called when TB_FILL_START() returned TB_FULL.
381  *
382  * \param[in] rdb Pointer to the buffer.
383  * \param[in] bl Pointer to block (tb_block_t *bl).
384  * \param[in] s Size of data written into the block. This will be set into header.
385  */
386 #define TB_FILL_END(rdb, bl, s) do { \
387  bl->data->size = s; \
388  bl->write_data += s; \
389  bl->read_data = bl->data->data; \
390  tb_block_unlock(bl); \
391  } while (0)
392 
393 /**
394  * @}
395  */
396 
397 #endif
398 
uint16_t cur_wr_block_idx
Definition: trap_buffer.h:118
int tb_unlock(trap_buffer_t *tb)
Definition: trap_buffer.c:217
void tb_first_rd_block(trap_buffer_t *tb)
Definition: trap_buffer.c:123
int tb_pushmess2(trap_buffer_t *tb, const void *d1, uint16_t s1, const void *d2, uint16_t s2)
Definition: trap_buffer.c:291
pthread_mutex_t lock
Definition: trap_buffer.h:92
uint16_t cur_rd_block_idx
Definition: trap_buffer.h:128
void tb_next_rd_block(trap_buffer_t *tb)
Definition: trap_buffer.c:113
char * read_data
Definition: trap_buffer.h:82
uint32_t size
Definition: trap_buffer.h:66
int tb_block_unlock(tb_block_t *bl)
Definition: trap_buffer.c:227
int tb_lock(trap_buffer_t *tb)
Definition: trap_buffer.c:212
uint16_t refcount
Definition: trap_buffer.h:87
uint8_t data[0]
struct tb_block_s tb_block_t
void tb_first_wr_block(trap_buffer_t *tb)
Definition: trap_buffer.c:130
int tb_pushmess(trap_buffer_t *tb, const void *data, uint16_t size)
Definition: trap_buffer.c:262
void tb_destroy(trap_buffer_t **tb)
Definition: trap_buffer.c:191
int tb_block_lock(tb_block_t *bl)
Definition: trap_buffer.c:222
tb_block_t ** blocks
Definition: trap_buffer.h:114
void tb_next_wr_block(trap_buffer_t *tb)
Definition: trap_buffer.c:103
void tb_clear_unused(trap_buffer_t *tb)
Definition: trap_buffer.c:357
trap_buffer_t * tb_init(uint16_t nblocks, uint32_t blocksize)
Definition: trap_buffer.c:146
uint32_t blocksize
Definition: trap_buffer.h:133
tb_block_t * cur_wr_block
Definition: trap_buffer.h:109
char * write_data
Definition: trap_buffer.h:77
uint16_t nblocks
Definition: trap_buffer.h:138
struct trap_buffer_s trap_buffer_t
pthread_mutex_t lock
Definition: trap_buffer.h:143
int tb_getmess(trap_buffer_t *tb, const void **data, uint16_t *size)
Definition: trap_buffer.c:323
int tb_isblockfree(tb_block_t *bl)
Definition: trap_buffer.c:137
tb_block_t * cur_rd_block
Definition: trap_buffer.h:123
struct tb_block_data_s data[0]
Definition: trap_buffer.h:97