// 获取数据的地址的函数,这样就能操作消息的数据内存了
void *zmq::msg_t::data ()
{
// Check the validity of the message.
zmq_assert (check ());
switch (u.base.type) {
case type_vsm: // 如果是小消息,就返回stack上的vsm_data的地址
return u.vsm.data;
case type_lmsg: // 如果是大消息,就返回heap上的content->data
return u.lmsg.content->data;
default: //如果是delimiter,返回是空指针
zmq_assert (false);
return NULL;
}
}
// 处理方式和data()类似,返回消息的大小
size_t zmq::msg_t::size ()
{
// Check the validity of the message.
zmq_assert (check ());
switch (u.base.type) {
case type_vsm:
return u.vsm.size;
case type_lmsg:
return u.lmsg.content->size;
default:
zmq_assert (false);
return 0;
}
// 销毁消息
int zmq::msg_t::close ()
{
// Check the validity of the message.
if (unlikely (!check ())) {
errno = EFAULT;
return -1;
}
if (u.base.type == type_lmsg) {
// 如果不是共享的,或是引用计数为0,销毁它,销毁过程如下:
// If the content is not shared, or if it is shared and the reference
// count has dropped to zero, deallocate it.
if (!(u.lmsg.flags & msg_t::shared) ||
!u.lmsg.content->refcnt.sub (1)) {
// 1、销毁引用计数,因为创建引用计数的时候,我们使用placement new,所以我们需要调用它的析构函数。
// We used "placement new" operator to initialize the reference
// counter so we call the destructor explicitly now.
u.lmsg.content->refcnt.~atomic_counter_t ();
// 2、如果有注册相应的自定义的销毁函数,就调用该函数。
// 这种情况主要用于使用init_data(),自己来管理data所指向空间。
if (u.lmsg.content->ffn)
u.lmsg.content->ffn (u.lmsg.content->data,
u.lmsg.content->hint);
// 3、调用free()释放heap的空间,注意,如果是使用init_size()来初始化消息,就会释放掉data的空间,
// 因为这块空间就是分配时多分配的size大小(在content下方)的那块
free (u.lmsg.content);
}
}
// Make the message invalid.
u.base.type = 0; // 设置为0,表明该消息已经被废除了
return 0;
}
// 对于小消息,消息数据是分配在stack上的,因此不需要手动销毁
// 对于大消息,消息数据是分配在heap上的,因此我们查看消息是不是shared模式,如果没有使用就直接销毁
假如使用了共享模式,那么我们递减消息的引用计数,一旦引用计数为0,我们就销毁消息内容。
int zmq::msg_t::copy (msg_t &src_)
{
// Check the validity of the source.
if (unlikely (!src_.check ())) {
errno = EFAULT;
return -1;
}
int rc = close ();
if (unlikely (rc < 0))
return rc;
if (src_.u.base.type == type_lmsg) {
// One reference is added to shared messages. Non-shared messages
// are turned into shared messages and reference count is set to 2.
if (src_.u.lmsg.flags & msg_t::shared) // 共享消息content引用,引用计数增加
src_.u.lmsg.content->refcnt.add (1);
else {
src_.u.lmsg.flags |= msg_t::shared;
src_.u.lmsg.content->refcnt.set (2);// 如果不是共享的,则设置成共享的,并将引用计数设置成2
}
}
*this = src_;
return 0;
}
int zmq::msg_t::move (msg_t &src_)
{
// Check the validity of the source.
if (unlikely (!src_.check ())) {
errno = EFAULT;
return -1;
}
int rc = close ();
if (unlikely (rc < 0))
return rc;
*this = src_;
rc = src_.init (); // 将source的消息充值成初始化的空消息
if (unlikely (rc < 0))
return rc;
return 0;
}