ACE_Message_Block* CMessageBlockManager::Create(uint32 u4Size)
{
	ACE_Guard<ACE_Recursive_Thread_Mutex> WGuard(m_ThreadWriteLock);
	ACE_Message_Block* pmb = NULL;

	if(u4Size <= 0)
	{
		//如果申请的空间为0,则直接返回空。
		return NULL;
	}

	ACE_NEW_MALLOC_NORETURN(pmb, 
		                    static_cast<ACE_Message_Block*>(m_pmsgallocator->malloc(sizeof(ACE_Message_Block))),
	 	                    ACE_Message_Block(u4Size, // size
							ACE_Message_Block::MB_DATA, // type
							0,
							0,
							m_pbuff_allocator, // allocator_strategy
							0, // locking strategy
							ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY, // priority
							ACE_Time_Value::zero,
							ACE_Time_Value::max_time,
							m_pdata_allocator,
							m_pmsgallocator
							));

	return pmb;
}
Ejemplo n.º 2
0
ACE_Message_Block *
ACE_Message_Block::duplicate (void) const
{
  ACE_TRACE ("ACE_Message_Block::duplicate");

  ACE_Message_Block *nb_top = 0;
  ACE_Message_Block *nb = 0;

  const ACE_Message_Block *current = this;

  // Increment the reference counts of all the continuation messages.
  while (current)
    {
      ACE_Message_Block* cur_dup = 0;

      // Create a new <ACE_Message_Block> that contains unique copies of
      // the message block fields, but a reference counted duplicate of
      // the <ACE_Data_Block>.

      // If there is no allocator, use the standard new and delete calls.
      if (current->message_block_allocator_ == 0)
        ACE_NEW_NORETURN (cur_dup,
                          ACE_Message_Block (0, // size
                                             ACE_Message_Type (0), // type
                                             0, // cont
                                             0, // data
                                             0, // allocator
                                             0, // locking strategy
                                             0, // flags
                                             current->priority_, // priority
                                             ACE_EXECUTION_TIME,
                                             ACE_DEADLINE_TIME,
                                             // Get a pointer to a
                                             // "duplicated" <ACE_Data_Block>
                                             // (will simply increment the
                                             // reference count).
                                             current->data_block ()->duplicate  (),
                                             current->data_block ()->data_block_allocator (),
                                             current->message_block_allocator_));
      else // Otherwise, use the message_block_allocator passed in.
        ACE_NEW_MALLOC_NORETURN (cur_dup,
                                 static_cast<ACE_Message_Block*> (
                                      current->message_block_allocator_->malloc (sizeof (ACE_Message_Block))),
                                 ACE_Message_Block (0, // size
                                                    ACE_Message_Type (0), // type
                                                    0, // cont
                                                    0, // data
                                                    0, // allocator
                                                    0, // locking strategy
                                                    0, // flags
                                                    current->priority_, // priority
                                                    ACE_EXECUTION_TIME,
                                                    ACE_DEADLINE_TIME,
                                                    // Get a pointer to a
                                                    // "duplicated" <ACE_Data_Block>
                                                    // (will simply increment the
                                                    // reference count).
                                                    current->data_block ()->duplicate  (),
                                                    current->data_block ()->data_block_allocator (),
                                                    current->message_block_allocator_));


      // If allocation failed above, release everything done so far and return NULL
      if (cur_dup == 0)
        {
          if (nb_top != 0)
            {
              nb_top->release ();
            }
          return 0;
        }

      // Set the read and write pointers in the new <Message_Block> to the
      // same relative offset as in the existing <Message_Block>.  Note
      // that we are assuming that the data_block()->base() pointer
      // doesn't change when it's duplicated.
      cur_dup->rd_ptr (current->rd_ptr_);
      cur_dup->wr_ptr (current->wr_ptr_);

      if (!nb)
        {
          /* First in the list: set leading pointers */
          nb_top = nb = cur_dup;
        }
      else
        {
          /* Continuing on: append to nb and walk down the list */
          nb->cont_ = cur_dup;
          nb = nb->cont_;
        }

      current = current->cont_;
    }

  return nb_top;
}
Ejemplo n.º 3
0
int
OpenDDS::DCPS::PacketRemoveVisitor::visit_element_ref
(TransportQueueElement*& element)
{
  DBG_ENTRY_LVL("PacketRemoveVisitor","visit_element_ref",6);

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
        "Obtain the element_blocks using element->msg()\n"));

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
        "The element is [%0x]\n",
        element));

  // These is the head of the chain of "source" blocks from the element
  // currently being visited.
  ACE_Message_Block* element_blocks =
    const_cast<ACE_Message_Block*>(element->msg());

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
        "element_blocks == [%0x]\n", element_blocks));

  // As we visit an element, we also adjust our current_block_ and
  // previous_block_ data members such that we can correlate the current
  // element (being visited) with the message blocks that it contributed
  // to the unsent packet blocks.  Our head_ data member was set to the
  // first unsent block in the chain of blocks that make up the remaining
  // portions of the "packet".

  if (this->current_block_ == 0) {
    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "this->current_block_ == 0.  Visiting first element.\n"));

    // This must be our first visit_element() call.  Set up the
    // current_block_ and previous_block_ data members appropriately.
    this->current_block_  = this->head_;
    this->previous_block_ = 0;

    // There is a chance that the head_ block (and thus the current_block_)
    // is actually a duplicate of the packet header_block_.  If so, we
    // need to adust the current_block_ and previous_block_ appropriately.
    if (this->header_block_->base() == this->current_block_->base()) {
      // Yup.  Just what we thought may be the case.
      this->previous_block_ = this->current_block_;
      this->current_block_ = this->previous_block_->cont();
    }

  } else {
    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "this->current_block_ != 0.  Visiting element other than "
          "the first element.\n"));

    // We are visiting an element that is not the very first element in
    // the packet.

    // Let's get the previous_block_ data member set to point to the
    // block in the packet chain that is the predecessor to the first
    // block in the packet chain that was contributed from the current
    // element.
    this->previous_block_ = this->current_block_;

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set previous_block_ to the current_block_ [%0x]\n",
          this->previous_block_));

    // Keep changing the previous_block_ to the next block in the chain
    // until we know that the next block in the chain is a duplicate of
    // the block at the front of the element_blocks chain.
    while (this->previous_block_->cont()->base() != element_blocks->base()) {
      this->previous_block_ = this->previous_block_->cont();

      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Moved previous_block_ to its cont() block [%0x]\n",
            this->previous_block_));
    }

    // At this point, we know that the previous_block_ is the block
    // that immediately precedes the first block contributed by the
    // element that we are currently visiting.  Set the current_block_
    // to point to the first block contributed by the element.
    this->current_block_ = this->previous_block_->cont();

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set current_block_ to the previous_block_->cont() [%0x]\n",
          this->current_block_));
  }

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
        "Does the current element match the sample to be replaced?\n"));

  // Does the current element (being visited) match the sample that we
  // need to remove?
  if( this->sample_ == *element) {
    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "YES - The element matches the sample\n"));

    // We get inside here if the element we are currently visiting is
    // the element that "matches" the sample that needs to be removed.

    // At this point, the current_block_ points to the first block in
    // the packet that is known to have been contributed by the
    // element that we are currently visiting.

    // The previous_block_ is either pointing to the block in the packet
    // that immediately precedes the current_block_, or the previous_block_
    // is set to 0 indicating that the current_block_ also happens to
    // be the head_ block in the packet (and the element we are visiting
    // is the first element (remaining) in the packet).

    // Our goal now is to extract the blocks from the packet that have
    // been contributed by the element that we are currently visiting.
    // Then, we will need to replace those blocks in the packet with
    // our own blocks.  How the replacement blocks are created depends
    // upon whether or not we are visiting the first element in the packet.

    // The original_blocks will end up being a chain of blocks
    // extracted from the packet, all of which were contributed by
    // the current element being visited.
    ACE_Message_Block* original_blocks = this->current_block_;

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set original_blocks to this->current_block_ [%0x]\n",
          original_blocks));

    // The remaining_chain will end up being the chain of blocks that
    // followed the original blocks in the packet.  There is always
    // the possibility that the remaining chain will be 0, meaning that
    // we are currently visiting (and removing) the last element in the
    // packet.
    ACE_Message_Block* remaining_chain = this->current_block_->cont();

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set remaining_chain to this->current_block_->cont() [%0x]\n",
          remaining_chain));

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set original_blocks->cont(0)\n"));

    // At this point, we only know for sure that one block was
    // contributed by the element currently being visited.
    original_blocks->cont(0);

    unsigned num_elem_blocks_sent = 0;

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set num_elem_blocks_sent to 0\n"));

    // The original_blocks_tail is a pointer to the last block in the
    // chain of blocks contributed by the element currently being visited.
    ACE_Message_Block* original_blocks_tail = original_blocks;

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set original_blocks_tail to original_blocks [%0x]\n",
          original_blocks_tail));

    // Find the block in the element_blocks that contributed the
    // block pointed to by the original_blocks_tail.
    ACE_Message_Block* contrib_block = element_blocks;

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set contrib_block to element_blocks [%0x]\n",
          contrib_block));

    // Loop through each block in the element_blocks until we either
    // find the contributing element block, or we have checked all of the
    // element_blocks, and never found the contributing element block.
    while (contrib_block != 0) {
      if (contrib_block->base() == original_blocks->base()) {
        VDBG((LM_DEBUG, "(%P|%t) DBG:   "
              "contrib_block->base() == original_blocks->base()\n"));
        // Ok.  We have found the source block.
        break;
      }

      // That wasn't a match.  Try the next contrib_block to see
      // if it is the contributing block for the block at the top of
      // the original_blocks chain (which is a chain of 1 at this point).
      contrib_block = contrib_block->cont();
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Move contrib_block to contrib_block->cont() [%0x]\n",
            contrib_block));
      ++num_elem_blocks_sent;
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "num_elem_blocks_sent incremented to %d\n",
            num_elem_blocks_sent));
    }

    // Sanity check - make sure that we found the contributing block
    // in the current element (being visited) for the contributed block
    // that is the lone block in the original_blocks chain.
    if (contrib_block == 0) {
      ACE_ERROR((LM_ERROR,
                 "(%P|%t) ERROR: Element queue and unsent message block "
                 "chain is out-of-synch. source_block == 0.\n"));

      // Set the status to indicate a fatal error occurred.
      this->status_ = -1;

      // Stop vistation now.
      return 0;
    }

    // Now that we have identified the contributing block for the
    // single block in the original_blocks chain, we may need to add
    // more blocks to the original_blocks chain - one more block for
    // each additional block chained to the element's contributing block.
    // Note that this while loop doesn't do anything if the contrib_block
    // is the last contributing block in the element.  In this case, the
    // original_blocks contains the lone block that was contributed by
    // the lone (last) contributing block in the element - and the
    // remaining_chain properly points to the remaining blocks in the
    // packet.
    while (contrib_block->cont() != 0) {
      // The source element block indicates that it has a "next"
      // block that would have also contributed a block to the packet.

      // This means that there is a block at the front of the
      // remaining_chain of blocks that really should be part of the
      // original_blocks.

      // Sanity check - the remaining_chain better not be NULL (0).
      if (remaining_chain == 0) {
        ACE_ERROR((LM_ERROR,
                   "(%P|%t) ERROR: Element queue and unsent message block "
                   "chain is out-of-synch. remaining_chain == 0.\n"));
      }

      // Extract/unchain the first block from the remaining_chain.
      ACE_Message_Block* additional_block = remaining_chain;
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Extracted additional_block from remaining_chain [%0x]\n",
            additional_block));

      remaining_chain = remaining_chain->cont();
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Move remaining_chain to remaining_chain->cont() [%0x]\n",
            remaining_chain));

      additional_block->cont(0);
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Set additional_block->cont(0)\n"));

      // Attach the block to the end of the original_blocks chain.
      original_blocks_tail->cont(additional_block);
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "original_blocks_tail->cont(additional_block)\n"));

      original_blocks_tail = additional_block;
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Set original_blocks_tail to additional_block [%0x]\n",
            original_blocks_tail));

      // Advance to the next contributing block.
      contrib_block = contrib_block->cont();
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Move contrib_block to contrib_block->cont() [%0x]\n",
            contrib_block));
    }

    // Finally!At this point we have broken the unsent packet chain of
    // blocks into three seperate chains:
    //
    //   (1) this->previous_block_ is either 0, or it points to the block
    //       (from the unsent packet chain) that immediately preceded the
    //       first block (from the unsent packet chain) that was contributed
    //       by the sample (that we need to replace).
    //       this->previous_block_ is 0 when the contributed blocks from
    //       the sample (that we are replacing) are the first blocks from
    //       the unsent packet chain.
    //
    //       Thus, sub-chain (1) is either an empty chain (when
    //       this->previous_block_ is 0), or it is a chain that starts
    //       with the head_ block (the first block from the unsent packet
    //       chain), and ends with the this->previous_block_.
    //
    //   (2) original_blocks points to the first block (from the unsent
    //       packet chain) that was contributed by the sample (that we
    //       need to replace).
    //
    //       Thus, sub-chain (2) is a chain that starts with the block
    //       pointed to by original_blocks.
    //
    //   (3) remaining_chain points to the first block (from the unsent
    //       packet chain) that followed the last block that was
    //       contributed by the sample (that we need to replace).
    //
    //       Thus, sub-chain (3) is a chain that starts with the block
    //       pointed to by remaining_chain.  Note that this may be 0 if
    //       the sample being replaced is the last sample in the packet.
    //
    // If sub-chains (1), (2), and (3) were chained together (in that
    // order), we would end up with the original unsent packet chain.
    // Whew.

    // Now we can perform our replacement duties.

    // Save off the pointer to the original element
    TransportQueueElement* orig_elem = element;

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Create the new TransportReplacedElement using the "
          "orig_elem [%0x]\n",
          orig_elem));

    // Create the replacement element for the original element.
    ACE_NEW_MALLOC_NORETURN(
      element,
      (TransportQueueElement*)this->replaced_element_allocator_.malloc(),
      TransportReplacedElement(orig_elem, &this->replaced_element_allocator_,
                               &this->replaced_element_mb_allocator_,
                               &this->replaced_element_db_allocator_)
    );
    if( element == 0) {
      // Set fatal error and stop visitation.
      this->status_ = -1;
      return 0;
    }

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "The new TransportReplacedElement is [%0x]\n",
          element));

    // Now we have to deal with replacing the original_blocks chain
    // with duplicates from the msg() chain of the replacement element.

    ACE_Message_Block* replacement_element_blocks =
      const_cast<ACE_Message_Block*>(element->msg());
    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set replacement_element_blocks to the replacement element's "
          "msg() [%0x]\n",
          replacement_element_blocks));

    // Move through the chain to account for the num_elem_blocks_sent
    for (unsigned i = 0; i < num_elem_blocks_sent; i++) {
      replacement_element_blocks = replacement_element_blocks->cont();

      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Moved replacement_element_blocks to its cont() block "
            "[%0x]\n",
            replacement_element_blocks));
    }

    // Make a duplicate of the replacement_element_blocks chain
    ACE_Message_Block* replacement_blocks =
      replacement_element_blocks->duplicate();

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set replacement_blocks to duplicate of "
          "replacement_element_blocks [%0x]\n",
          replacement_blocks));

    // Now adjust the block at the front of the replacement_blocks chain
    // to match the block at the front of the original_blocks chain -
    // with respect to the difference between the rd_ptr() setting and
    // the base() setting.
    size_t rd_offset = original_blocks->rd_ptr() - original_blocks->base();

    if (rd_offset > 0) {
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Call replacement_blocks->rd_ptr(rd_offset) with "
            "rd_offset == [%d]\n",
            rd_offset));
      replacement_blocks->rd_ptr(rd_offset);
    }

    // Find the last block (the tail) in the replacement_blocks chain
    ACE_Message_Block* replacement_blocks_tail = replacement_blocks;

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set replacement_blocks_tail to replacement_blocks "
          "[%0x]\n",
          replacement_blocks_tail));

    while (replacement_blocks_tail->cont() != 0) {
      replacement_blocks_tail = replacement_blocks_tail->cont();
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Moved replacement_blocks_tail to its cont() block "
            "[%0x]\n",
            replacement_blocks_tail));
    }

    // Now we can stitch the unsent packet chain back together using the
    // replacement blocks instead of the orig_blocks.
    replacement_blocks_tail->cont(remaining_chain);

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Stitched replacement_blocks_tail to remaining_chain.\n"));

    if (this->previous_block_ == 0) {
      // Replacing blocks at the head of the unsent packet chain.
      this->head_ = replacement_blocks;
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Replacing blocks at head of unsent packet chain.\n"));

    } else {
      // Replacing blocks not at the head of the unsent packet chain.
      this->previous_block_->cont(replacement_blocks);
      VDBG((LM_DEBUG, "(%P|%t) DBG:   "
            "Replacing blocks not at head of unsent packet chain.\n"));
    }

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Release the original_blocks.\n"));

    // Release the chain of original blocks.
    original_blocks->release();

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Set our status_ to 1.\n"));

    // Set the status to 1 to indicate that an element was replaced,
    // and no problems were encountered.
    this->status_ = 1;

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Tell original element that data_dropped().\n"));

    // Tell the original element (that we replaced), data_dropped()
    // by transport.
    // This visitor is used in TransportSendStrategy::do_remove_sample
    // and TransportSendBuffer::retain_all. In former case, the sample
    // is dropped as a result of writer's remove_sample call. In the
    // later case, the dropped_by_transport is not used as the sample
    // is retained sample and no callback is made to writer.
    this->sample_.released (orig_elem->data_dropped());

    VDBG((LM_DEBUG, "(%P|%t) DBG:   "
          "Return 0 to halt visitation.\n"));

    if (this->sample_.released() ||  this->sample_.msg() != 0) {
      // Replace a single sample if one is specified, otherwise visit the
      // entire queue replacing each sample with the specified
      // publication Id value.
      return 0;
    }
  }

  VDBG((LM_DEBUG, "(%P|%t) DBG:   "
        "Return 1 to continue visitation.\n"));

  // Continue visitation.
  return 1;
}