Allocation-free msg::init_data

With a msg_t size of 64 bytes, it becomes possible to embedd the content_t's members
struct for large messages directly in the msg_t. This saves the dynamic allocation
of content_t obejcts when using msg_t::init_data.

content_t contains a zmq::atomic_counter_t object which is not a POD in C++98
and thus it cannot be used as a member of the union u. To bypass this, C++11
is used which has relaxed rules for POD and atomic_counter is a C++11-POD. An
alternative would have been to make atomic_counter a classical POD by removing
constructors and all private member functions, i.e. have a struct and free functions
to manipulate it.

A new msg_t::init function is added which decides to either to copy the data for size<64 bytes
or use msg_t::init_data to do zero-copy initialization.
This commit is contained in:
Jens Auer
2015-05-29 23:47:03 +02:00
parent 03d6a7341b
commit 611e96c701
2 changed files with 91 additions and 58 deletions

View File

@@ -54,7 +54,6 @@ namespace zmq
class msg_t
{
public:
// Message flags.
enum
{
@@ -66,6 +65,8 @@ namespace zmq
};
bool check ();
int init (void *data_, size_t size_, msg_free_fn *ffn_,
void *hint_);
int init ();
int init_size (size_t size_);
int init_data (void *data_, size_t size_, msg_free_fn *ffn_,
@@ -88,6 +89,7 @@ namespace zmq
bool is_credential () const;
bool is_delimiter () const;
bool is_vsm ();
bool is_lmsg () const;
bool is_cmsg ();
uint32_t get_routing_id();
int set_routing_id(uint32_t routing_id_);
@@ -107,22 +109,6 @@ namespace zmq
enum { msg_t_size = 64 };
enum { max_vsm_size = msg_t_size - (8 + sizeof (metadata_t *) + 3 + sizeof(uint32_t)) };
// Shared message buffer. Message data are either allocated in one
// continuous block along with this structure - thus avoiding one
// malloc/free pair or they are stored in used-supplied memory.
// In the latter case, ffn member stores pointer to the function to be
// used to deallocate the data. If the buffer is actually shared (there
// are at least 2 references to it) refcount member contains number of
// references.
struct content_t
{
void *data;
size_t size;
msg_free_fn *ffn;
void *hint;
zmq::atomic_counter_t refcnt;
};
// Different message types.
enum type_t
{
@@ -138,6 +124,8 @@ namespace zmq
type_max = 104
};
atomic_counter_t& msg_counter();
// the file descriptor where this message originated, needs to be 64bit due to alignment
int64_t file_desc;
@@ -161,10 +149,32 @@ namespace zmq
unsigned char flags;
uint32_t routing_id;
} vsm;
struct {
struct lmsg_t {
metadata_t *metadata;
content_t *content;
unsigned char unused [msg_t_size - (8 + sizeof (metadata_t *) + sizeof (content_t*) + 2 + sizeof(uint32_t))];
// Shared message buffer. Message data are either allocated in one
// continuous block along with this structure - thus avoiding one
// malloc/free pair or they are stored in used-supplied memory.
// In the latter case, ffn member stores pointer to the function to be
// used to deallocate the data. If the buffer is actually shared (there
// are at least 2 references to it) refcount member contains number of
// references.
void *data;
size_t size;
msg_free_fn *ffn;
void *hint;
// create an aligned block for an atomic_counter_t object
union aligned_atomic_counter_storage {
zmq::atomic_counter_t::integer_t maxAlign;
unsigned char counter[ sizeof(zmq::atomic_counter_t) ];
} refcnt;
unsigned char unused [msg_t_size - (8 + sizeof (metadata_t *)
+ sizeof(void*)
+ sizeof(size_t)
+ sizeof(msg_free_fn*)
+ sizeof(void*)
+ sizeof(aligned_atomic_counter_storage)
+ 2
+ sizeof(uint32_t))];
unsigned char type;
unsigned char flags;
uint32_t routing_id;