The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
message.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: bdb8eae283d2d7e88bd6fc25fd04034fc0946734 $
19 *
20 * @brief Messages for inter-thread communication
21 * @file io/message.c
22 *
23 * @copyright 2016 Alan DeKok (aland@freeradius.org)
24 */
25RCSID("$Id: bdb8eae283d2d7e88bd6fc25fd04034fc0946734 $")
26
27#include <freeradius-devel/io/message.h>
28#include <freeradius-devel/util/strerror.h>
29
30
31/*
32 * Debugging, mainly for message_set_test
33 */
34#if 0
35#define MPRINT(...) fprintf(stderr, __VA_ARGS__)
36#else
37#define MPRINT(...)
38#endif
39
40#define MSG_ARRAY_SIZE (16)
41
42#define CACHE_ALIGN(_x) do { _x += 63; _x &= ~(size_t) 63; } while (0)
43
44/** A Message set, composed of message headers and ring buffer data.
45 *
46 * A message set is intended to send short-lived messages. The
47 * message headers are fixed in size, and allocated from an array
48 * which is treated like a circular buffer. Message bodies (i.e. raw
49 * packets) are variable in size, and live in a separate ring buffer.
50 *
51 * The message set starts off with a small array of message headers,
52 * and a small ring buffer. If an array/buffer fills up, a new one
53 * is allocated at double the size of the previous one.
54 *
55 * The array / buffers are themselves kept in fixed-size arrays, of
56 * MSG_ARRAY_SIZE. The reason is that the memory for fr_message_set_t
57 * should be contiguous, and not in a linked list scattered in
58 * memory.
59 *
60 * The originator allocates a message, and sends it to a recipient.
61 * The recipient (usually in another thread) uses the message, and
62 * marks it as FR_MESSAGE_DONE. The originator then asynchronously
63 * cleans up the message.
64 *
65 * This asynchronous cleanup is done via self-clocking. If there is
66 * no need to clean up the messages, it isn't done. Only when we run
67 * out of space to store messages (or packets) is the cleanup done.
68 *
69 * This cleanup latency ensures that we don't have cache line
70 * bouncing, where the originator sends the message, and then while
71 * the recipieent is reading it... thrashes the cache line with
72 * checks for "are you done? Are you done?"
73 *
74 * If there are more than one used entry in either array, we then try
75 * to coalesce the buffers on cleanup. If we discover that one array
76 * is empty, we discard it, and move the used array entries into it's
77 * place.
78 *
79 * This process ensures that we don't have too many buffers in
80 * progress. It is better to have a few large buffers than many
81 * small ones.
82 *
83 * MSG_ARRAY_SIZE is defined to be large (16 doublings) to allow for
84 * the edge case where messages are stuck for long periods of time.
85 *
86 * With an initial message array size of 64, this gives us room for
87 * 2M packets, if *all* of the mr_array entries have packets stuck in
88 * them that aren't cleaned up for extended periods of time.
89 *
90 * @todo Add a flag for UDP-style protocols, where we can put the
91 * message into the ring buffer. This helps with locality of
92 * reference, and removes the need to track two separate things.
93 */
95 int mr_current; //!< current used message ring entry
96 int mr_max; //!< max used message ring entry
97
98 size_t message_size; //!< size of the callers message, including fr_message_t
99
100 int mr_cleaned; //!< where we last cleaned
101
102 int rb_current; //!< current used ring buffer entry
103 int rb_max; //!< max used ring buffer entry
104
105 size_t max_allocation; //!< maximum allocation size
106
108 int freed;
109
110 fr_ring_buffer_t *mr_array[MSG_ARRAY_SIZE]; //!< array of message arrays
111
112 fr_ring_buffer_t *rb_array[MSG_ARRAY_SIZE]; //!< array of ring buffers
113};
114
115
116/** Create a message set
117 *
118 * @param[in] ctx the context for talloc
119 * @param[in] num_messages size of the initial message array. MUST be a power of 2.
120 * @param[in] message_size the size of each message, INCLUDING fr_message_t, which MUST be at the start of the struct
121 * @param[in] ring_buffer_size of the ring buffer. MUST be a power of 2.
122 * @param[in] unlimited_size allow any message size to be allocated. If false it is limited to ring_buffer_size / 2.
123 * @return
124 * - NULL on error
125 * - newly allocated fr_message_set_t on success
126 */
127fr_message_set_t *fr_message_set_create(TALLOC_CTX *ctx, int num_messages, size_t message_size, size_t ring_buffer_size,
128 bool unlimited_size)
129{
131
132 /*
133 * Too small, or not a power of 2.
134 */
135 if (num_messages < 8) num_messages = 8;
136
137 if ((num_messages & (num_messages - 1)) != 0) {
138 fr_strerror_const("Number of messages must be a power of 2");
139 return NULL;
140 }
141
142 if (message_size < sizeof(fr_message_t)) {
143 fr_strerror_printf("Message size must be at least %zu", sizeof(fr_message_t));
144 return NULL;
145 }
146
147 if (message_size > 1024) {
148 fr_strerror_const("Message size must be no larger than 1024");
149 return NULL;
150 }
151
152 ms = talloc_zero(ctx, fr_message_set_t);
153 if (!ms) {
154 fr_strerror_const("Failed allocating memory");
155 return NULL;
156 }
157
158 CACHE_ALIGN(message_size);
159 ms->message_size = message_size;
160
161 ms->rb_array[0] = fr_ring_buffer_create(ms, ring_buffer_size);
162 if (!ms->rb_array[0]) {
163 talloc_free(ms);
164 return NULL;
165 }
166 ms->rb_max = 0;
167
168 ms->mr_array[0] = fr_ring_buffer_create(ms, num_messages * message_size);
169 if (!ms->mr_array[0]) {
170 talloc_free(ms);
171 return NULL;
172 }
173
174 /*
175 * If unlimited size is allowed, set the max allocation to 1 << 29
176 * which is based on the maximum ring buffer reservation of 1 << 30
177 */
178 ms->max_allocation = unlimited_size ? 1 << 29 : ring_buffer_size / 2;
179
180 return ms;
181}
182
183
184/** Mark a message as done
185 *
186 * Note that this call is usually done from a thread OTHER than the
187 * originator of the message. As such, the message is NOT actually
188 * freed. Instead, it is just marked as freed.
189 *
190 * @param[in] m the message to make as done.
191 * @return
192 * - <0 on error
193 * - 0 on success
194 */
196{
199
200 /*
201 * Mark a message as freed. The originator will take
202 * care of cleaning it up.
203 */
204 if (m->status == FR_MESSAGE_USED) {
206 return 0;
207 }
208
209 /*
210 * This message was localized, so we can free it via
211 * talloc.
212 */
213 if (m->status == FR_MESSAGE_LOCALIZED) {
214 talloc_free(m);
215 return 0;
216 }
217
218 /*
219 * A catastrophic error.
220 */
221 fr_assert(0 == 1);
222
223 fr_strerror_const("Failed marking message as done");
224 return -1;
225}
226
227
228/** Localize a message by copying it to local storage
229 *
230 * This function "localizes" a message by copying it to local
231 * storage. In the case where the recipient of a message has to sit
232 * on it for a while, that blocks the originator from cleaning up the
233 * message. The recipient can then copy the message to local
234 * storage, so that the originator can clean it up.
235 *
236 * The localized message is marked as FR_MESSAGE_LOCALIZED, so that
237 * the recipient can call the normal fr_message_done() function to
238 * free it.
239 *
240 * @param[in] ctx the talloc context to use for localization
241 * @param[in] m the message to be localized
242 * @param[in] message_size the size of the message, including the fr_message_t
243 * @return
244 * - NULL on allocation error
245 * - a newly localized message
246 */
247fr_message_t *fr_message_localize(TALLOC_CTX *ctx, fr_message_t *m, size_t message_size)
248{
249 fr_message_t *l;
250
251 if (m->status != FR_MESSAGE_USED) {
252 fr_strerror_const("Cannot localize message unless it is in use");
253 return NULL;
254 }
255
256 if (message_size < sizeof(fr_message_t)) {
257 fr_strerror_const("Message size is too small");
258 return NULL;
259 }
260
261 l = talloc_memdup(ctx, m, message_size);
262 if (!l) {
263 nomem:
264 fr_strerror_const("Failed allocating memory");
265 return NULL;
266 }
267
268 l->data = NULL;
269
270 if (l->data_size) {
271 l->data = talloc_memdup(l, m->data, l->data_size);
272 if (!l->data) {
273 talloc_free(l);
274 goto nomem;
275 }
276 }
277
279
280 /*
281 * After this change, "m" should not be used for
282 * anything.
283 */
285
286 /*
287 * Now clean up the other fields of the newly localized
288 * message.
289 */
290 l->rb = NULL;
291 l->rb_size = 0;
292
293 return l;
294}
295
296
297/** Clean up messages in a message ring.
298 *
299 * Find the oldest messages which are marked FR_MESSAGE_DONE,
300 * and mark them FR_MESSAGE_FREE.
301 *
302 * FIXME: If we care, track which ring buffer is in use, and how
303 * many contiguous chunks we can free. Then, free the chunks at
304 * once, instead of piecemeal. Realistically tho... this will
305 * probably make little difference.
306 *
307 * @param[in] ms the message set
308 * @param[in] mr the message ring
309 * @param[in] max_to_clean maximum number of messages to clean at a time.
310 */
311static int message_ring_gc(fr_message_set_t *ms, fr_ring_buffer_t *mr, int max_to_clean)
312{
313 int messages_cleaned = 0;
314 size_t size;
315 fr_message_t *m;
316
317 while (true) {
318 (void) fr_ring_buffer_start(mr, (uint8_t **) &m, &size);
319 if (size == 0) break;
320
321 fr_assert(m != NULL);
322 fr_assert(size >= ms->message_size);
323
325 if (m->status != FR_MESSAGE_DONE) break;
326
327 /*
328 * A data ring buffer only frees from its tail, and
329 * is shared by every message ring. The rings are
330 * collected one at a time, so this message's data
331 * can sit behind a live message from another ring.
332 * Leave it until its data is the oldest in the
333 * buffer, or we free someone else's bytes.
334 */
335 if (m->rb) {
336 uint8_t *start;
337 size_t used;
338
339 (void) fr_ring_buffer_start(m->rb, &start, &used);
340 if (start != m->data) break;
341 }
342
343 messages_cleaned++;
345 ms->freed++;
346
347 if (m->rb) {
348 (void) fr_ring_buffer_free(m->rb, m->rb_size);
349#ifndef NDEBUG
350 memset(m, 0, ms->message_size);
351#endif
352 }
353
355
356 if (messages_cleaned >= max_to_clean) break;
357 }
358
359 MPRINT("CLEANED %d (%p) left\n", messages_cleaned, mr);
360 return messages_cleaned;
361}
362
363
364/** Garbage collect "done" messages.
365 *
366 * Called only from the originating thread. We also clean a limited
367 * number of messages at a time, so that we don't have sudden latency
368 * spikes when cleaning 1M messages.
369 *
370 *
371 * @param[in] ms the message set
372 * @param[in] max_to_clean the maximum number of messages to clean
373 * @param[in] compact whether to free empty rings and repack the arrays
374 */
375static void message_gc(fr_message_set_t *ms, int max_to_clean, bool compact)
376{
377 int i;
378 int arrays_freed, arrays_used, empty_slot;
379 int largest_free_slot;
380 int total_cleaned;
381 size_t largest_free_size;
382
383 /*
384 * Clean up "done" messages.
385 */
386 total_cleaned = 0;
387
388 /*
389 * Garbage collect the smaller buffers first.
390 */
391 for (i = 0; i <= ms->mr_max; i++) {
392 int cleaned;
393
394 cleaned = message_ring_gc(ms, ms->mr_array[i], max_to_clean - total_cleaned);
395 total_cleaned += cleaned;
396 fr_assert(total_cleaned <= max_to_clean);
397
398 /*
399 * Stop when we've reached our GC limit.
400 */
401 if (total_cleaned == max_to_clean) break;
402 }
403
404 /*
405 * Couldn't GC anything. Don't do more work.
406 */
407 if (total_cleaned == 0) return;
408
409 if (!compact) return;
410
411 arrays_freed = 0;
412 arrays_used = 0;
413
414 /*
415 * Keep the two largest message buffers (used or not),
416 * and free all smaller ones which are empty.
417 */
418 for (i = ms->mr_max; i >= 0; i--) {
419 fr_assert(ms->mr_array[i] != NULL);
420
421 if (arrays_used < 2) {
422 MPRINT("\tleaving entry %d alone\n", i);
423 arrays_used++;
424 continue;
425 }
426
427 /*
428 * If the message ring buffer is empty, check if
429 * we should perhaps delete it.
430 */
431 if (fr_ring_buffer_used(ms->mr_array[i]) == 0) {
432 MPRINT("\tfreeing entry %d\n", i);
433 TALLOC_FREE(ms->mr_array[i]);
434 arrays_freed++;
435 continue;
436 }
437
438 MPRINT("\tstill in use entry %d\n", i);
439 }
440
441 /*
442 * Some entries have been freed. We need to coalesce the
443 * remaining entries.
444 */
445 if (arrays_freed) {
446 MPRINT("TRYING TO PACK from %d free arrays out of %d\n", arrays_freed, ms->rb_max + 1);
447
448 empty_slot = -1;
449
450 /*
451 * Pack the rb array by moving used entries to
452 * the bottom of the array.
453 */
454 for (i = 0; i <= ms->mr_max; i++) {
455 int j;
456
457 /*
458 * Skip over empty entries, but set
459 * "empty_slot" to the first empty on we
460 * found.
461 */
462 if (!ms->mr_array[i]) {
463 if (empty_slot < 0) empty_slot = i;
464
465 continue;
466 }
467
468 /*
469 * This array entry is used, but there is
470 * no empty slot to put it into. Ignore
471 * it, and continue
472 */
473 if (empty_slot < 0) continue;
474
475 fr_assert(ms->mr_array[empty_slot] == NULL);
476
477 ms->mr_array[empty_slot] = ms->mr_array[i];
478 ms->mr_array[i] = NULL;
479
480 /*
481 * Find the next empty slot which is
482 * greater than the one we just used.
483 */
484 for (j = empty_slot + 1; j <= i; j++) {
485 if (!ms->mr_array[j]) {
486 empty_slot = j;
487 break;
488 }
489 }
490 }
491
492 /*
493 * Lower max, and set current to the largest
494 * array, whether or not it's used.
495 */
496 ms->mr_max -= arrays_freed;
497 ms->mr_current = ms->mr_max;
498
499#ifndef NDEBUG
500 MPRINT("NUM RB ARRAYS NOW %d\n", ms->mr_max + 1);
501 for (i = 0; i <= ms->mr_max; i++) {
502 MPRINT("\t%d %p\n", i, ms->mr_array[i]);
503 fr_assert(ms->mr_array[i] != NULL);
504 }
505#endif
506 }
507
508 /*
509 * And now we do the same thing for the ring buffers.
510 * Except that freeing the messages above also cleaned up
511 * the contents of each ring buffer, so all we need to do
512 * is find the largest empty ring buffer.
513 *
514 * We do this by keeping the two largest ring buffers
515 * (used or not), and then freeing all smaller ones which
516 * are empty.
517 */
518 arrays_used = 0;
519 arrays_freed = 0;
520 MPRINT("TRYING TO FREE ARRAYS %d\n", ms->rb_max);
521 for (i = ms->rb_max; i >= 0; i--) {
522 fr_assert(ms->rb_array[i] != NULL);
523
524 if (arrays_used < 2) {
525 MPRINT("\tleaving entry %d alone\n", i);
526 arrays_used++;
527 continue;
528 }
529
530 if (fr_ring_buffer_used(ms->rb_array[i]) == 0) {
531 MPRINT("\tfreeing entry %d\n", i);
532 TALLOC_FREE(ms->rb_array[i]);
533 arrays_freed++;
534 continue;
535 }
536
537 MPRINT("\tstill in use entry %d\n", i);
538 }
539
540 /*
541 * Pack the array entries back down.
542 */
543 if (arrays_freed > 0) {
544 MPRINT("TRYING TO PACK from %d free arrays out of %d\n", arrays_freed, ms->rb_max + 1);
545
546 empty_slot = -1;
547
548 /*
549 * Pack the rb array by moving used entries to
550 * the bottom of the array.
551 */
552 for (i = 0; i <= ms->rb_max; i++) {
553 int j;
554
555 /*
556 * Skip over empty entries, but set
557 * "empty_slot" to the first empty on we
558 * found.
559 */
560 if (!ms->rb_array[i]) {
561 if (empty_slot < 0) empty_slot = i;
562
563 continue;
564 }
565
566 /*
567 * This array entry is used, but there is
568 * no empty slot to put it into. Ignore
569 * it, and continue
570 */
571 if (empty_slot < 0) continue;
572
573 fr_assert(ms->rb_array[empty_slot] == NULL);
574
575 ms->rb_array[empty_slot] = ms->rb_array[i];
576 ms->rb_array[i] = NULL;
577
578 /*
579 * Find the next empty slot which is
580 * greater than the one we just used.
581 */
582 for (j = empty_slot + 1; j <= i; j++) {
583 if (!ms->rb_array[j]) {
584 empty_slot = j;
585 break;
586 }
587 }
588 }
589
590 /*
591 * Lower max, and set current to the largest
592 * array, whether or not it's used.
593 */
594 ms->rb_max -= arrays_freed;
595 ms->rb_current = ms->rb_max;
596
597#ifndef NDEBUG
598 MPRINT("NUM RB ARRAYS NOW %d\n", ms->rb_max + 1);
599 for (i = 0; i <= ms->rb_max; i++) {
600 MPRINT("\t%d %p\n", i, ms->rb_array[i]);
601 fr_assert(ms->rb_array[i] != NULL);
602 }
603#endif
604 }
605
606 /*
607 * Set the current ring buffer to the one with the
608 * largest free space in it.
609 *
610 * This is different from the allocation strategy for
611 * messages.
612 */
613 if (!fr_cond_assert(ms->rb_array[ms->rb_max] != NULL)) return;
614
615 largest_free_slot = ms->rb_max;
616 largest_free_size = (fr_ring_buffer_size(ms->rb_array[ms->rb_max]) -
618
619 for (i = 0; i < ms->rb_max; i++) {
620 size_t free_size;
621
622 fr_assert(ms->rb_array[i] != NULL);
623
624 free_size = (fr_ring_buffer_size(ms->rb_array[i]) -
626 if (largest_free_size < free_size) {
627 largest_free_slot = i;
628 largest_free_size = free_size;
629 }
630 }
631
632 ms->rb_current = largest_free_slot;
633 fr_assert(ms->rb_current >= 0);
634 fr_assert(ms->rb_current <= ms->rb_max);
635}
636
637typedef uint8_t *(*fr_ring_buffer_op_t)(fr_ring_buffer_t *rb, size_t size);
638
639/** Find a message ring with space, performing GC and expansion as needed.
640 *
641 * The caller passes in the operation to perform on the ring buffer
642 * (fr_ring_buffer_alloc or fr_ring_buffer_reserve). This function
643 * handles GC, searching across all message rings, and doubling the
644 * ring size when all are full.
645 *
646 * @param[out] p_cleaned a flag to indicate if we cleaned the message array
647 * @param[in] ms the message set
648 * @param[in] op the ring buffer operation (alloc or reserve)
649 * @return
650 * - NULL on error
651 * - pointer to message-sized region on success
652 */
653static inline CC_HINT(always_inline)
655{
656 int i;
657 uint8_t *p;
659
660 *p_cleaned = false;
661
662 /*
663 * Grab the current message array. In the general case,
664 * there's room, so we grab a message and go find a ring
665 * buffer.
666 */
667 mr = ms->mr_array[ms->mr_current];
668 p = op(mr, ms->message_size);
669 if (p) {
670 MPRINT("RING FIND normal\n");
671 return p;
672 }
673
674 MPRINT("CLEANING UP (%d - %d = %d)\n", ms->allocated, ms->freed,
675 ms->allocated - ms->freed);
676
677 /*
678 * Else the buffer is full. Do a global cleanup.
679 */
680 message_gc(ms, 128, true);
681 *p_cleaned = true;
682
683 /*
684 * If we're lucky, the cleanup has given us a new
685 * "current" buffer, which is empty. If so, use it.
686 *
687 * Do a small per-ring GC first to free up the oldest
688 * entries. This results in a small amount of cache line
689 * thrashing, but if the buffer is full, it's likely
690 * that the oldest entry can be freed.
691 */
692 mr = ms->mr_array[ms->mr_current];
693 (void) message_ring_gc(ms, mr, 4);
694 p = op(mr, ms->message_size);
695 if (p) {
696 MPRINT("RING FIND after cleanup\n");
697 return p;
698 }
699
700 /*
701 * We've tried two allocations, and both failed. Brute
702 * force over all arrays, trying to allocate one
703 * somewhere... anywhere. We start from the largest
704 * array, because that is the one we want to use the
705 * most.
706 *
707 * We want to avoid allocations in the smallest array,
708 * because that array will quickly wrap, and will cause
709 * us to do cleanups more often. That also lets old
710 * entries in the smallest array age out, so that we can
711 * free the smallest arrays.
712 */
713 for (i = ms->mr_max; i >= 0; i--) {
714 mr = ms->mr_array[i];
715
716 (void) message_ring_gc(ms, mr, 4);
717 p = op(mr, ms->message_size);
718 if (p) {
719 ms->mr_current = i;
720 MPRINT("RING FIND from changed ring buffer\n");
721 MPRINT("SET MR to changed %d\n", ms->mr_current);
722 return p;
723 }
724 }
725
726 /*
727 * All of the arrays are full. If we don't have
728 * room to allocate another array, we're dead.
729 */
730 if ((ms->mr_max + 1) >= MSG_ARRAY_SIZE) {
731 fr_strerror_const("All message arrays are full");
732 return NULL;
733 }
734
735 /*
736 * Allocate another message ring, double the size
737 * of the previous maximum.
738 */
739 mr = fr_ring_buffer_create(ms, fr_ring_buffer_size(ms->mr_array[ms->mr_max]) * 2);
740 if (!mr) {
741 fr_strerror_const_push("Failed allocating ring buffer");
742 return NULL;
743 }
744
745 /*
746 * Set the new one as current for all new
747 * allocations, and perform the operation on the
748 * entirely empty message ring.
749 */
750 ms->mr_max++;
751 ms->mr_current = ms->mr_max;
752 ms->mr_array[ms->mr_max] = mr;
753
754 MPRINT("SET MR to doubled %d\n", ms->mr_current);
755
756 return op(mr, ms->message_size);
757}
758
759/** Allocate a fr_message_t, WITHOUT a ring buffer
760 *
761 * @param[in] ms the message set
762 * @param[out] p_cleaned a flag to indicate if we cleaned the message array
763 * @return
764 * - NULL on error
765 * - fr_message_t* on success
766 */
767static inline CC_HINT(always_inline) fr_message_t *message_alloc(fr_message_set_t *ms, bool *p_cleaned)
768{
769 fr_message_t *m;
770
772 if (!m) return NULL;
773
774 memset(m, 0, ms->message_size);
776 ms->allocated++;
777
778 return m;
779}
780
781/** Reserve a fr_message_t, WITHOUT a ring buffer
782 *
783 * @note This only _reserves_ the message, i.e. checks there's space, and initialises the message
784 * memory, it does not perform the actual allocation. This is useful if there are error
785 * paths which could result in the message needing to be returned to the message set without
786 * being used. Multiple pending reservations are NOT permitted.
787 *
788 * @param[in] ms the message set to reserve the message in.
789 * @param[out] p_cleaned a flag to indicate if we cleaned the message array
790 * @return
791 * - NULL on error
792 * - fr_message_t* on success
793 */
794static inline CC_HINT(always_inline) fr_message_t *message_reserve(fr_message_set_t *ms, bool *p_cleaned)
795{
796 fr_message_t *m;
797
799 if (!m) return NULL;
800
801 memset(m, 0, ms->message_size);
803
804 return m;
805}
806
807/** Finalise a reserved message allocation
808 *
809 * @note This finalises the allocation of a previous message. No additional reserve calls can be made
810 * between the one that initialised memory for m, and this finalise call.
811 *
812 * @param[in] ms the message set to finalise the allocation in.
813 * @param[in] m the message to perform the allocation for.
814 * @return
815 * - <0 on error
816 * - 0 on success.
817 */
818static inline CC_HINT(always_inline) int message_finalise(fr_message_set_t *ms, fr_message_t *m)
819{
820 bool cleaned = false;
821 fr_message_t *nm;
822
823 /*
824 * This _should_ use the same ring as before, unless someone has
825 * interleaved _another_ reserve call between the initial reserve
826 * call and this finalisation.
827 */
829 if (!fr_cond_assert_msg(nm == m, "Alloc interleaved between reserving and finalising message allocation %p", m)) {
830 return -1;
831 }
832
833 ms->allocated++;
834
835 return 0;
836}
837
838/** Reserve data in a ring buffer for this message
839 *
840 * @param[in] ms the message set
841 * @param[in] m the message
842 * @param[in] cleaned_up whether the message set was partially garbage collected
843 * @return
844 * - NULL on error, and m is deallocated
845 * - m on success
846 */
848{
849 int i;
851 size_t alloc_size;
852
853 /*
854 * And... we go through a bunch of hoops, all over again.
855 */
856 m->rb = ms->rb_array[ms->rb_current];
857 fr_assert(m->rb != NULL);
859 if (m->data) return m;
860
861 /*
862 * When the simple allocation fails, ensure we don't do
863 * the cleanup twice in one allocation.
864 */
865 if (!cleaned_up) {
866 /*
867 * If we run out of room in the current ring
868 * buffer, AND it's our only one, then just
869 * double it in size.
870 */
871 if (ms->rb_max == 0) goto alloc_rb;
872
873 /*
874 * We're using multiple ring buffers, and we
875 * haven't already done a cleanup. Force a
876 * cleanup.
877 */
878 MPRINT("CLEANED UP BECAUSE OF RING BUFFER (%d - %d = %d)\n", ms->allocated, ms->freed,
879 ms->allocated - ms->freed);
880
881 /*
882 * The message slot is reserved but not finalised,
883 * so only collect: see message_gc().
884 */
885 message_gc(ms, 128, false);
886
887 /*
888 * Try to allocate the packet from the newly current ring buffer.
889 */
890 m->rb = ms->rb_array[ms->rb_current];
891 fr_assert(m->rb != NULL);
893 if (m->data) return m;
894
895 MPRINT("CLEANUP RING BUFFER FAILED\n");
896 }
897
898 /*
899 * We've tried two allocations, and both failed. Brute
900 * force over all arrays, trying to allocate one
901 * somewhere... anywhere. We start from the largest
902 * array, because that is the one we want to use the
903 * most.
904 *
905 * We want to avoid allocations in the smallest array,
906 * because that array will quickly wrap, and will cause
907 * us to do cleanups more often. That also lets old
908 * entries in the smallest array age out, so that we can
909 * free the smallest arrays.
910 */
911 for (i = ms->rb_max; i >= 0; i--) {
912 m->rb = ms->rb_array[i];
913 fr_assert(m->rb != NULL);
915 if (m->data) {
916 MPRINT("MOVED TO RING BUFFER %d\n", i);
917 ms->rb_current = i;
918 return m;
919 }
920 }
921
922 /*
923 * All of the arrays are full. If we don't have
924 * room to allocate another array, we're dead.
925 */
926 if ((ms->rb_max + 1) >= MSG_ARRAY_SIZE) {
927 fr_strerror_const("Message arrays are full");
928 goto cleanup;
929 }
930
931alloc_rb:
932 /*
933 * Allocate another message ring, double the size
934 * of the previous maximum, or large enough to hold
935 * twice the requested size if that is larger.
936 * fr_ring_buffer_create will round to the next power of 2.
937 */
938 alloc_size = fr_ring_buffer_size(ms->rb_array[ms->rb_max]) * 2;
939 if (alloc_size < m->rb_size) {
940 alloc_size = m->rb_size * 2;
941 }
942 rb = fr_ring_buffer_create(ms, alloc_size);
943 if (!rb) {
944 fr_strerror_const_push("Failed allocating ring buffer");
945 goto cleanup;
946 }
947
948 MPRINT("RING BUFFER DOUBLES\n");
949
950 /*
951 * Set the new one as current for all new
952 * allocations, allocate a message, and go try to
953 * reserve room for the raw packet data.
954 */
955 ms->rb_max++;
956 ms->rb_current = ms->rb_max;
957 ms->rb_array[ms->rb_current] = rb;
958
959 /*
960 * And we should now have an entirely empty message ring.
961 */
962 m->rb = rb;
964 if (m->data) return m;
965
966cleanup:
967 MPRINT("OUT OF MEMORY\n");
968
969 m->rb = NULL;
971 return NULL;
972}
973
974
975/** Reserve a message
976 *
977 * A later call to fr_message_and_data_commit() will commit the reservation.
978 * This call just reserves a message header and space for the packet data.
979 *
980 * If the caller later decides that the message is not needed, he
981 * should call fr_message_free() to free the message.
982 *
983 * We assume that the caller will call fr_message_and_data_reserve(), and then
984 * almost immediately fr_message_and_data_commit(). Multiple calls in series
985 * to fr_message_and_data_reserve() MUST NOT be done. The caller could also
986 * just call fr_ring_buffer_alloc(m->rb, size) if they wanted, and
987 * then update m->data_size by hand...
988 *
989 * The message is returned
990 *
991 * @param[in] ms the message set
992 * @param[in] reserve_size to reserve
993 * @return
994 * - NULL on error
995 * - fr_message_t* on success
996 */
998{
999 bool cleaned_up;
1000 fr_message_t *m;
1001
1002 (void) talloc_get_type_abort(ms, fr_message_set_t);
1003
1004 if (reserve_size > ms->max_allocation) {
1005 fr_strerror_printf("Cannot reserve %zu > max allocation %zu\n", reserve_size, ms->max_allocation);
1006 return NULL;
1007 }
1008
1009 /*
1010 * Reserve a bare message.
1011 */
1012 m = message_reserve(ms, &cleaned_up);
1013 if (!m) {
1014 MPRINT("Failed to reserve message\n");
1015 return NULL;
1016 }
1017
1018 /*
1019 * If the caller is not allocating any packet data, just
1020 * return the empty message.
1021 */
1022 if (!reserve_size) return m;
1023
1024 /*
1025 * We leave m->data_size as zero, and m->rb_size as the
1026 * reserved size. This indicates that the message has
1027 * reserved room for the packet data, but nothing has
1028 * been allocated.
1029 */
1031 m->rb_size = reserve_size;
1032
1033 return message_data_reserve(ms, m, cleaned_up);
1034}
1035
1036/** Cancel a reservation made by fr_message_and_data_reserve(), returning the slot to the set.
1037 *
1038 * Both rings are uncommitted at this point (write_offset was not advanced).
1039 * Clearing the message fields is sufficient: the next reserve overwrites the
1040 * slot, and the data ring's reserved field is replaced by the new reservation size.
1041 *
1042 * Callers MUST verify m->data_size == 0 before calling this. If a concurrent
1043 * fr_message_and_data_alloc() aliased this reservation (same ring slot, same
1044 * data address), m->data_size will be non-zero and the slot is already committed;
1045 * calling this function in that case corrupts the committed message.
1046 *
1047 * @param[in] ms the message set the reservation was made against.
1048 * @param[in] m the previously reserved message to cancel.
1049 */
1051{
1052 (void) talloc_get_type_abort(ms, fr_message_set_t);
1055 m->rb = NULL;
1056 m->data = NULL;
1057 m->data_size = 0;
1058 m->rb_size = 0;
1059}
1060
1061/** Commit a previously reserved message, allocating exactly total_size bytes of packet data.
1062 *
1063 * Commits both the message ring slot and the data ring buffer. total_size is the
1064 * final packet size; it may be less than the original reservation. For streaming
1065 * reads where m->data_size is already non-zero (leftover bytes from a prior read),
1066 * total_size must include those bytes.
1067 *
1068 * @param[in] ms the message set
1069 * @param[in] m the previously reserved message (m is NOT talloc'd)
1070 * @param[in] total_size final packet size in bytes
1071 * @return
1072 * - NULL on error, input message m is left alone
1073 * - m on success
1074 */
1076{
1077 uint8_t *p;
1078 size_t align_size;
1079
1080 (void) talloc_get_type_abort(ms, fr_message_set_t);
1081
1082 /* m is NOT talloc'd */
1083 if (!m) {
1084 m = fr_message_and_data_reserve(ms, total_size);
1085 if (!m) return NULL;
1086 }
1087
1089 fr_assert(m->rb_size >= total_size);
1090
1091 if (total_size == 0) {
1092 m->data = NULL;
1093 m->rb = NULL;
1094 m->data_size = m->rb_size = 0;
1095 message_finalise(ms, m);
1096 return m;
1097 }
1098
1099 fr_assert(m->rb != NULL);
1100 fr_assert(m->data != NULL);
1101
1102 align_size = total_size;
1103 CACHE_ALIGN(align_size);
1104
1105 p = fr_ring_buffer_alloc(m->rb, align_size);
1106 fr_assert(p != NULL);
1107 if (!p) {
1108 fr_strerror_const_push("Failed allocating from ring buffer");
1109 return NULL;
1110 }
1111
1112 fr_assert(p == m->data);
1113
1114 m->data_size = total_size;
1115 m->rb_size = align_size;
1116 message_finalise(ms, m);
1117
1118 return m;
1119}
1120
1121/** Reserve and commit a message atomically.
1122 *
1123 * Combines fr_message_and_data_reserve() and fr_message_and_data_commit() into a
1124 * single call for callers that know the exact packet size upfront.
1125 *
1126 * @param[in] ms the message set
1127 * @param[in] size packet size in bytes
1128 * @return
1129 * - NULL on error
1130 * - fr_message_t* on success
1131 */
1133{
1134 fr_message_t *m;
1135
1136 m = fr_message_and_data_reserve(ms, size);
1137 if (!m) return NULL;
1138
1139 return fr_message_and_data_commit(ms, m, size);
1140}
1141
1142/** Allocate packet data for a message, and reserve a new message
1143 *
1144 * This function allocates a previously reserved message, and then
1145 * reserves a new message.
1146 *
1147 * The application should call fr_message_and_data_reserve() with a large
1148 * buffer, and then read data into the buffer. If the buffer
1149 * contains multiple packets, the application should call
1150 * fr_message_and_data_commit_with_leftover() repeatedly to allocate the full
1151 * packets, while reserving room for the partial packet.
1152 *
1153 * When the application is determines that there is only one full
1154 * packet, and one partial packet in the buffer, it should call this
1155 * function with actual_packet_size, and a large reserve_size. The
1156 * partial packet will be reserved. If the ring buffer is full, the
1157 * partial packet will be copied to a new ring buffer.
1158 *
1159 * When the application determines that there are multiple full
1160 * packets in the buffer, it should call this function with
1161 * actual_packet_size for each buffer, and reserve_size which
1162 * reserves all of the data in the buffer. i.e. the full packets +
1163 * partial packets, which should start off as the original
1164 * reserve_size.
1165 *
1166 * The application should call this function to allocate each packet,
1167 * while decreasing reserve_size by each actual_packet_size that was
1168 * allocated. Once there is only one full and a partial packet in
1169 * the buffer, it should use a large reserve_size, as above.
1170 *
1171 * The application could just always ecall this function with a large
1172 * reserve_size, at the cost of substantially more memcpy()s.
1173 *
1174 * @param[in] ms the message set
1175 * @param[in] m the message message to allocate packet data for
1176 * @param[in] actual_packet_size to use
1177 * @param[in] leftover "dirty" bytes in the buffer
1178 * @param[in] reserve_size to reserve for new message
1179 * @return
1180 * - NULL on error, and input message m is left alone
1181 * - fr_message_t* on success. Will always be a new message.
1182 */
1184 size_t actual_packet_size,
1185 size_t leftover, size_t reserve_size)
1186{
1187 bool cleaned_up;
1188 uint8_t *p;
1189 fr_message_t *m2;
1190 size_t m_rb_size, align_size;
1191
1192 (void) talloc_get_type_abort(ms, fr_message_set_t);
1193
1194 align_size = actual_packet_size;
1195 CACHE_ALIGN(align_size);
1196
1197 /* m is NOT talloc'd */
1198
1200 fr_assert(m->rb != NULL);
1201 fr_assert(m->data != NULL);
1202 fr_assert(m->rb_size >= actual_packet_size);
1203
1204 p = fr_ring_buffer_alloc(m->rb, align_size);
1205 fr_assert(p != NULL);
1206 if (!p) {
1207 fr_strerror_const_push("Failed allocating from ring buffer");
1208 return NULL;
1209 }
1210
1211 fr_assert(p == m->data);
1212
1213 m_rb_size = m->rb_size; /* for ring buffer cleanups */
1214 m->data_size = actual_packet_size;
1215 m->rb_size = align_size;
1216 message_finalise(ms, m);
1217
1218 /*
1219 * If we've allocated all of the reserved ring buffer
1220 * data, then just reserve a brand new reservation.
1221 *
1222 * This will be automatically cache aligned.
1223 */
1224 if (!leftover) return fr_message_and_data_reserve(ms, reserve_size);
1225
1226 /*
1227 * Reserve a new message.
1228 */
1229 m2 = message_reserve(ms, &cleaned_up);
1230 if (!m2) return NULL;
1231
1232 /*
1233 * Ensure that there's enough room to shift the next
1234 * packet, so that it's cache aligned. Moving small
1235 * amounts of memory is likely faster than having two
1236 * CPUs fight over the same cache lines.
1237 */
1238 reserve_size += (align_size - actual_packet_size);
1240
1241 /*
1242 * Track how much data there is in the packet.
1243 */
1244 m2->rb = m->rb;
1245 m2->data_size = leftover;
1246 m2->rb_size = reserve_size;
1247
1248 /*
1249 * Try to extend the reservation. If we can do it,
1250 * return.
1251 */
1253 if (m2->data) {
1254 /*
1255 * The next packet pointer doesn't point to the
1256 * actual data after the current packet. Move
1257 * the next packet to match up with the ring
1258 * buffer allocation.
1259 */
1260 if (m2->data != (m->data + actual_packet_size)) {
1261 memmove(m2->data, m->data + actual_packet_size, leftover);
1262 }
1263 return m2;
1264 }
1265
1266 /*
1267 * We failed reserving more memory at the end of the
1268 * current ring buffer.
1269 *
1270 * Reserve data from a new ring buffer. If it doesn't
1271 * succeed, ensure that the old message will properly
1272 * clean up the old ring buffer.
1273 */
1274 if (!message_data_reserve(ms, m2, false)) {
1275 m->rb_size = m_rb_size;
1276 return NULL;
1277 }
1278
1279 /*
1280 * If necessary, copy the remaining data from the old
1281 * buffer to the new one.
1282 */
1283 if (m2->data != (m->data + actual_packet_size)) {
1284 memmove(m2->data, m->data + actual_packet_size, leftover);
1285 }
1286
1287 /*
1288 * The messages are in different ring buffers. We've
1289 * aligned m->rb_size above for the current packet, but
1290 * there's no subsequent message to clean up this
1291 * reservation. Re-extend the current message to it's
1292 * original size, so that cleaning it up will clean up the ring buffer.
1293 */
1294 if (m2->rb != m->rb) {
1295 m->rb_size = m_rb_size;
1296 return m2;
1297 }
1298
1299 /*
1300 * If we've managed to allocate the next message in the
1301 * current ring buffer, then it really should have
1302 * wrapped around. In which case, re-extend the current
1303 * message as above.
1304 */
1305 if (m2->data < m->data) {
1306 m->rb_size = m_rb_size;
1307 return m2;
1308 }
1309
1310 return m2;
1311}
1312
1313/** Count the number of used messages
1314 *
1315 * @param[in] ms the message set
1316 * @return
1317 * - number of used messages
1318 */
1320{
1321 int i, used;
1322
1323 (void) talloc_get_type_abort(ms, fr_message_set_t);
1324
1325 used = 0;
1326 for (i = 0; i <= ms->mr_max; i++) {
1327 fr_ring_buffer_t *mr;
1328
1329 mr = ms->mr_array[i];
1330
1332 }
1333
1334 return used;
1335}
1336
1337/** Garbage collect the message set.
1338 *
1339 * This function should ONLY be called just before freeing the
1340 * message set. It is intended only for debugging, and will cause
1341 * huge latency spikes if used at run time.
1342 *
1343 * @param[in] ms the message set
1344 */
1346{
1347 int i, cleaned;
1348
1349 (void) talloc_get_type_abort(ms, fr_message_set_t);
1350
1351 /*
1352 * Manually clean up each message ring. A ring can be
1353 * blocked by a done message whose data sits behind
1354 * another ring's, so keep going until a pass frees
1355 * nothing.
1356 */
1357 do {
1358 cleaned = 0;
1359 for (i = 0; i <= ms->mr_max; i++) {
1360 cleaned += message_ring_gc(ms, ms->mr_array[i], INT_MAX);
1361 }
1362 } while (cleaned > 0);
1363
1364 /*
1365 * And then do one last pass to clean up the arrays.
1366 */
1367 message_gc(ms, INT_MAX, true);
1368}
1369
1370/** Print debug information about the message set.
1371 *
1372 * @param[in] ms the message set
1373 * @param[in] fp the FILE where the messages are printed.
1374 */
1376{
1377 int i;
1378
1379 (void) talloc_get_type_abort(ms, fr_message_set_t);
1380
1381 fprintf(fp, "message arrays = %d\t(current %d)\n", ms->mr_max + 1, ms->mr_current);
1382 fprintf(fp, "ring buffers = %d\t(current %d)\n", ms->rb_max + 1, ms->rb_current);
1383
1384 for (i = 0; i <= ms->mr_max; i++) {
1385 fr_ring_buffer_t *mr = ms->mr_array[i];
1386
1387 fprintf(fp, "messages[%d] =\tsize %zu, used %zu\n",
1389 }
1390
1391 for (i = 0; i <= ms->rb_max; i++) {
1392 fprintf(fp, "ring buffer[%d] =\tsize %zu, used %zu\n",
1394 }
1395}
#define RCSID(id)
Definition build.h:603
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:177
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:194
talloc_free(hp)
unsigned char uint8_t
fr_ring_buffer_t * rb_array[MSG_ARRAY_SIZE]
array of ring buffers
Definition message.c:112
size_t message_size
size of the callers message, including fr_message_t
Definition message.c:98
fr_message_set_t * fr_message_set_create(TALLOC_CTX *ctx, int num_messages, size_t message_size, size_t ring_buffer_size, bool unlimited_size)
Create a message set.
Definition message.c:127
int mr_current
current used message ring entry
Definition message.c:95
#define MPRINT(...)
Definition message.c:37
fr_ring_buffer_t * mr_array[MSG_ARRAY_SIZE]
array of message arrays
Definition message.c:110
void fr_message_and_data_reset(fr_message_set_t *ms, fr_message_t *m)
Cancel a reservation made by fr_message_and_data_reserve(), returning the slot to the set.
Definition message.c:1050
int fr_message_done(fr_message_t *m)
Mark a message as done.
Definition message.c:195
static void message_gc(fr_message_set_t *ms, int max_to_clean, bool compact)
Garbage collect "done" messages.
Definition message.c:375
static fr_message_t * message_reserve(fr_message_set_t *ms, bool *p_cleaned)
Reserve a fr_message_t, WITHOUT a ring buffer.
Definition message.c:794
fr_message_t * fr_message_localize(TALLOC_CTX *ctx, fr_message_t *m, size_t message_size)
Localize a message by copying it to local storage.
Definition message.c:247
static int message_finalise(fr_message_set_t *ms, fr_message_t *m)
Finalise a reserved message allocation.
Definition message.c:818
static int message_ring_gc(fr_message_set_t *ms, fr_ring_buffer_t *mr, int max_to_clean)
Clean up messages in a message ring.
Definition message.c:311
int rb_max
max used ring buffer entry
Definition message.c:103
fr_message_t * fr_message_and_data_commit_with_leftover(fr_message_set_t *ms, fr_message_t *m, size_t actual_packet_size, size_t leftover, size_t reserve_size)
Allocate packet data for a message, and reserve a new message.
Definition message.c:1183
#define MSG_ARRAY_SIZE
Definition message.c:40
fr_message_t * fr_message_and_data_commit(fr_message_set_t *ms, fr_message_t *m, size_t total_size)
Commit a previously reserved message, allocating exactly total_size bytes of packet data.
Definition message.c:1075
int fr_message_set_messages_used(fr_message_set_t *ms)
Count the number of used messages.
Definition message.c:1319
#define CACHE_ALIGN(_x)
Definition message.c:42
static fr_message_t * message_alloc(fr_message_set_t *ms, bool *p_cleaned)
Allocate a fr_message_t, WITHOUT a ring buffer.
Definition message.c:767
void fr_message_set_gc(fr_message_set_t *ms)
Garbage collect the message set.
Definition message.c:1345
static uint8_t * _message_ring_find(bool *p_cleaned, fr_message_set_t *ms, fr_ring_buffer_op_t op)
Find a message ring with space, performing GC and expansion as needed.
Definition message.c:654
int mr_max
max used message ring entry
Definition message.c:96
uint8_t *(* fr_ring_buffer_op_t)(fr_ring_buffer_t *rb, size_t size)
Definition message.c:637
void fr_message_set_debug(FILE *fp, fr_message_set_t *ms)
Print debug information about the message set.
Definition message.c:1375
fr_message_t * fr_message_and_data_alloc(fr_message_set_t *ms, size_t size)
Reserve and commit a message atomically.
Definition message.c:1132
int mr_cleaned
where we last cleaned
Definition message.c:100
static fr_message_t * message_data_reserve(fr_message_set_t *ms, fr_message_t *m, bool cleaned_up)
Reserve data in a ring buffer for this message.
Definition message.c:847
size_t max_allocation
maximum allocation size
Definition message.c:105
fr_message_t * fr_message_and_data_reserve(fr_message_set_t *ms, size_t reserve_size)
Reserve a message.
Definition message.c:997
int rb_current
current used ring buffer entry
Definition message.c:102
A Message set, composed of message headers and ring buffer data.
Definition message.c:94
fr_ring_buffer_t * rb
pointer to the ring buffer
Definition message.h:48
size_t rb_size
cache-aligned size in the ring buffer
Definition message.h:51
uint8_t * data
pointer to the data in the ring buffer
Definition message.h:49
@ FR_MESSAGE_USED
Definition message.h:39
@ FR_MESSAGE_LOCALIZED
Definition message.h:40
@ FR_MESSAGE_DONE
Definition message.h:41
@ FR_MESSAGE_FREE
Definition message.h:38
size_t data_size
size of the data in the ring buffer
Definition message.h:50
fr_message_status_t status
free, used, done, etc.
Definition message.h:45
static size_t reserve_size
static size_t used
#define fr_assert(_expr)
Definition rad_assert.h:37
static bool cleanup
Definition radsniff.c:59
fr_ring_buffer_t * fr_ring_buffer_create(TALLOC_CTX *ctx, size_t size)
Create a ring buffer.
Definition ring_buffer.c:64
uint8_t * fr_ring_buffer_alloc(fr_ring_buffer_t *rb, size_t size)
Mark data as allocated.
uint8_t * fr_ring_buffer_reserve(fr_ring_buffer_t *rb, size_t size)
Reserve room in the ring buffer.
int fr_ring_buffer_free(fr_ring_buffer_t *rb, size_t size_to_free)
Mark data as free,.
size_t fr_ring_buffer_used(fr_ring_buffer_t *rb)
Get the amount of data used in a ring buffer.
size_t fr_ring_buffer_size(fr_ring_buffer_t *rb)
Get the size of the ring buffer.
int fr_ring_buffer_start(fr_ring_buffer_t *rb, uint8_t **p_start, size_t *p_size)
Get a pointer to the data at the start of the ring buffer.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const_push(_msg)
Definition strerror.h:227
#define fr_strerror_const(_msg)
Definition strerror.h:223