int ACE_Message_Block::release_i (ACE_Lock *lock) { ACE_TRACE ("ACE_Message_Block::release_i"); // Free up all the continuation messages. if (this->cont_) { ACE_Message_Block *mb = this->cont_; ACE_Message_Block *tmp = 0; do { tmp = mb; mb = mb->cont_; tmp->cont_ = 0; ACE_Data_Block *db = tmp->data_block (); if (tmp->release_i (lock) != 0) { ACE_Allocator *allocator = db->data_block_allocator (); ACE_DES_FREE (db, allocator->free, ACE_Data_Block); } } while (mb); this->cont_ = 0; } int result = 0; if (ACE_BIT_DISABLED (this->flags_, ACE_Message_Block::DONT_DELETE) && this->data_block ()) { if (this->data_block ()->release_no_delete (lock) == 0) result = 1; this->data_block_ = 0; } // We will now commit suicide: this object *must* have come from the // allocator given. if (this->message_block_allocator_ == 0) delete this; else { ACE_Allocator *allocator = this->message_block_allocator_; ACE_DES_FREE (this, allocator->free, ACE_Message_Block); } return result; }
int TAO_DII_Asynch_Reply_Dispatcher::dispatch_reply ( TAO_Pluggable_Reply_Params ¶ms) { this->reply_status_ = params.reply_status (); this->locate_reply_status_ = params.locate_reply_status (); // Transfer the <params.input_cdr_>'s content to this->reply_cdr_ ACE_Data_Block *db = this->reply_cdr_.clone_from (*params.input_cdr_); // See whether we need to delete the data block by checking the // flags. We cannot be happy that we initally allocated the // datablocks of the stack. If this method is called twice, as is in // some cases where the same invocation object is used to make two // invocations like forwarding, the release becomes essential. if (ACE_BIT_DISABLED (db->flags (), ACE_Message_Block::DONT_DELETE)) db->release (); // Steal the buffer, that way we don't do any unnecesary copies of // this data. CORBA::ULong max = params.svc_ctx_.maximum (); CORBA::ULong len = params.svc_ctx_.length (); IOP::ServiceContext* context_list = params.svc_ctx_.get_buffer (1); this->reply_service_info_.replace (max, len, context_list, 1); if (TAO_debug_level >= 4) { TAOLIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P | %t):") ACE_TEXT ("TAO_DII_Asynch_Reply_Dispatcher::dispatch_reply: status = %d\n"), this->reply_status_)); } try { // Call the handler with the reply data. CORBA::Request::_tao_reply_stub (this->reply_cdr_, this->callback_, this->reply_status_); } catch (const CORBA::Exception& ex) { if (TAO_debug_level >= 4) { ex._tao_print_exception ("Exception during reply handler"); } } // This was dynamically allocated. Now the job is done. this->intrusive_remove_ref (this); return 1; }
ACE_Message_Block * ACE_Message_Block::release (void) { ACE_TRACE ("ACE_Message_Block::release"); // We want to hold the data block in a temporary variable because we // invoked "delete this;" at some point, so using this->data_block_ // could be a bad idea. ACE_Data_Block *tmp = this->data_block (); // This flag is set to 1 when we have to destroy the data_block int destroy_dblock = 0; ACE_Lock *lock = 0; // Do we have a valid data block if (this->data_block ()) { // Grab the lock that belongs to my data block lock = this->data_block ()->locking_strategy (); // if we have a lock if (lock != 0) { // One guard for all ACE_GUARD_RETURN (ACE_Lock, ace_mon, *lock, 0); // Call non-guarded release with <lock> destroy_dblock = this->release_i (lock); } // This is the case when we have a valid data block but no lock else // Call non-guarded release with no lock destroy_dblock = this->release_i (0); } else // This is the case when we don't even have a valid data block destroy_dblock = this->release_i (0); if (destroy_dblock != 0) { ACE_Allocator *allocator = tmp->data_block_allocator (); ACE_DES_FREE (tmp, allocator->free, ACE_Data_Block); } return 0; }
ACE_Data_Block * ACE_Data_Block::clone_nocopy (ACE_Message_Block::Message_Flags mask, size_t max_size) const { ACE_FUNCTION_TIMEPROBE(ACE_DATA_BLOCK_CLONE_ENTER); ACE_TRACE ("ACE_Data_Block::clone_nocopy"); // You always want to clear this one to prevent memory leaks but you // might add some others later. const ACE_Message_Block::Message_Flags always_clear = ACE_Message_Block::DONT_DELETE; const size_t newsize = max_size == 0 ? this->max_size_ : max_size; ACE_Data_Block *nb = 0; ACE_NEW_MALLOC_RETURN (nb, static_cast<ACE_Data_Block*> ( this->data_block_allocator_->malloc (sizeof (ACE_Data_Block))), ACE_Data_Block (newsize, // size this->type_, // type 0, // data this->allocator_strategy_, // allocator this->locking_strategy_, // locking strategy this->flags_, // flags this->data_block_allocator_), 0); // Message block initialization may fail while the construction // succeds. Since as a matter of policy, ACE may throw no // exceptions, we have to do a separate check like this. if (nb != 0 && nb->size () < newsize) { nb->ACE_Data_Block::~ACE_Data_Block(); // placement destructor ... this->data_block_allocator_->free (nb); // free ... errno = ENOMEM; return 0; } // Set new flags minus the mask... nb->clr_flags (mask | always_clear); return nb; }
int TAO_Synch_Reply_Dispatcher::dispatch_reply ( TAO_Pluggable_Reply_Params ¶ms) { if (params.input_cdr_ == 0) return -1; this->reply_status_ = params.reply_status (); this->locate_reply_status_ = params.locate_reply_status (); // Steal the buffer, that way we don't do any unnecesary copies of // this data. CORBA::ULong const max = params.svc_ctx_.maximum (); CORBA::ULong const len = params.svc_ctx_.length (); IOP::ServiceContext* context_list = params.svc_ctx_.get_buffer (true); this->reply_service_info_.replace (max, len, context_list, true); if (this->reply_service_info_.length() > 0) { orb_core_->service_context_registry (). process_service_contexts (this->reply_service_info_, *(params.transport_), 0); } // Must reset the message state, it is possible that the same reply // dispatcher is used because the request must be re-sent. // this->message_state_.reset (0); // Transfer the <params.input_cdr_>'s content to this->reply_cdr_ if (ACE_BIT_DISABLED ((*params.input_cdr_).start()->data_block()->flags(), ACE_Message_Block::DONT_DELETE)) { // Data block is on the heap, so just duplicate it. this->reply_cdr_ = *params.input_cdr_; this->reply_cdr_.clr_mb_flags (ACE_Message_Block::DONT_DELETE); } else { ACE_Data_Block *db = this->reply_cdr_.clone_from (*params.input_cdr_); if (db == 0) { if (TAO_debug_level > 2) { TAOLIB_ERROR ((LM_ERROR, "TAO (%P|%t) - Synch_Reply_Dispatcher::dispatch_reply " "clone_from failed\n")); } return -1; } // See whether we need to delete the data block by checking the // flags. We cannot be happy that we initally allocated the // datablocks of the stack. If this method is called twice, as is in // some cases where the same invocation object is used to make two // invocations like forwarding, the release becomes essential. if (ACE_BIT_DISABLED (db->flags (), ACE_Message_Block::DONT_DELETE)) { db->release (); } } this->state_changed (TAO_LF_Event::LFS_SUCCESS, this->orb_core_->leader_follower ()); return 1; }
ACE_Message_Block * ACE_Message_Block::clone (Message_Flags mask) const { ACE_TRACE ("ACE_Message_Block::clone"); // Get a pointer to a "cloned" <ACE_Data_Block> (will copy the // values rather than increment the reference count). ACE_Data_Block *db = this->data_block ()->clone (mask); if (db == 0) return 0; ACE_Message_Block *nb = 0; if (message_block_allocator_ == 0) { ACE_NEW_RETURN (nb, ACE_Message_Block (0, // size ACE_Message_Type (0), // type 0, // cont 0, // data 0, // allocator 0, // locking strategy 0, // flags this->priority_, // priority ACE_EXECUTION_TIME, // execution time ACE_DEADLINE_TIME, // absolute time to deadline // Get a pointer to a // "duplicated" <ACE_Data_Block> // (will simply increment the // reference count). db, db->data_block_allocator (), this->message_block_allocator_), 0); } else { // This is the ACE_NEW_MALLOC macro with the return check removed. // We need to do it this way because if it fails we need to release // the cloned data block that was created above. If we used // ACE_NEW_MALLOC_RETURN, there would be a memory leak because the // above db pointer would be left dangling. nb = static_cast<ACE_Message_Block*> (message_block_allocator_->malloc (sizeof (ACE_Message_Block))); if (nb != 0) new (nb) ACE_Message_Block (0, // size ACE_Message_Type (0), // type 0, // cont 0, // data 0, // allocator 0, // locking strategy 0, // flags this->priority_, // priority ACE_EXECUTION_TIME, // execution time ACE_DEADLINE_TIME, // absolute time to deadline db, db->data_block_allocator (), this->message_block_allocator_); } if (nb == 0) { db->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>. nb->rd_ptr (this->rd_ptr_); nb->wr_ptr (this->wr_ptr_); // Clone all the continuation messages if necessary. if (this->cont () != 0 && (nb->cont_ = this->cont ()->clone (mask)) == 0) { nb->release (); return 0; } return nb; }
// Dispatch the reply. int TAO_Asynch_Reply_Dispatcher::dispatch_reply (TAO_Pluggable_Reply_Params ¶ms) { if (this->timeout_handler_) { // If we had registered timeout handlers just cancel them and // loose ownership of the handlers this->timeout_handler_->cancel (); this->timeout_handler_->remove_reference (); this->timeout_handler_ = 0; // AMI Timeout Handling End } // With Asynch requests the invocation handler can't call idle_after_reply () // since it does not handle the reply. // So we have to do that here in case f.i. the Exclusive TMS left the transport // busy after the send if (this->transport_ != 0) this->transport_->tms ()->idle_after_reply (); if (!params.input_cdr_) return -1; if (!this->try_dispatch_reply ()) return 0; this->reply_status_ = params.reply_status (); this->locate_reply_status_ = params.locate_reply_status (); // Transfer the <params.input_cdr_>'s content to this->reply_cdr_ ACE_Data_Block *db = this->reply_cdr_.clone_from (*params.input_cdr_); if (db == 0) { if (TAO_debug_level > 2) { TAOLIB_ERROR (( LM_ERROR, ACE_TEXT ("TAO_Messaging (%P|%t) - Asynch_Reply_Dispatcher::dispatch_reply ") ACE_TEXT ("clone_from failed\n"))); } return -1; } // See whether we need to delete the data block by checking the // flags. We cannot be happy that we initially allocated the // datablocks of the stack. If this method is called twice, as is in // some cases where the same invocation object is used to make two // invocations like forwarding, the release becomes essential. if (ACE_BIT_DISABLED (db->flags (), ACE_Message_Block::DONT_DELETE)) { db->release (); } if (!CORBA::is_nil (this->reply_handler_.in ())) { // Steal the buffer, that way we don't do any unnecesary copies of // this data. CORBA::ULong const max = params.svc_ctx_.maximum (); CORBA::ULong const len = params.svc_ctx_.length (); IOP::ServiceContext *context_list = params.svc_ctx_.get_buffer (1); this->reply_service_info_.replace (max, len, context_list, 1); if (TAO_debug_level >= 4) { TAOLIB_DEBUG ((LM_DEBUG, ACE_TEXT ("TAO_Messaging (%P|%t) - Asynch_Reply_Dispatcher") ACE_TEXT ("::dispatch_reply status = %d\n"), this->reply_status_)); } CORBA::ULong reply_error = TAO_AMI_REPLY_NOT_OK; switch (this->reply_status_) { case GIOP::NO_EXCEPTION: reply_error = TAO_AMI_REPLY_OK; break; case GIOP::USER_EXCEPTION: reply_error = TAO_AMI_REPLY_USER_EXCEPTION; break; case GIOP::SYSTEM_EXCEPTION: reply_error = TAO_AMI_REPLY_SYSTEM_EXCEPTION; break; case GIOP::LOCATION_FORWARD: reply_error = TAO_AMI_REPLY_LOCATION_FORWARD; break; case GIOP::LOCATION_FORWARD_PERM: reply_error = TAO_AMI_REPLY_LOCATION_FORWARD_PERM; break; default: // @@ Michael: Not even the spec mentions this case. // We have to think about this case. // Handle the forwarding and return so the stub restarts the // request! reply_error = TAO_AMI_REPLY_NOT_OK; break; } try { // Call the Reply Handler's stub. this->reply_handler_stub_ (this->reply_cdr_, this->reply_handler_.in (), reply_error); } catch (const ::CORBA::Exception& ex) { if (TAO_debug_level >= 4) ex._tao_print_exception ("Exception during reply handler"); } } this->intrusive_remove_ref (this); return 1; }
ACE_Message_Block * ACE_Message_Block::clone (Message_Flags mask) const { ACE_TRACE ("ACE_Message_Block::clone"); const ACE_Message_Block *old_message_block = this; ACE_Message_Block *new_message_block = 0; ACE_Message_Block *new_previous_message_block = 0; ACE_Message_Block *new_root_message_block = 0; do { // Get a pointer to a "cloned"<ACE_Data_Block> (will copy the // values rather than increment the reference count). ACE_Data_Block *db = old_message_block->data_block ()->clone (mask); if (db == 0) return 0; if(old_message_block->message_block_allocator_ == 0) { ACE_NEW_RETURN (new_message_block, ACE_Message_Block (0, // size ACE_Message_Type (0), // type 0, // cont 0, // data 0, // allocator 0, // locking strategy 0, // flags old_message_block->priority_, // priority ACE_EXECUTION_TIME, // execution time ACE_DEADLINE_TIME, // absolute time to deadline // Get a pointer to a // "duplicated"<ACE_Data_Block> // (will simply increment the // reference count). db, db->data_block_allocator (), old_message_block->message_block_allocator_), 0); } else { // This is the ACE_NEW_MALLOC macro with the return check removed. // We need to do it this way because if it fails we need to release // the cloned data block that was created above. If we used // ACE_NEW_MALLOC_RETURN, there would be a memory leak because the // above db pointer would be left dangling. new_message_block = static_cast<ACE_Message_Block*> (old_message_block->message_block_allocator_->malloc (sizeof (ACE_Message_Block))); if (new_message_block != 0) new (new_message_block) ACE_Message_Block (0, // size ACE_Message_Type (0), // type 0, // cont 0, // data 0, // allocator 0, // locking strategy 0, // flags old_message_block->priority_, // priority ACE_EXECUTION_TIME, // execution time ACE_DEADLINE_TIME, // absolute time to deadline db, db->data_block_allocator (), old_message_block->message_block_allocator_); } if (new_message_block == 0) { db->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>. new_message_block->rd_ptr (old_message_block->rd_ptr_); new_message_block->wr_ptr (old_message_block->wr_ptr_); // save the root message block to return if (new_root_message_block == 0) new_root_message_block = new_message_block; if (new_previous_message_block != 0) // we're a continuation of the previous block, add ourself to its chain new_previous_message_block->cont_ = new_message_block; new_previous_message_block = new_message_block; old_message_block = old_message_block->cont (); } while (old_message_block != 0); return new_root_message_block; }