25RCSID(
"$Id: bdb8eae283d2d7e88bd6fc25fd04034fc0946734 $")
27#include <freeradius-devel/io/message.h>
28#include <freeradius-devel/util/strerror.h>
35#define MPRINT(...) fprintf(stderr, __VA_ARGS__)
40#define MSG_ARRAY_SIZE (16)
42#define CACHE_ALIGN(_x) do { _x += 63; _x &= ~(size_t) 63; } while (0)
135 if (num_messages < 8) num_messages = 8;
137 if ((num_messages & (num_messages - 1)) != 0) {
147 if (message_size > 1024) {
178 ms->
max_allocation = unlimited_size ? 1 << 29 : ring_buffer_size / 2;
261 l = talloc_memdup(ctx, m, message_size);
313 int messages_cleaned = 0;
319 if (size == 0)
break;
340 if (start != m->
data)
break;
356 if (messages_cleaned >= max_to_clean)
break;
359 MPRINT(
"CLEANED %d (%p) left\n", messages_cleaned, mr);
360 return messages_cleaned;
378 int arrays_freed, arrays_used, empty_slot;
379 int largest_free_slot;
381 size_t largest_free_size;
391 for (i = 0; i <= ms->
mr_max; i++) {
395 total_cleaned += cleaned;
396 fr_assert(total_cleaned <= max_to_clean);
401 if (total_cleaned == max_to_clean)
break;
407 if (total_cleaned == 0)
return;
409 if (!compact)
return;
418 for (i = ms->
mr_max; i >= 0; i--) {
421 if (arrays_used < 2) {
422 MPRINT(
"\tleaving entry %d alone\n", i);
432 MPRINT(
"\tfreeing entry %d\n", i);
438 MPRINT(
"\tstill in use entry %d\n", i);
446 MPRINT(
"TRYING TO PACK from %d free arrays out of %d\n", arrays_freed, ms->
rb_max + 1);
454 for (i = 0; i <= ms->
mr_max; i++) {
463 if (empty_slot < 0) empty_slot = i;
473 if (empty_slot < 0)
continue;
484 for (j = empty_slot + 1; j <= i; j++) {
496 ms->
mr_max -= arrays_freed;
501 for (i = 0; i <= ms->
mr_max; i++) {
521 for (i = ms->
rb_max; i >= 0; i--) {
524 if (arrays_used < 2) {
525 MPRINT(
"\tleaving entry %d alone\n", i);
531 MPRINT(
"\tfreeing entry %d\n", i);
537 MPRINT(
"\tstill in use entry %d\n", i);
543 if (arrays_freed > 0) {
544 MPRINT(
"TRYING TO PACK from %d free arrays out of %d\n", arrays_freed, ms->
rb_max + 1);
552 for (i = 0; i <= ms->
rb_max; i++) {
561 if (empty_slot < 0) empty_slot = i;
571 if (empty_slot < 0)
continue;
582 for (j = empty_slot + 1; j <= i; j++) {
594 ms->
rb_max -= arrays_freed;
599 for (i = 0; i <= ms->
rb_max; i++) {
615 largest_free_slot = ms->
rb_max;
619 for (i = 0; i < ms->
rb_max; i++) {
626 if (largest_free_size < free_size) {
627 largest_free_slot = i;
628 largest_free_size = free_size;
653static inline CC_HINT(always_inline)
667 mr = ms->mr_array[ms->mr_current];
668 p = op(mr, ms->message_size);
670 MPRINT(
"RING FIND normal\n");
674 MPRINT(
"CLEANING UP (%d - %d = %d)\n", ms->allocated, ms->freed,
675 ms->allocated - ms->freed);
692 mr = ms->mr_array[ms->mr_current];
694 p = op(mr, ms->message_size);
696 MPRINT(
"RING FIND after cleanup\n");
713 for (i = ms->mr_max; i >= 0; i--) {
714 mr = ms->mr_array[i];
717 p = op(mr, ms->message_size);
720 MPRINT(
"RING FIND from changed ring buffer\n");
721 MPRINT(
"SET MR to changed %d\n", ms->mr_current);
751 ms->mr_current = ms->mr_max;
752 ms->mr_array[ms->mr_max] = mr;
754 MPRINT(
"SET MR to doubled %d\n", ms->mr_current);
756 return op(mr, ms->message_size);
820 bool cleaned =
false;
829 if (!
fr_cond_assert_msg(nm == m,
"Alloc interleaved between reserving and finalising message allocation %p", m)) {
859 if (m->
data)
return m;
871 if (ms->
rb_max == 0)
goto alloc_rb;
893 if (m->
data)
return m;
895 MPRINT(
"CLEANUP RING BUFFER FAILED\n");
911 for (i = ms->
rb_max; i >= 0; i--) {
916 MPRINT(
"MOVED TO RING BUFFER %d\n", i);
939 if (alloc_size < m->rb_size) {
948 MPRINT(
"RING BUFFER DOUBLES\n");
964 if (m->
data)
return m;
967 MPRINT(
"OUT OF MEMORY\n");
1014 MPRINT(
"Failed to reserve message\n");
1085 if (!m)
return NULL;
1091 if (total_size == 0) {
1102 align_size = total_size;
1137 if (!m)
return NULL;
1184 size_t actual_packet_size,
1190 size_t m_rb_size, align_size;
1194 align_size = actual_packet_size;
1230 if (!m2)
return NULL;
1260 if (m2->
data != (m->
data + actual_packet_size)) {
1261 memmove(m2->
data, m->
data + actual_packet_size, leftover);
1283 if (m2->
data != (m->
data + actual_packet_size)) {
1284 memmove(m2->
data, m->
data + actual_packet_size, leftover);
1294 if (m2->
rb != m->
rb) {
1326 for (i = 0; i <= ms->
mr_max; i++) {
1359 for (i = 0; i <= ms->
mr_max; i++) {
1362 }
while (cleaned > 0);
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);
1384 for (i = 0; i <= ms->
mr_max; i++) {
1387 fprintf(fp,
"messages[%d] =\tsize %zu, used %zu\n",
1391 for (i = 0; i <= ms->
rb_max; i++) {
1392 fprintf(fp,
"ring buffer[%d] =\tsize %zu, used %zu\n",
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
fr_ring_buffer_t * rb_array[MSG_ARRAY_SIZE]
array of ring buffers
size_t message_size
size of the callers message, including fr_message_t
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.
int mr_current
current used message ring entry
fr_ring_buffer_t * mr_array[MSG_ARRAY_SIZE]
array of message arrays
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.
int fr_message_done(fr_message_t *m)
Mark a message as done.
static void message_gc(fr_message_set_t *ms, int max_to_clean, bool compact)
Garbage collect "done" messages.
static fr_message_t * message_reserve(fr_message_set_t *ms, bool *p_cleaned)
Reserve a fr_message_t, WITHOUT a ring buffer.
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.
static int message_finalise(fr_message_set_t *ms, fr_message_t *m)
Finalise a reserved message allocation.
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.
int rb_max
max used ring buffer entry
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.
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.
int fr_message_set_messages_used(fr_message_set_t *ms)
Count the number of used messages.
static fr_message_t * message_alloc(fr_message_set_t *ms, bool *p_cleaned)
Allocate a fr_message_t, WITHOUT a ring buffer.
void fr_message_set_gc(fr_message_set_t *ms)
Garbage collect the message set.
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.
int mr_max
max used message ring entry
uint8_t *(* fr_ring_buffer_op_t)(fr_ring_buffer_t *rb, size_t size)
void fr_message_set_debug(FILE *fp, fr_message_set_t *ms)
Print debug information about the message set.
fr_message_t * fr_message_and_data_alloc(fr_message_set_t *ms, size_t size)
Reserve and commit a message atomically.
int mr_cleaned
where we last cleaned
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.
size_t max_allocation
maximum allocation size
fr_message_t * fr_message_and_data_reserve(fr_message_set_t *ms, size_t reserve_size)
Reserve a message.
int rb_current
current used ring buffer entry
A Message set, composed of message headers and ring buffer data.
fr_ring_buffer_t * rb
pointer to the ring buffer
size_t rb_size
cache-aligned size in the ring buffer
uint8_t * data
pointer to the data in the ring buffer
size_t data_size
size of the data in the ring buffer
fr_message_status_t status
free, used, done, etc.
static size_t reserve_size
fr_ring_buffer_t * fr_ring_buffer_create(TALLOC_CTX *ctx, size_t size)
Create a ring buffer.
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.
#define fr_strerror_const_push(_msg)
#define fr_strerror_const(_msg)