Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
scheduler.h
00001 /****************************************************************************** 00002 The MIT License(MIT) 00003 00004 Embedded Template Library. 00005 https://github.com/ETLCPP/etl 00006 http://www.etlcpp.com 00007 00008 Copyright(c) 2017 jwellbelove 00009 00010 Permission is hereby granted, free of charge, to any person obtaining a copy 00011 of this software and associated documentation files(the "Software"), to deal 00012 in the Software without restriction, including without limitation the rights 00013 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 00014 copies of the Software, and to permit persons to whom the Software is 00015 furnished to do so, subject to the following conditions : 00016 00017 The above copyright notice and this permission notice shall be included in all 00018 copies or substantial portions of the Software. 00019 00020 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00021 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00022 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 00023 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00024 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00025 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00026 SOFTWARE. 00027 ******************************************************************************/ 00028 00029 #ifndef __ETL_SCHEDULER__ 00030 #define __ETL_SCHEDULER__ 00031 00032 #include <stdint.h> 00033 00034 #include "platform.h " 00035 #include "vector.h " 00036 #include "nullptr.h " 00037 #include "error_handler.h " 00038 #include "exception.h " 00039 #include "task.h" 00040 #include "type_traits.h " 00041 #include "function.h " 00042 00043 #undef ETL_FILE 00044 #define ETL_FILE "36" 00045 00046 namespace etl 00047 { 00048 //*************************************************************************** 00049 /// Base exception class for scheduler. 00050 //*************************************************************************** 00051 class scheduler_exception : public etl::exception 00052 { 00053 public: 00054 00055 scheduler_exception(string_type reason_, string_type file_name_, numeric_type line_number_) 00056 : etl::exception(reason_, file_name_, line_number_) 00057 { 00058 } 00059 }; 00060 00061 //*************************************************************************** 00062 /// 'No tasks' exception. 00063 //*************************************************************************** 00064 class scheduler_no_tasks_exception : public etl::scheduler_exception 00065 { 00066 public: 00067 00068 scheduler_no_tasks_exception(string_type file_name_, numeric_type line_number_) 00069 : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:no tasks", ETL_FILE"A"), file_name_, line_number_) 00070 { 00071 } 00072 }; 00073 00074 //*************************************************************************** 00075 /// 'Null tasks' exception. 00076 //*************************************************************************** 00077 class scheduler_null_task_exception : public etl::scheduler_exception 00078 { 00079 public: 00080 00081 scheduler_null_task_exception(string_type file_name_, numeric_type line_number_) 00082 : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:null task", ETL_FILE"B"), file_name_, line_number_) 00083 { 00084 } 00085 }; 00086 00087 //*************************************************************************** 00088 /// 'Too many tasks' exception. 00089 //*************************************************************************** 00090 class scheduler_too_many_tasks_exception : public etl::scheduler_exception 00091 { 00092 public: 00093 00094 scheduler_too_many_tasks_exception(string_type file_name_, numeric_type line_number_) 00095 : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:too many tasks", ETL_FILE"C"), file_name_, line_number_) 00096 { 00097 } 00098 }; 00099 00100 //*************************************************************************** 00101 /// Sequencial Single. 00102 /// A policy the scheduler can use to decide what to do next. 00103 /// Only calls the task to process work once, if it has work to do. 00104 //*************************************************************************** 00105 struct scheduler_policy_sequencial_single 00106 { 00107 bool schedule_tasks(etl::ivector<etl::task*> & task_list) 00108 { 00109 bool idle = true; 00110 00111 for (size_t index = 0; index < task_list.size(); ++index) 00112 { 00113 etl::task& task = *(task_list[index]); 00114 00115 if (task.task_request_work() > 0) 00116 { 00117 task.task_process_work(); 00118 idle = false; 00119 } 00120 } 00121 00122 return idle; 00123 } 00124 }; 00125 00126 //*************************************************************************** 00127 /// Sequencial Multiple. 00128 /// A policy the scheduler can use to decide what to do next. 00129 /// Calls the task to process work until it reports that it has no more. 00130 //*************************************************************************** 00131 struct scheduler_policy_sequencial_multiple 00132 { 00133 bool schedule_tasks(etl::ivector<etl::task*> & task_list) 00134 { 00135 bool idle = true; 00136 00137 for (size_t index = 0; index < task_list.size(); ++index) 00138 { 00139 etl::task& task = *(task_list[index]); 00140 00141 while (task.task_request_work() > 0) 00142 { 00143 task.task_process_work(); 00144 idle = false; 00145 } 00146 } 00147 00148 return idle; 00149 } 00150 }; 00151 00152 //*************************************************************************** 00153 /// Highest Priority. 00154 /// A policy the scheduler can use to decide what to do next. 00155 /// Calls the highest priority task that has work. 00156 //*************************************************************************** 00157 struct scheduler_policy_highest_priority 00158 { 00159 bool schedule_tasks(etl::ivector<etl::task*> & task_list) 00160 { 00161 bool idle = true; 00162 00163 size_t index = 0; 00164 while (index < task_list.size()) 00165 { 00166 etl::task& task = *(task_list[index]); 00167 00168 if (task.task_request_work() > 0) 00169 { 00170 task.task_process_work(); 00171 idle = false; 00172 break; 00173 } 00174 else 00175 { 00176 ++index; 00177 } 00178 } 00179 00180 return idle; 00181 } 00182 }; 00183 00184 //*************************************************************************** 00185 /// Most Work. 00186 /// A policy the scheduler can use to decide what to do next. 00187 /// Calls the task that has the most work. 00188 /// Starts looking from the task with the highest priority. 00189 //*************************************************************************** 00190 struct scheduler_policy_most_work 00191 { 00192 bool schedule_tasks(etl::ivector<etl::task*> & task_list) 00193 { 00194 bool idle = true; 00195 00196 size_t most_index = 0; 00197 uint_least8_t most_work = 0; 00198 00199 for (size_t index = 0; index < task_list.size(); ++index) 00200 { 00201 etl::task& task = *(task_list[index]); 00202 00203 uint_least8_t n_work = task.task_request_work(); 00204 00205 if (n_work > most_work) 00206 { 00207 most_index = index; 00208 most_work = n_work; 00209 idle = false; 00210 } 00211 } 00212 00213 if (!idle) 00214 { 00215 task_list[most_index]->task_process_work(); 00216 } 00217 00218 return idle; 00219 } 00220 }; 00221 00222 //*************************************************************************** 00223 /// Scheduler base. 00224 //*************************************************************************** 00225 class ischeduler 00226 { 00227 public: 00228 00229 //******************************************* 00230 // Virtuals. 00231 //******************************************* 00232 virtual void start() = 0; 00233 00234 virtual ~ischeduler() 00235 { 00236 } 00237 00238 //******************************************* 00239 /// Set the idle callback. 00240 //******************************************* 00241 void set_idle_callback(etl::ifunction<void>& callback) 00242 { 00243 p_idle_callback = &callback; 00244 } 00245 00246 //******************************************* 00247 /// Set the watchdog callback. 00248 //******************************************* 00249 void set_watchdog_callback(etl::ifunction<void>& callback) 00250 { 00251 p_watchdog_callback = &callback; 00252 } 00253 00254 //******************************************* 00255 /// Set the running state for the scheduler. 00256 //******************************************* 00257 void set_scheduler_running(bool scheduler_running_) 00258 { 00259 scheduler_running = scheduler_running_; 00260 } 00261 00262 //******************************************* 00263 /// Get the running state for the scheduler. 00264 //******************************************* 00265 bool scheduler_is_running() const 00266 { 00267 return scheduler_running; 00268 } 00269 00270 //******************************************* 00271 /// Force the scheduler to exit. 00272 //******************************************* 00273 void exit_scheduler() 00274 { 00275 scheduler_exit = true; 00276 } 00277 00278 //******************************************* 00279 /// Add a task. 00280 /// Add to the task list in priority order. 00281 //******************************************* 00282 void add_task(etl::task& task) 00283 { 00284 ETL_ASSERT(!task_list.full(), ETL_ERROR(etl::scheduler_too_many_tasks_exception)) 00285 00286 if (!task_list.full()) 00287 { 00288 typename task_list_t::iterator itask = std::upper_bound(task_list.begin(), 00289 task_list.end(), 00290 task.get_task_priority(), 00291 compare_priority()); 00292 00293 task_list.insert(itask, &task); 00294 } 00295 } 00296 00297 //******************************************* 00298 /// Add a task list. 00299 /// Adds to the tasks to the internal task list in priority order. 00300 /// Input order is ignored. 00301 //******************************************* 00302 template <typename TSize> 00303 void add_task_list(etl::task** p_tasks, TSize size) 00304 { 00305 for (TSize i = 0; i < size; ++i) 00306 { 00307 ETL_ASSERT((p_tasks[i] != std::nullptr), ETL_ERROR(etl::scheduler_null_task_exception)); 00308 add_task(*(p_tasks[i])); 00309 } 00310 } 00311 00312 protected: 00313 00314 //******************************************* 00315 /// Constructor. 00316 //******************************************* 00317 ischeduler(etl::ivector<etl::task*> & task_list_) 00318 : scheduler_running(false), 00319 scheduler_exit(false), 00320 p_idle_callback(std::nullptr), 00321 p_watchdog_callback(std::nullptr), 00322 task_list(task_list_) 00323 { 00324 } 00325 00326 bool scheduler_running; 00327 bool scheduler_exit; 00328 etl::ifunction<void>* p_idle_callback; 00329 etl::ifunction<void>* p_watchdog_callback; 00330 00331 private: 00332 00333 //******************************************* 00334 // Used to order tasks in descending priority. 00335 //******************************************* 00336 struct compare_priority 00337 { 00338 bool operator()(etl::task* ptask, etl::task_priority_t priority) const 00339 { 00340 return ptask->get_task_priority() > priority; 00341 } 00342 00343 bool operator()(etl::task_priority_t priority, etl::task* ptask) const 00344 { 00345 return priority > ptask->get_task_priority(); 00346 } 00347 }; 00348 00349 typedef etl::ivector<etl::task*> task_list_t; 00350 task_list_t& task_list; 00351 }; 00352 00353 //*************************************************************************** 00354 /// Scheduler. 00355 //*************************************************************************** 00356 template <typename TSchedulerPolicy, size_t MAX_TASKS_> 00357 class scheduler : public etl::ischeduler, protected TSchedulerPolicy 00358 { 00359 public: 00360 00361 enum 00362 { 00363 MAX_TASKS = MAX_TASKS_, 00364 }; 00365 00366 scheduler() 00367 : ischeduler(task_list) 00368 { 00369 } 00370 00371 //******************************************* 00372 /// Start the scheduler. SEQUENCIAL_SINGLE 00373 /// Only calls the task to process work once, if it has work to do. 00374 //******************************************* 00375 void start() 00376 { 00377 ETL_ASSERT(task_list.size() > 0, ETL_ERROR(etl::scheduler_no_tasks_exception)); 00378 00379 const size_t task_list_size = task_list.size(); 00380 00381 scheduler_running = true; 00382 00383 while (!scheduler_exit) 00384 { 00385 if (scheduler_running) 00386 { 00387 bool idle = TSchedulerPolicy::schedule_tasks(task_list); 00388 00389 if (p_watchdog_callback) 00390 { 00391 (*p_watchdog_callback)(); 00392 } 00393 00394 if (idle && p_idle_callback) 00395 { 00396 (*p_idle_callback)(); 00397 } 00398 } 00399 } 00400 } 00401 00402 private: 00403 00404 typedef etl::vector<etl::task*, MAX_TASKS> task_list_t; 00405 task_list_t task_list; 00406 }; 00407 } 00408 00409 #undef ETL_FILE 00410 00411 #endif 00412
Generated on Tue Jul 12 2022 14:05:44 by
