The FreeRADIUS server
$Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
|
Two-way thread-safe channels. More...
#include <freeradius-devel/io/channel.h>
#include <freeradius-devel/io/control.h>
#include <freeradius-devel/util/log.h>
#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/util/stdatomic.h>
Go to the source code of this file.
Data Structures | |
struct | fr_channel_control_t |
struct | fr_channel_end_t |
One end of a channel. More... | |
struct | fr_channel_s |
A full channel, which consists of two ends. More... | |
Macros | |
#define | ATOMIC_QUEUE_SIZE (1024) |
Size of the atomic queues. More... | |
#define | ENABLE_SKIPS (0) |
#define | IALPHA (8) |
#define | MPRINT(...) |
#define | RTT(_old, _new) fr_time_delta_wrap((fr_time_delta_unwrap(_new) + (fr_time_delta_unwrap(_old) * (IALPHA - 1))) / IALPHA) |
Typedefs | |
typedef enum fr_channel_signal_t | fr_channel_signal_t |
typedef struct fr_channel_s | fr_channel_t |
Enumerations | |
enum | fr_channel_direction_t { TO_RESPONDER = 0 , TO_REQUESTOR = 1 } |
enum | fr_channel_signal_t { FR_CHANNEL_SIGNAL_ERROR = FR_CHANNEL_ERROR , FR_CHANNEL_SIGNAL_DATA_TO_RESPONDER = FR_CHANNEL_DATA_READY_RESPONDER , FR_CHANNEL_SIGNAL_DATA_TO_REQUESTOR = FR_CHANNEL_DATA_READY_REQUESTOR , FR_CHANNEL_SIGNAL_OPEN = FR_CHANNEL_OPEN , FR_CHANNEL_SIGNAL_CLOSE = FR_CHANNEL_CLOSE , FR_CHANNEL_SIGNAL_DATA_DONE_RESPONDER , FR_CHANNEL_SIGNAL_RESPONDER_SLEEPING } |
Functions | |
bool | fr_channel_active (fr_channel_t *ch) |
Check if a channel is active. More... | |
fr_channel_t * | fr_channel_create (TALLOC_CTX *ctx, fr_control_t *requestor, fr_control_t *responder, bool same) |
Create a new channel. More... | |
static int | fr_channel_data_ready (fr_channel_t *ch, fr_time_t when, fr_channel_end_t *end, fr_channel_signal_t which) |
Send a message via a kq user signal. More... | |
int | fr_channel_null_reply (fr_channel_t *ch) |
Don't send a reply message into the channel. More... | |
bool | fr_channel_recv_reply (fr_channel_t *ch) |
Receive a reply message from the channel. More... | |
bool | fr_channel_recv_request (fr_channel_t *ch) |
Receive a request message from the channel. More... | |
void | fr_channel_requestor_uctx_add (fr_channel_t *ch, void *uctx) |
Add network-specific data to a channel. More... | |
void * | fr_channel_requestor_uctx_get (fr_channel_t *ch) |
Get network-specific data from a channel. More... | |
int | fr_channel_responder_ack_close (fr_channel_t *ch) |
Acknowledge that the channel is closing. More... | |
int | fr_channel_responder_sleeping (fr_channel_t *ch) |
Signal a channel that the responder is sleeping. More... | |
void | fr_channel_responder_uctx_add (fr_channel_t *ch, void *uctx) |
Add responder-specific data to a channel. More... | |
void * | fr_channel_responder_uctx_get (fr_channel_t *ch) |
Get responder-specific data from a channel. More... | |
int | fr_channel_send_reply (fr_channel_t *ch, fr_channel_data_t *cd) |
Send a reply message into the channel. More... | |
int | fr_channel_send_request (fr_channel_t *ch, fr_channel_data_t *cd) |
Send a request message into the channel. More... | |
int | fr_channel_service_kevent (fr_channel_t *ch, fr_control_t *c, UNUSED struct kevent const *kev) |
Service a control-plane event. More... | |
fr_channel_event_t | fr_channel_service_message (fr_time_t when, fr_channel_t **p_channel, void const *data, size_t data_size) |
Service a control-plane message. More... | |
int | fr_channel_set_recv_reply (fr_channel_t *ch, void *uctx, fr_channel_recv_callback_t recv_reply) |
int | fr_channel_set_recv_request (fr_channel_t *ch, void *uctx, fr_channel_recv_callback_t recv_request) |
int | fr_channel_signal_open (fr_channel_t *ch) |
Send a channel to a responder. More... | |
int | fr_channel_signal_responder_close (fr_channel_t *ch) |
Signal a responder that the channel is closing. More... | |
void | fr_channel_stats_log (fr_channel_t const *ch, fr_log_t const *log, char const *file, int line) |
Two-way thread-safe channels.
Definition in file channel.c.
struct fr_channel_control_t |
Data Fields | ||
---|---|---|
uint64_t | ack | or the endpoint.. |
fr_channel_t * | ch | the channel |
fr_channel_signal_t | signal | the signal to send |
struct fr_channel_end_t |
One end of a channel.
Consists of a kqueue descriptor, and an atomic queue. The atomic queue is there to get bulk data through, because it's more efficient than pushing 1M+ events per second through a kqueue.
Data Fields | ||
---|---|---|
uint64_t | ack | Sequence number of the other end. |
atomic_bool | active | Whether the channel is active. |
fr_atomic_queue_t * | aq | The queue of messages - visible only to this channel. |
fr_control_t * | control | The control plane, consisting of an atomic queue and kqueue. |
fr_channel_direction_t | direction | Use for debug messages. |
bool | must_signal | we need to signal the other end |
fr_ring_buffer_t * | rb | Ring buffer for control-plane messages. |
fr_channel_recv_callback_t | recv | callback for receiving messages |
void * | recv_uctx | context for receiving messages |
uint64_t | sequence | Sequence number for this channel. |
uint64_t | sequence_at_last_signal | When we last signaled. |
fr_channel_stats_t | stats | channel statistics |
uint64_t | their_view_of_my_sequence | Should be clear. |
void * | uctx | Worker context. |
struct fr_channel_s |
A full channel, which consists of two ends.
A channel consists of an I/O identifier that can be placed in kequeue and an atomic queue in each direction to allow for bidirectional communication.
Data Fields | ||
---|---|---|
fr_time_delta_t | cpu_time | Total time used by the responder for this channel. |
fr_channel_end_t | end[2] | Two ends of the channel. |
fr_time_delta_t | processing_time | Time spent by the responder processing requests. |
bool | same_thread | are both ends in the same thread? |
#define ATOMIC_QUEUE_SIZE (1024) |
Size of the atomic queues.
The queue reader MUST service the queue occasionally, otherwise the writer will not be able to write. If it's too low, the writer will fail. If it's too high, it will unnecessarily use memory. So we're better off putting it on the high side.
The reader SHOULD service the queues at inter-packet latency. i.e. at 1M pps, the queue will get serviced every microsecond.
#define RTT | ( | _old, | |
_new | |||
) | fr_time_delta_wrap((fr_time_delta_unwrap(_new) + (fr_time_delta_unwrap(_old) * (IALPHA - 1))) / IALPHA) |
typedef enum fr_channel_signal_t fr_channel_signal_t |
typedef struct fr_channel_s fr_channel_t |
enum fr_channel_signal_t |
bool fr_channel_active | ( | fr_channel_t * | ch | ) |
Check if a channel is active.
A channel may be closed by either end. If so, it stays alive (but inactive) until both ends acknowledge the close.
[in] | ch | the channel |
Definition at line 812 of file channel.c.
fr_channel_t* fr_channel_create | ( | TALLOC_CTX * | ctx, |
fr_control_t * | requestor, | ||
fr_control_t * | responder, | ||
bool | same | ||
) |
Create a new channel.
[in] | ctx | The talloc_ctx to allocate channel data in. |
[in] | requestor | control plane. |
[in] | responder | control plane. |
[in] | same | whether or not the channel is for the same thread |
Definition at line 183 of file channel.c.
|
static |
Send a message via a kq user signal.
Note that the caller doesn't care about data in the event, that is sent via the atomic queue. The kevent code takes care of delivering the signal once, even if it's sent by multiple requestor threads.
The thread watching the KQ knows which end it is. So when it gets the signal (and the channel pointer) it knows to look at end[0] or end[1]. We also send which end in 'which' (0, 1) to further help the recipient.
[in] | ch | the channel. |
[in] | when | the data was ready. Typically taken from the message. |
[in] | end | of the channel that the message was written to. |
[in] | which | end of the channel (0/1). |
Definition at line 272 of file channel.c.
int fr_channel_null_reply | ( | fr_channel_t * | ch | ) |
bool fr_channel_recv_reply | ( | fr_channel_t * | ch | ) |
bool fr_channel_recv_request | ( | fr_channel_t * | ch | ) |
void fr_channel_requestor_uctx_add | ( | fr_channel_t * | ch, |
void * | uctx | ||
) |
void* fr_channel_requestor_uctx_get | ( | fr_channel_t * | ch | ) |
int fr_channel_responder_ack_close | ( | fr_channel_t * | ch | ) |
int fr_channel_responder_sleeping | ( | fr_channel_t * | ch | ) |
Signal a channel that the responder is sleeping.
This function should be called from the responders idle loop. i.e. only when it has nothing else to do.
[in] | ch | the channel to signal we're no longer listening on. |
Definition at line 646 of file channel.c.
void fr_channel_responder_uctx_add | ( | fr_channel_t * | ch, |
void * | uctx | ||
) |
void* fr_channel_responder_uctx_get | ( | fr_channel_t * | ch | ) |
int fr_channel_send_reply | ( | fr_channel_t * | ch, |
fr_channel_data_t * | cd | ||
) |
Send a reply message into the channel.
The message should be initialized, other than "sequence" and "ack".
[in] | ch | the channel to send the reply on. |
[in] | cd | the message to send |
Definition at line 511 of file channel.c.
int fr_channel_send_request | ( | fr_channel_t * | ch, |
fr_channel_data_t * | cd | ||
) |
Send a request message into the channel.
The message should be initialized, other than "sequence" and "ack".
This function automatically calls the recv_reply callback if there is a reply.
[in] | ch | the channel to send the request on. |
[in] | cd | the message to send. |
Definition at line 306 of file channel.c.
int fr_channel_service_kevent | ( | fr_channel_t * | ch, |
fr_control_t * | c, | ||
UNUSED struct kevent const * | kev | ||
) |
Service a control-plane event.
The channels use control planes for internal signaling. Note that the caller does NOT pass the channel into this function. Instead, the channel is taken from the kevent.
[in] | ch | The channel to service. |
[in] | c | The control plane on which we received the kev. |
[in] | kev | The kevent data, should get passed to the control plane. |
Definition at line 788 of file channel.c.
fr_channel_event_t fr_channel_service_message | ( | fr_time_t | when, |
fr_channel_t ** | p_channel, | ||
void const * | data, | ||
size_t | data_size | ||
) |
Service a control-plane message.
[in] | when | The current time. |
[out] | p_channel | The channel which should be serviced. |
[in] | data | The control message. |
[in] | data_size | The size of the control message. |
Definition at line 685 of file channel.c.
int fr_channel_set_recv_reply | ( | fr_channel_t * | ch, |
void * | uctx, | ||
fr_channel_recv_callback_t | recv_reply | ||
) |
int fr_channel_set_recv_request | ( | fr_channel_t * | ch, |
void * | uctx, | ||
fr_channel_recv_callback_t | recv_request | ||
) |
int fr_channel_signal_open | ( | fr_channel_t * | ch | ) |
int fr_channel_signal_responder_close | ( | fr_channel_t * | ch | ) |
void fr_channel_stats_log | ( | fr_channel_t const * | ch, |
fr_log_t const * | log, | ||
char const * | file, | ||
int | line | ||
) |
fr_table_num_sorted_t const channel_packet_priority[] |
size_t channel_packet_priority_len = NUM_ELEMENTS(channel_packet_priority) |
fr_table_num_sorted_t const channel_signals[] |
size_t channel_signals_len = NUM_ELEMENTS(channel_signals) |