#include "orbsvcs/Log_Macros.h" #include "orbsvcs/Time_Utilities.h" #include "orbsvcs/Runtime_Scheduler.h" #include "ace/OS_NS_string.h" TAO_BEGIN_VERSIONED_NAMESPACE_DECL // Constructor. Initialize the data from the POD_RT_Info array. ACE_Runtime_Scheduler:: ACE_Runtime_Scheduler (int config_count, ACE_Scheduler_Factory::POD_Config_Info config_info[], int entry_count, ACE_Scheduler_Factory::POD_RT_Info rt_info[]) : config_count_ (config_count), config_info_ (config_info), entry_count_ (entry_count), rt_info_ (rt_info) { } // Create an RT_Info. In the config run scheduler this actually constructs // a new RT_Info. Here, we just return its handle, or an error value if // it's not present. RtecScheduler::handle_t ACE_Runtime_Scheduler::create (const char *entry_point) { // Just make sure it's there and return its handle. for (int i = 0; i < entry_count_; ++i) if (ACE_OS::strcmp (entry_point, rt_info_[i].entry_point) == 0) return i + 1; // TODO: throw an exception or print an error. return -1; } // Lookup a handle for an RT_Info, and return its handle, or an error // value if it's not present. RtecScheduler::handle_t ACE_Runtime_Scheduler::lookup (const char * entry_point) { return create (entry_point); } // Return a pointer to the RT_Info corresponding to the passed handle. RtecScheduler::RT_Info * ACE_Runtime_Scheduler::get (RtecScheduler::handle_t handle) { if (handle <= 0 || handle > entry_count_) throw RtecScheduler::UNKNOWN_TASK (); // Note: there is no memory leak here, according to the CORBA spec, // we are supposed to allocate an structure and return it, the // caller owns it from then on. // Allocate a new RT_Info RtecScheduler::RT_Info* info; ACE_NEW_THROW_EX (info, RtecScheduler::RT_Info, CORBA::NO_MEMORY ()); info->entry_point = rt_info_[handle - 1].entry_point; info->handle = rt_info_[handle - 1].handle; info->worst_case_execution_time = rt_info_[handle - 1].worst_case_execution_time; info->typical_execution_time = rt_info_[handle - 1].typical_execution_time; info->cached_execution_time = rt_info_[handle - 1].cached_execution_time; info->period = rt_info_[handle - 1].period; info->criticality = RtecScheduler::Criticality_t(rt_info_[handle - 1].criticality); info->importance = RtecScheduler::Importance_t(rt_info_[handle - 1].importance); info->quantum = rt_info_[handle - 1].quantum; info->threads = rt_info_[handle - 1].threads; info->priority = rt_info_[handle - 1].priority; info->preemption_subpriority = rt_info_[handle - 1].static_subpriority; info->preemption_priority = rt_info_[handle - 1].preemption_priority; info->info_type = RtecScheduler::Info_Type_t(rt_info_[handle - 1].info_type); return info; } // Set characteristics of the RT_Info corresponding to the passed handle. void ACE_Runtime_Scheduler::set (::RtecScheduler::handle_t handle, ::RtecScheduler::Criticality_t criticality, ::RtecScheduler::Time time, ::RtecScheduler::Time typical_time, ::RtecScheduler::Time cached_time, ::RtecScheduler::Period_t period, ::RtecScheduler::Importance_t importance, ::RtecScheduler::Quantum_t quantum, ::RtecScheduler::Threads_t threads, ::RtecScheduler::Info_Type_t info_type) { // We compare the values with the ones stored and print a message on // any differences. if (handle <= 0 || handle > entry_count_) { ORBSVCS_DEBUG ((LM_DEBUG, "Unknown task: no entry for handle %d\n", handle)); throw RtecScheduler::UNKNOWN_TASK(); // NOTREACHED } if (rt_info_[handle - 1].worst_case_execution_time != time || rt_info_[handle - 1].typical_execution_time != typical_time || rt_info_[handle - 1].cached_execution_time != cached_time || rt_info_[handle - 1].period != period || rt_info_[handle - 1].criticality != criticality || rt_info_[handle - 1].importance != static_cast (importance) || rt_info_[handle - 1].quantum != quantum || rt_info_[handle - 1].info_type != info_type || rt_info_[handle - 1].threads != static_cast (threads)) ORBSVCS_ERROR ((LM_ERROR, "invalid data for RT_Info: %s\n", (const char*)rt_info_[handle - 1].entry_point)); // TODO: throw something here. } void ACE_Runtime_Scheduler::reset (RtecScheduler::handle_t handle, RtecScheduler::Criticality_t criticality, RtecScheduler::Time time, RtecScheduler::Time typical_time, RtecScheduler::Time cached_time, RtecScheduler::Period_t period, RtecScheduler::Importance_t importance, RtecScheduler::Quantum_t quantum, RtecScheduler::Threads_t threads, RtecScheduler::Info_Type_t info_type) { // Just go ahead and call the set method this->set (handle, criticality, time, typical_time, cached_time, period, importance, quantum, threads, info_type ); } void ACE_Runtime_Scheduler::set_seq (const RtecScheduler::RT_Info_Set& infos) { for (u_int i = 0; i < infos.length (); ++i) { // Call the internal set method. this->set (infos[i].handle, infos[i].criticality, infos[i].worst_case_execution_time, infos[i].typical_execution_time, infos[i].cached_execution_time, infos[i].period, infos[i].importance, infos[i].quantum, infos[i].threads, infos[i].info_type); } } void ACE_Runtime_Scheduler::replace_seq (const RtecScheduler::RT_Info_Set& infos) { for (u_int i = 0; i < infos.length (); ++i) { // Call the internal set method. this->set (infos[i].handle, infos[i].criticality, infos[i].worst_case_execution_time, infos[i].typical_execution_time, infos[i].cached_execution_time, infos[i].period, infos[i].importance, infos[i].quantum, infos[i].threads, infos[i].info_type); } } void ACE_Runtime_Scheduler::reset_seq (const RtecScheduler::RT_Info_Set& infos) { // Just call the set sequence method this->set_seq (infos); } // Returns the priority and subpriority values assigned to an RT_Info, // based on its handle. void ACE_Runtime_Scheduler::priority (RtecScheduler::handle_t handle, RtecScheduler::OS_Priority& o_priority, RtecScheduler::Preemption_Subpriority_t& subpriority, RtecScheduler::Preemption_Priority_t& p_priority) { if (handle <= 0 || handle > entry_count_) throw RtecScheduler::UNKNOWN_TASK (); // NOTREACHED o_priority = rt_info_[handle - 1].priority; subpriority = rt_info_[handle - 1].static_subpriority; p_priority = rt_info_[handle - 1].preemption_priority; } // Returns the priority and subpriority values assigned to an RT_Info, // based on its entry point name. void ACE_Runtime_Scheduler::entry_point_priority (const char * entry_point, RtecScheduler::OS_Priority& priority, RtecScheduler::Preemption_Subpriority_t& subpriority, RtecScheduler::Preemption_Priority_t& p_priority) { RtecScheduler::handle_t handle = lookup (entry_point); if (handle < -1) // The exception was thrown or is in already. return; this->priority (handle, priority, subpriority, p_priority); } // In the config run scheduler, this method registers a dependency between // two RT_Infos. In the run time scheduler, this is a no-op. void ACE_Runtime_Scheduler::add_dependency (RtecScheduler::handle_t handle, RtecScheduler::handle_t /* dependency */, CORBA::Long /* number_of_calls */, RtecScheduler::Dependency_Type_t /* dependency_type */) { if (handle <= 0 || handle > entry_count_) throw RtecScheduler::UNKNOWN_TASK (); // NOTREACHED #if 0 // Just check that the information is consistent. RtecScheduler::Dependency_Set& deps = rt_info_[handle - 1]->dependencies; for (CORBA::ULong i = 0; i < deps.length (); ++i) { if (deps[i].rt_info == dependency && deps[i].number_of_calls == number_of_calls && deps[i].dependency_type == dependency_type) { return; } } ORBSVCS_ERROR ((LM_ERROR, "unmatched dependency on %s\n", (const char*)rt_info_[handle - 1]->entry_point)); #endif } // In the reconfig scheduler, this method removes a dependency between // two RT_Infos. In the run time scheduler, this is a no-op. void ACE_Runtime_Scheduler::remove_dependency (RtecScheduler::handle_t handle, RtecScheduler::handle_t /* dependency */, CORBA::Long /* number_of_calls */, RtecScheduler::Dependency_Type_t /* dependency_type */) { if (handle <= 0 || handle > entry_count_) throw RtecScheduler::UNKNOWN_TASK (); } // In the reconfig scheduler, this method enables a dependency between // two RT_Infos. In the run time scheduler, this is a no-op. void ACE_Runtime_Scheduler::set_dependency_enable_state (RtecScheduler::handle_t handle, RtecScheduler::handle_t /* dependency */, CORBA::Long /* number_of_calls */, RtecScheduler::Dependency_Type_t /* dependency_type */, RtecScheduler::Dependency_Enabled_Type_t /* enabled */) { if (handle <= 0 || handle > entry_count_) throw RtecScheduler::UNKNOWN_TASK (); } // In the reconfig scheduler, this method enables or disables an RT_Info. // In the run time scheduler, this is a no-op. void ACE_Runtime_Scheduler::set_rt_info_enable_state (RtecScheduler::handle_t handle, RtecScheduler::RT_Info_Enabled_Type_t /* enabled */) { if (handle <= 0 || handle > entry_count_) throw RtecScheduler::UNKNOWN_TASK (); } void ACE_Runtime_Scheduler::set_dependency_enable_state_seq (const RtecScheduler::Dependency_Set & dependencies) // This method sets the enable state of a sequence of dependencies. { ACE_UNUSED_ARG (dependencies); throw CORBA::NO_IMPLEMENT (); } void ACE_Runtime_Scheduler::set_rt_info_enable_state_seq ( const RtecScheduler::RT_Info_Enable_State_Pair_Set &) // This method enables or disables a sequence of RT_Infos. { } // In the config run scheduler, this method causes scheduling information // to be computed for all registered RT_Infos. In the run time scheduler, // this is a no-op. void ACE_Runtime_Scheduler::compute_scheduling (CORBA::Long /* minimum_priority */, CORBA::Long /* maximum_priority */, RtecScheduler::RT_Info_Set_out /* infos */, RtecScheduler::Dependency_Set_out /*dependencies */, RtecScheduler::Config_Info_Set_out /* configs */, RtecScheduler::Scheduling_Anomaly_Set_out /* anomalies */) { // TODO: Right now just do nothing, later we could validate the // priorities (without recomputing). // TODO: fill up the infos. return; } // Recomputes the scheduling priorities, etc. void ACE_Runtime_Scheduler::recompute_scheduling (CORBA::Long minimum_priority, CORBA::Long maximum_priority, RtecScheduler::Scheduling_Anomaly_Set_out anomalies) { // TODO: Right now just do nothing. ACE_UNUSED_ARG(minimum_priority); ACE_UNUSED_ARG(maximum_priority); ACE_UNUSED_ARG(anomalies); return; } // Returns the set of rt_infos, with their assigned priorities (as // of the last schedule re-computation). void ACE_Runtime_Scheduler::get_rt_info_set (RtecScheduler::RT_Info_Set_out infos) { // TODO: Right now just do nothing. ACE_UNUSED_ARG(infos); return; } // Returns the set of rt_infos, with their assigned priorities (as // of the last schedule re-computation). void ACE_Runtime_Scheduler::get_dependency_set (RtecScheduler::Dependency_Set_out dependencies) { // TODO: Right now just do nothing. ACE_UNUSED_ARG(dependencies); return; } // Returns the set of config_infos, describing the appropriate // number, types, and priority levels for the dispatching lanes. void ACE_Runtime_Scheduler::get_config_info_set (RtecScheduler::Config_Info_Set_out configs) { // TODO: Right now just do nothing. ACE_UNUSED_ARG(configs); return; } // Provides the thread priority and queue type for the given priority // level. void ACE_Runtime_Scheduler::dispatch_configuration (RtecScheduler::Preemption_Priority_t p_priority, RtecScheduler::OS_Priority& priority, RtecScheduler::Dispatching_Type_t & d_type) { // Throw an exception if a valid schedule has not been loaded if (config_count_ <= 0 || config_info_ [p_priority].preemption_priority != p_priority) { throw RtecScheduler::NOT_SCHEDULED (); ACE_NOTREACHED (return); } // throw an exception if an invalid priority was passed else if (p_priority < 0 || p_priority >= config_count_) { throw RtecScheduler::UNKNOWN_PRIORITY_LEVEL(); ACE_NOTREACHED (return); } else { priority = config_info_ [p_priority].thread_priority; d_type = config_info_ [p_priority].dispatching_type; return; } } // Returns the last priority number assigned to an operation in the // schedule. The number returned is one less than the total number // of scheduled priorities. All scheduled priorities range from 0 // to the number returned, inclusive. RtecScheduler::Preemption_Priority_t ACE_Runtime_Scheduler::last_scheduled_priority () { // throw an exception if a valid schedule has not been loaded if (config_count_ <= 0) throw RtecScheduler::NOT_SCHEDULED(); else return (RtecScheduler::Preemption_Priority_t) (config_count_ - 1); } void ACE_Runtime_Scheduler::get_config_infos (RtecScheduler::Config_Info_Set_out /*configs */) { // throw an exception if a valid schedule has not been loaded if (this->config_count_ <= 0) throw RtecScheduler::NOT_SCHEDULED(); //TODO: fill the Config_Info_Set with the runtime Config_Infos //for now, this function is unimplemented // // @@ If unimplemented we either return a CORBA::NO_IMPL exception // or a proprietary ACE_NOTSUP; -- Bala throw CORBA::NO_IMPLEMENT (); } TAO_END_VERSIONED_NAMESPACE_DECL