ORB_Core.i

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // ORB_Core.i,v 1.164 2006/04/26 21:21:54 jeliazkov_i Exp
00004 
00005 #include "tao/ORB_Core_TSS_Resources.h"
00006 #include "tao/ORB_Table.h"
00007 
00008 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
00009 
00010 ACE_INLINE ACE_Service_Gestalt*
00011 TAO_ORB_Core::configuration (void) const
00012 {
00013   return this->config_;
00014 }
00015 
00016 ACE_INLINE CORBA::ULong
00017 TAO_ORB_Core::_incr_refcnt (void)
00018 {
00019   ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, guard, this->lock_, 0);
00020   return this->refcount_++;
00021 }
00022 
00023 ACE_INLINE CORBA::ULong
00024 TAO_ORB_Core::_decr_refcnt (void)
00025 {
00026   {
00027     ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, mon, this->lock_, 0);
00028     --this->refcount_;
00029     if (this->refcount_ != 0)
00030       return this->refcount_;
00031   }
00032 
00033   this->fini ();
00034   return 0;
00035 }
00036 
00037 ACE_INLINE ACE_Lock *
00038 TAO_ORB_Core::locking_strategy (void)
00039 {
00040   if (this->resource_factory ()->use_locked_data_blocks ())
00041     return &this->data_block_lock_;
00042 
00043   return 0;
00044 }
00045 
00046 ACE_INLINE CORBA::Boolean
00047 TAO_ORB_Core::bidir_giop_policy (void)
00048 {
00049   return this->bidir_giop_policy_;
00050 }
00051 
00052 ACE_INLINE void
00053 TAO_ORB_Core::bidir_giop_policy (CORBA::Boolean val)
00054 {
00055   this->bidir_giop_policy_ = val;
00056 }
00057 
00058 ACE_INLINE TAO_Object_Ref_Table &
00059 TAO_ORB_Core::object_ref_table (void)
00060 {
00061   return this->object_ref_table_;
00062 }
00063 
00064 ACE_INLINE TAO::ObjectKey_Table &
00065 TAO_ORB_Core::object_key_table (void)
00066 {
00067   return this->object_key_table_;
00068 }
00069 
00070 ACE_INLINE TAO_Flushing_Strategy *
00071 TAO_ORB_Core::flushing_strategy (void)
00072 {
00073   return this->flushing_strategy_;
00074 }
00075 
00076 ACE_INLINE TAO_Protocols_Hooks *
00077 TAO_ORB_Core::get_protocols_hooks (void)
00078 {
00079   return this->protocols_hooks_;
00080 }
00081 
00082 ACE_INLINE CORBA::Boolean
00083 TAO_ORB_Core::service_profile_selection (TAO_MProfile &mprofile,
00084                                          TAO_Profile  *&profile)
00085 {
00086   CORBA::Boolean retval = 0;
00087   // @@ If different services have the same feature we may want to
00088   // prioritise them here. We need to decide here whose selection of
00089   // profile is more important.
00090   if (this->ft_service_.service_callback ())
00091     {
00092       retval =
00093         this->ft_service_.service_callback ()->select_profile (&mprofile,
00094                                                                 profile);
00095     }
00096   return retval;
00097 }
00098 
00099 ACE_INLINE CORBA::Boolean
00100 TAO_ORB_Core::service_profile_reselection (TAO_Stub *stub,
00101                                            TAO_Profile *&profile)
00102 {
00103   CORBA::Boolean retval = 0;
00104   // @@ If different services have the same feature we may want to
00105   // prioritise them here. We need to decide here whose selection of
00106   // profile is more important.
00107   if (this->ft_service_.service_callback ())
00108     {
00109       retval =
00110         this->ft_service_.service_callback ()->reselect_profile (stub,
00111                                                                  profile);
00112     }
00113   return retval;
00114 }
00115 
00116 ACE_INLINE void
00117 TAO_ORB_Core::reset_service_profile_flags (void)
00118 {
00119   // @@ If different services have the same feature we may want to
00120   // prioritise them here. We need to decide here whose selection of
00121   // profile is more important.
00122 
00123   if (this->ft_service_.service_callback ())
00124     {
00125       this->ft_service_.service_callback ()->reset_profile_flags ();
00126     }
00127   return;
00128 }
00129 
00130 
00131 ACE_INLINE CORBA::Boolean
00132 TAO_ORB_Core::object_is_nil (CORBA::Object_ptr obj)
00133 {
00134   CORBA::Boolean retval = 0;
00135   if (this->ft_service_.service_callback ())
00136     {
00137       retval =
00138         this->ft_service_.service_callback ()->object_is_nil (obj);
00139     }
00140   return retval;
00141 }
00142 
00143 
00144 ACE_INLINE TAO_Service_Callbacks::Profile_Equivalence
00145 TAO_ORB_Core::is_profile_equivalent (const TAO_Profile *this_p,
00146                                      const TAO_Profile *that_p)
00147 {
00148   TAO_Service_Callbacks::Profile_Equivalence retval
00149     = TAO_Service_Callbacks::DONT_KNOW;
00150 
00151   if (this->ft_service_.service_callback ())
00152     {
00153       retval =
00154         this->ft_service_.service_callback ()->is_profile_equivalent (this_p,
00155                                                                       that_p);
00156     }
00157 
00158   return retval;
00159 }
00160 
00161 ACE_INLINE CORBA::ULong
00162 TAO_ORB_Core::hash_service (TAO_Profile *p,
00163                             CORBA::ULong m)
00164 {
00165   if (this->ft_service_.service_callback ())
00166     {
00167       return this->ft_service_.service_callback ()->hash_ft (p, m);
00168     }
00169 
00170   return 0;
00171 }
00172 
00173 ACE_INLINE TAO_Fault_Tolerance_Service &
00174 TAO_ORB_Core::fault_tolerance_service (void)
00175 {
00176   return this->ft_service_;
00177 }
00178 
00179 ACE_INLINE ACE_Thread_Manager *
00180 TAO_ORB_Core::thr_mgr (void)
00181 {
00182   return &this->tm_;
00183 }
00184 
00185 ACE_INLINE CORBA::ORB_ptr
00186 TAO_ORB_Core::orb (void)
00187 {
00188   return this->orb_;
00189 }
00190 
00191 ACE_INLINE TAO_Adapter_Registry *
00192 TAO_ORB_Core::adapter_registry (void)
00193 {
00194   return &this->adapter_registry_;
00195 }
00196 
00197 ACE_INLINE TAO_Request_Dispatcher *
00198 TAO_ORB_Core::request_dispatcher (void)
00199 {
00200   return this->request_dispatcher_;
00201 }
00202 
00203 ACE_INLINE TAO_ORB_Core::InitRefMap *
00204 TAO_ORB_Core::init_ref_map (void)
00205 {
00206   return &this->init_ref_map_;
00207 }
00208 
00209 ACE_INLINE void
00210 TAO_ORB_Core::set_default (const char * orb_id)
00211 {
00212   TAO::ORB_Table * const table = TAO::ORB_Table::instance ();
00213   table->set_default (orb_id);
00214 }
00215 
00216 ACE_INLINE void
00217 TAO_ORB_Core::not_default (const char * orb_id)
00218 {
00219   TAO::ORB_Table * const table = TAO::ORB_Table::instance ();
00220   table->not_default (orb_id);
00221 }
00222 
00223 ACE_INLINE void
00224 TAO_ORB_Core::optimize_collocation_objects (CORBA::Boolean opt)
00225 {
00226   this->opt_for_collocation_ = opt;
00227 }
00228 
00229 ACE_INLINE CORBA::Boolean
00230 TAO_ORB_Core::optimize_collocation_objects (void) const
00231 {
00232   return this->opt_for_collocation_;
00233 }
00234 
00235 ACE_INLINE void
00236 TAO_ORB_Core::use_global_collocation (CORBA::Boolean opt)
00237 {
00238   this->use_global_collocation_ = opt;
00239 }
00240 
00241 ACE_INLINE CORBA::Boolean
00242 TAO_ORB_Core::use_global_collocation (void) const
00243 {
00244   return this->use_global_collocation_;
00245 }
00246 
00247 ACE_INLINE CORBA::ULong
00248 TAO_ORB_Core::get_collocation_strategy (void) const
00249 {
00250   return this->collocation_strategy_;
00251 }
00252 
00253 ACE_INLINE TAO_ORB_Parameters *
00254 TAO_ORB_Core::orb_params(void)
00255 {
00256   return &(this->orb_params_);
00257 }
00258 
00259 #define TAO_OC_RETRIEVE(member) \
00260 ((this->member##_ == 0) \
00261   ? (this->member##_ = this->resource_factory ()->get_##member ()) \
00262   : (this->member##_))
00263 
00264 ACE_INLINE TAO_ProtocolFactorySet *
00265 TAO_ORB_Core::protocol_factories (void)
00266 {
00267   return TAO_OC_RETRIEVE (protocol_factories);
00268 }
00269 
00270 ACE_INLINE TAO_Parser_Registry *
00271 TAO_ORB_Core::parser_registry (void)
00272 {
00273   return &this->parser_registry_;
00274 }
00275 
00276 #undef TAO_OC_RETRIEVE
00277 
00278 #if (TAO_HAS_CORBA_MESSAGING == 1)
00279 
00280 ACE_INLINE TAO_Policy_Manager *
00281 TAO_ORB_Core::policy_manager (void)
00282 {
00283   return this->policy_manager_;
00284 }
00285 
00286 #endif /* TAO_HAS_CORBA_MESSAGING == 1 */
00287 
00288 ACE_INLINE TAO_ORB_Core_TSS_Resources*
00289 TAO_ORB_Core::get_tss_resources (void)
00290 {
00291   return ACE_TSS_GET (&this->tss_resources_,TAO_ORB_Core_TSS_Resources);
00292 }
00293 
00294 ACE_INLINE void *
00295 TAO_ORB_Core::get_tss_resource (size_t slot_id)
00296 {
00297   TAO_ORB_Core_TSS_Resources *tss_resources =
00298     this->get_tss_resources ();
00299 
00300   if (slot_id >= tss_resources->ts_objects_.size ())
00301     return 0;
00302 
00303   return tss_resources->ts_objects_[slot_id];
00304 }
00305 
00306 ACE_INLINE int
00307 TAO_ORB_Core::set_tss_resource (size_t slot_id, void *ts_object)
00308 {
00309   TAO_ORB_Core_TSS_Resources *tss_resources =
00310     this->get_tss_resources ();
00311 
00312   // The number of allocated slots is equal to the number of
00313   // registered TSS cleanup functions, *not* the size of the array in
00314   // the ORB core TSS resources.
00315   if (slot_id >= this->tss_cleanup_funcs_.size ())
00316     {
00317       errno = EINVAL;
00318       return -1;
00319     }
00320 
00321   // If the TSS array isn't large enough, then increase its size.
00322   // We're guaranteed not to exceed the number of allocated slots by
00323   // the above check.
00324   const size_t old_size = tss_resources->ts_objects_.size ();
00325   const size_t new_size = slot_id + 1;
00326   if (slot_id >= old_size
00327       && tss_resources->ts_objects_.size (new_size) != 0)
00328     return -1;
00329 
00330   // Initialize intermediate array elements to zero, since they
00331   // haven't been initialized yet.  This ensures that garbage is not
00332   // returned when accessing any of those elements at a later point in
00333   // time.
00334   for (size_t i = old_size; i < slot_id; ++i)
00335     tss_resources->ts_objects_[i] = 0;
00336 
00337   tss_resources->ts_objects_[slot_id] = ts_object;
00338 
00339   // Make sure the ORB core pointer is set in the ORB core's TSS
00340   // resources so that the TSS cleanup functions stored in the ORB
00341   // core can be invoked.
00342   tss_resources->orb_core_ = this;
00343 
00344   return 0;
00345 }
00346 
00347 ACE_INLINE TAO_Cleanup_Func_Registry *
00348 TAO_ORB_Core::tss_cleanup_funcs (void)
00349 {
00350   return &(this->tss_cleanup_funcs_);
00351 }
00352 
00353 ACE_INLINE int
00354 TAO_ORB_Core::has_shutdown (void)
00355 {
00356   return this->has_shutdown_;
00357 }
00358 
00359 ACE_INLINE int
00360 TAO_ORB_Core::thread_per_connection_timeout (ACE_Time_Value &timeout) const
00361 {
00362   timeout = this->thread_per_connection_timeout_;
00363   return this->thread_per_connection_use_timeout_;
00364 }
00365 
00366 ACE_INLINE const char *
00367 TAO_ORB_Core::orbid (void) const
00368 {
00369   return this->orbid_;
00370 }
00371 
00372 ACE_INLINE void
00373 TAO_ORB_Core::implrepo_service (const CORBA::Object_ptr ir)
00374 {
00375   this->implrepo_service_ = ir;
00376 }
00377 
00378 ACE_INLINE CORBA::Boolean
00379 TAO_ORB_Core::use_implrepo (void)
00380 {
00381   return use_implrepo_;
00382 }
00383 
00384 ACE_INLINE CORBA::Boolean
00385 TAO_ORB_Core::imr_endpoints_in_ior (void)
00386 {
00387   return imr_endpoints_in_ior_;
00388 }
00389 
00390 ACE_INLINE CORBA::Object_ptr
00391 TAO_ORB_Core::resolve_typecodefactory (ACE_ENV_SINGLE_ARG_DECL)
00392 {
00393   ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, mon, this->lock_,
00394                     CORBA::Object::_nil ());
00395   if (CORBA::is_nil (this->typecode_factory_))
00396     {
00397       this->resolve_typecodefactory_i (ACE_ENV_SINGLE_ARG_PARAMETER);
00398       ACE_CHECK_RETURN (CORBA::Object::_nil ());
00399     }
00400   return CORBA::Object::_duplicate (this->typecode_factory_);
00401 }
00402 
00403 #if TAO_HAS_INTERCEPTORS == 1
00404 
00405 ACE_INLINE CORBA::Object_ptr
00406 TAO_ORB_Core::resolve_picurrent (ACE_ENV_SINGLE_ARG_DECL)
00407 {
00408   ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, mon, this->lock_,
00409                     CORBA::Object::_nil ());
00410   if (CORBA::is_nil (this->pi_current_))
00411     {
00412       this->resolve_picurrent_i (ACE_ENV_SINGLE_ARG_PARAMETER);
00413       ACE_CHECK_RETURN (CORBA::Object::_nil ());
00414     }
00415   return CORBA::Object::_duplicate (this->pi_current_);
00416 }
00417 
00418 #endif  /* TAO_HAS_INTERCEPTORS == 1 */
00419 
00420 ACE_INLINE CORBA::Object_ptr
00421 TAO_ORB_Core::resolve_codecfactory (ACE_ENV_SINGLE_ARG_DECL)
00422 {
00423   ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, mon, this->lock_,
00424                     CORBA::Object::_nil ());
00425   if (CORBA::is_nil (this->codec_factory_))
00426     {
00427       this->resolve_codecfactory_i (ACE_ENV_SINGLE_ARG_PARAMETER);
00428       ACE_CHECK_RETURN (CORBA::Object::_nil ());
00429     }
00430   return CORBA::Object::_duplicate (this->codec_factory_);
00431 }
00432 
00433 ACE_INLINE const char *
00434 TAO_ORB_Core::server_id (void) const
00435 {
00436   return this->server_id_.c_str();
00437 }
00438 
00439 ACE_INLINE TAO_Codeset_Manager *
00440 TAO_ORB_Core::codeset_manager()
00441 {
00442   if (this->orb_params()->negotiate_codesets() == 0)
00443     return 0;
00444   if (this->codeset_manager_ == 0)
00445     {
00446       // This causes a factory to be loaded which will call
00447       // the codeset_manager setter in this thread.
00448       this->codeset_manager_ =
00449         this->resource_factory()->codeset_manager();
00450       if (this->codeset_manager_ == 0)
00451         this->orb_params()->negotiate_codesets(false);
00452     }
00453   return this->codeset_manager_;
00454 }
00455 
00456 ACE_INLINE TAO::ORBInitializer_Registry_Adapter *
00457 TAO_ORB_Core::orbinitializer_registry ()
00458 {
00459   ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, mon, this->lock_,
00460                     0);
00461   if (orbinitializer_registry_ == 0)
00462     {
00463       return this->orbinitializer_registry_i ();
00464     }
00465   return this->orbinitializer_registry_;
00466 }
00467 
00468 ACE_INLINE TAO::PolicyFactory_Registry_Adapter *
00469 TAO_ORB_Core::policy_factory_registry ()
00470 {
00471   ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, mon, this->lock_,
00472                     0);
00473   if (policy_factory_registry_ == 0)
00474     {
00475       return this->policy_factory_registry_i ();
00476     }
00477   return this->policy_factory_registry_;
00478 }
00479 
00480 ACE_INLINE CORBA::Object_ptr
00481 TAO_ORB_Core::resolve_dynanyfactory (ACE_ENV_SINGLE_ARG_DECL)
00482 {
00483   ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, mon, this->lock_,
00484                     CORBA::Object::_nil ());
00485   if (CORBA::is_nil (this->dynany_factory_))
00486     {
00487       this->resolve_dynanyfactory_i (ACE_ENV_SINGLE_ARG_PARAMETER);
00488       ACE_CHECK_RETURN (CORBA::Object::_nil ());
00489     }
00490   return CORBA::Object::_duplicate (this->dynany_factory_);
00491 }
00492 
00493 ACE_INLINE CORBA::Object_ptr
00494 TAO_ORB_Core::resolve_ior_manipulation (ACE_ENV_SINGLE_ARG_DECL)
00495 {
00496   ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, mon, this->lock_,
00497                     CORBA::Object::_nil ());
00498   if (CORBA::is_nil (this->ior_manip_factory_))
00499     {
00500       this->resolve_iormanipulation_i (ACE_ENV_SINGLE_ARG_PARAMETER);
00501       ACE_CHECK_RETURN (CORBA::Object::_nil ());
00502     }
00503   return CORBA::Object::_duplicate (this->ior_manip_factory_);
00504 }
00505 
00506 ACE_INLINE CORBA::Object_ptr
00507 TAO_ORB_Core::resolve_ior_table (ACE_ENV_SINGLE_ARG_DECL)
00508 {
00509   ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, mon, this->lock_,
00510                     CORBA::Object::_nil ());
00511   if (CORBA::is_nil (this->ior_table_))
00512     {
00513       this->resolve_ior_table_i (ACE_ENV_SINGLE_ARG_PARAMETER);
00514       ACE_CHECK_RETURN (CORBA::Object::_nil ());
00515     }
00516   return CORBA::Object::_duplicate (this->ior_table_);
00517 }
00518 
00519 // ****************************************************************
00520 
00521 #if (TAO_HAS_BUFFERING_CONSTRAINT_POLICY == 1)
00522 
00523 ACE_INLINE TAO::Transport_Queueing_Strategy &
00524 TAO_ORB_Core::eager_transport_queueing_strategy (void)
00525 {
00526   return *this->eager_transport_queueing_strategy_;
00527 }
00528 
00529 ACE_INLINE TAO::Transport_Queueing_Strategy &
00530 TAO_ORB_Core::delayed_transport_queueing_strategy (void)
00531 {
00532   return *this->delayed_transport_queueing_strategy_;
00533 }
00534 
00535 ACE_INLINE TAO::Transport_Queueing_Strategy &
00536 TAO_ORB_Core::flush_transport_queueing_strategy (void)
00537 {
00538   return *this->flush_transport_queueing_strategy_;
00539 }
00540 
00541 #endif /* TAO_HAS_BUFFERING_CONSTRAINT_POLICY == 1 */
00542 
00543 ACE_INLINE TAO::Transport_Queueing_Strategy &
00544 TAO_ORB_Core::default_transport_queueing_strategy (void)
00545 {
00546   return *this->default_transport_queueing_strategy_;
00547 }
00548 
00549 #if (TAO_HAS_CORBA_MESSAGING == 1)
00550 
00551 ACE_INLINE TAO_Policy_Current &
00552 TAO_ORB_Core::policy_current (void)
00553 {
00554   return *this->policy_current_;
00555 }
00556 
00557 #endif /* TAO_HAS_CORBA_MESSAGING == 1 */
00558 
00559 ACE_INLINE CORBA::Object_ptr
00560 TAO_ORB_Core::resolve_poa_current (ACE_ENV_SINGLE_ARG_DECL)
00561 {
00562   ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, mon, this->lock_,
00563                     CORBA::Object::_nil ());
00564   if (CORBA::is_nil (this->poa_current_.in ()))
00565     {
00566       this->resolve_poa_current_i (ACE_ENV_SINGLE_ARG_PARAMETER);
00567       ACE_CHECK_RETURN (CORBA::Object::_nil ());
00568     }
00569   return CORBA::Object::_duplicate (this->poa_current_.in ());
00570 }
00571 
00572 #if (TAO_HAS_CORBA_MESSAGING == 1)
00573 
00574 ACE_INLINE  TAO_Policy_Set *
00575 TAO_ORB_Core::get_default_policies (void)
00576 {
00577   return this->default_policies_;
00578 }
00579 
00580 #endif /* TAO_HAS_CORBA_MESSAGING == 1 */
00581 
00582 ACE_INLINE CORBA::Object_ptr
00583 TAO_ORB_Core::resolve_rt_orb (void)
00584 {
00585   if (CORBA::is_nil (this->rt_orb_.in ()))
00586     {
00587       ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, mon, this->lock_,
00588                         CORBA::Object::_nil ());
00589       if (CORBA::is_nil (this->rt_orb_.in ()))
00590         {
00591           // Save a reference to the priority mapping manager.
00592           this->rt_orb_ =
00593               this->object_ref_table ().resolve_initial_reference (
00594               TAO_OBJID_RTORB);
00595         }
00596     }
00597 
00598   return CORBA::Object::_duplicate (this->rt_orb_.in ());
00599 }
00600 
00601 #if (TAO_HAS_INTERCEPTORS == 1)
00602 ACE_INLINE CORBA::Object_ptr
00603 TAO_ORB_Core::pi_current (void)
00604 {
00605   // A pointer/reference to PICurrent is cached in the ORB Core since
00606   // it is accessed in the critical path (i.e. the request invocation
00607   // path).  Caching it prevents additional overhead to due object
00608   // resolution from occurring.
00609   return this->pi_current_;
00610 }
00611 
00612 ACE_INLINE void
00613 TAO_ORB_Core::pi_current (CORBA::Object_ptr current)
00614 {
00615   // Not duplicated since the ORB Core's "object_ref_table" already
00616   // contains a duplicate of the PICurrent object.
00617   this->pi_current_ = current;
00618 }
00619 
00620 ACE_INLINE TAO::ClientRequestInterceptor_Adapter *
00621 TAO_ORB_Core::clientrequestinterceptor_adapter (void)
00622 {
00623   return this->client_request_interceptor_adapter_;
00624 }
00625 
00626 ACE_INLINE TAO::ServerRequestInterceptor_Adapter *
00627 TAO_ORB_Core::serverrequestinterceptor_adapter (void)
00628 {
00629   return this->server_request_interceptor_adapter_;
00630 }
00631 
00632 #endif /* TAO_HAS_INTERCEPTORS */
00633 
00634 /// Verify condition for  permanent forward is given,
00635 /// both parameters must provide group attributes.
00636 ACE_INLINE  CORBA::Boolean
00637 TAO_ORB_Core::is_permanent_forward_condition
00638 (const CORBA::Object_ptr obj,
00639  const TAO_Service_Context &service_context)
00640 {
00641   const TAO_Service_Callbacks *service_callback =
00642       this->fault_tolerance_service ().service_callback ();
00643 
00644   const CORBA::Boolean permanent_forward_condition =
00645       service_callback &&
00646       service_callback->is_permanent_forward_condition (obj,
00647                                                         service_context);
00648 
00649   return permanent_forward_condition;
00650 }
00651 
00652 TAO_END_VERSIONED_NAMESPACE_DECL

Generated on Thu Nov 9 11:54:19 2006 for TAO by doxygen 1.3.6