[1f0d013] | 1 | /** |
---|
| 2 | * @file |
---|
| 3 | * |
---|
[11e7893] | 4 | * @ingroup RTEMSScoreScheduler |
---|
| 5 | * |
---|
[1f0d013] | 6 | * @brief Inlined Routines Associated with the Manipulation of the Scheduler |
---|
[0faa9dad] | 7 | * |
---|
[1f0d013] | 8 | * This inline file contains all of the inlined routines associated with |
---|
| 9 | * the manipulation of the scheduler. |
---|
[0faa9dad] | 10 | */ |
---|
| 11 | |
---|
| 12 | /* |
---|
| 13 | * Copyright (C) 2010 Gedare Bloom. |
---|
[010192d] | 14 | * Copyright (C) 2011 On-Line Applications Research Corporation (OAR). |
---|
[088acbb0] | 15 | * Copyright (c) 2014, 2017 embedded brains GmbH |
---|
[0faa9dad] | 16 | * |
---|
| 17 | * The license and distribution terms for this file may be |
---|
| 18 | * found in the file LICENSE in this distribution or at |
---|
[c499856] | 19 | * http://www.rtems.org/license/LICENSE. |
---|
[0faa9dad] | 20 | */ |
---|
| 21 | |
---|
[c6e21ee1] | 22 | #ifndef _RTEMS_SCORE_SCHEDULERIMPL_H |
---|
| 23 | #define _RTEMS_SCORE_SCHEDULERIMPL_H |
---|
| 24 | |
---|
| 25 | #include <rtems/score/scheduler.h> |
---|
[a7a8ec03] | 26 | #include <rtems/score/assert.h> |
---|
[300f6a48] | 27 | #include <rtems/score/priorityimpl.h> |
---|
[c5831a3f] | 28 | #include <rtems/score/smpimpl.h> |
---|
[c0bd006] | 29 | #include <rtems/score/status.h> |
---|
[e5ca54c9] | 30 | #include <rtems/score/threadimpl.h> |
---|
[0faa9dad] | 31 | |
---|
[c6e21ee1] | 32 | #ifdef __cplusplus |
---|
| 33 | extern "C" { |
---|
| 34 | #endif |
---|
[0faa9dad] | 35 | |
---|
| 36 | /** |
---|
[4c20da4b] | 37 | * @addtogroup RTEMSScoreScheduler |
---|
[11e7893] | 38 | * |
---|
| 39 | * @{ |
---|
[0faa9dad] | 40 | */ |
---|
| 41 | |
---|
[c6e21ee1] | 42 | /** |
---|
[11e7893] | 43 | * @brief Initializes the scheduler to the policy chosen by the user. |
---|
[c6e21ee1] | 44 | * |
---|
[11e7893] | 45 | * This routine initializes the scheduler to the policy chosen by the user |
---|
| 46 | * through confdefs, or to the priority scheduler with ready chains by |
---|
| 47 | * default. |
---|
[c6e21ee1] | 48 | */ |
---|
| 49 | void _Scheduler_Handler_initialization( void ); |
---|
| 50 | |
---|
[11e7893] | 51 | /** |
---|
| 52 | * @brief Gets the context of the scheduler. |
---|
| 53 | * |
---|
| 54 | * @param scheduler The scheduler to get the context of. |
---|
| 55 | * |
---|
| 56 | * @return The context of @a scheduler. |
---|
| 57 | */ |
---|
[5c3d250] | 58 | RTEMS_INLINE_ROUTINE Scheduler_Context *_Scheduler_Get_context( |
---|
| 59 | const Scheduler_Control *scheduler |
---|
| 60 | ) |
---|
| 61 | { |
---|
| 62 | return scheduler->context; |
---|
| 63 | } |
---|
| 64 | |
---|
[11e7893] | 65 | /** |
---|
| 66 | * @brief Gets the scheduler for the cpu. |
---|
| 67 | * |
---|
| 68 | * @param cpu The cpu control to get the scheduler of. |
---|
| 69 | * |
---|
| 70 | * @return The scheduler for the cpu. |
---|
| 71 | */ |
---|
[1c46b80] | 72 | RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU( |
---|
| 73 | const Per_CPU_Control *cpu |
---|
[c5831a3f] | 74 | ) |
---|
| 75 | { |
---|
| 76 | #if defined(RTEMS_SMP) |
---|
[1c46b80] | 77 | return cpu->Scheduler.control; |
---|
[c5831a3f] | 78 | #else |
---|
[1c46b80] | 79 | (void) cpu; |
---|
[c5831a3f] | 80 | return &_Scheduler_Table[ 0 ]; |
---|
| 81 | #endif |
---|
| 82 | } |
---|
| 83 | |
---|
[bd12dda] | 84 | /** |
---|
| 85 | * @brief Acquires the scheduler instance inside a critical section (interrupts |
---|
| 86 | * disabled). |
---|
| 87 | * |
---|
[11e7893] | 88 | * @param scheduler The scheduler instance. |
---|
| 89 | * @param lock_context The lock context to use for |
---|
[bd12dda] | 90 | * _Scheduler_Release_critical(). |
---|
| 91 | */ |
---|
| 92 | RTEMS_INLINE_ROUTINE void _Scheduler_Acquire_critical( |
---|
| 93 | const Scheduler_Control *scheduler, |
---|
| 94 | ISR_lock_Context *lock_context |
---|
| 95 | ) |
---|
| 96 | { |
---|
[913864c] | 97 | #if defined(RTEMS_SMP) |
---|
| 98 | Scheduler_Context *context; |
---|
| 99 | |
---|
| 100 | context = _Scheduler_Get_context( scheduler ); |
---|
| 101 | _ISR_lock_Acquire( &context->Lock, lock_context ); |
---|
| 102 | #else |
---|
[bd12dda] | 103 | (void) scheduler; |
---|
[913864c] | 104 | (void) lock_context; |
---|
| 105 | #endif |
---|
[bd12dda] | 106 | } |
---|
| 107 | |
---|
| 108 | /** |
---|
| 109 | * @brief Releases the scheduler instance inside a critical section (interrupts |
---|
| 110 | * disabled). |
---|
| 111 | * |
---|
[11e7893] | 112 | * @param scheduler The scheduler instance. |
---|
| 113 | * @param lock_context The lock context used for |
---|
[bd12dda] | 114 | * _Scheduler_Acquire_critical(). |
---|
| 115 | */ |
---|
| 116 | RTEMS_INLINE_ROUTINE void _Scheduler_Release_critical( |
---|
| 117 | const Scheduler_Control *scheduler, |
---|
| 118 | ISR_lock_Context *lock_context |
---|
| 119 | ) |
---|
| 120 | { |
---|
[913864c] | 121 | #if defined(RTEMS_SMP) |
---|
| 122 | Scheduler_Context *context; |
---|
| 123 | |
---|
| 124 | context = _Scheduler_Get_context( scheduler ); |
---|
| 125 | _ISR_lock_Release( &context->Lock, lock_context ); |
---|
| 126 | #else |
---|
[bd12dda] | 127 | (void) scheduler; |
---|
[913864c] | 128 | (void) lock_context; |
---|
| 129 | #endif |
---|
[bd12dda] | 130 | } |
---|
| 131 | |
---|
[ca1e546e] | 132 | #if defined(RTEMS_SMP) |
---|
[088acbb0] | 133 | void _Scheduler_Request_ask_for_help( Thread_Control *the_thread ); |
---|
| 134 | |
---|
[ca1e546e] | 135 | /** |
---|
[088acbb0] | 136 | * @brief Registers an ask for help request if necessary. |
---|
[ca1e546e] | 137 | * |
---|
| 138 | * The actual ask for help operation is carried out during |
---|
| 139 | * _Thread_Do_dispatch() on a processor related to the thread. This yields a |
---|
| 140 | * better separation of scheduler instances. A thread of one scheduler |
---|
| 141 | * instance should not be forced to carry out too much work for threads on |
---|
| 142 | * other scheduler instances. |
---|
| 143 | * |
---|
[11e7893] | 144 | * @param the_thread The thread in need for help. |
---|
[ca1e546e] | 145 | */ |
---|
| 146 | RTEMS_INLINE_ROUTINE void _Scheduler_Ask_for_help( Thread_Control *the_thread ) |
---|
| 147 | { |
---|
| 148 | _Assert( _Thread_State_is_owner( the_thread ) ); |
---|
| 149 | |
---|
| 150 | if ( the_thread->Scheduler.helping_nodes > 0 ) { |
---|
[088acbb0] | 151 | _Scheduler_Request_ask_for_help( the_thread ); |
---|
[ca1e546e] | 152 | } |
---|
| 153 | } |
---|
| 154 | #endif |
---|
| 155 | |
---|
[0faa9dad] | 156 | /** |
---|
[1f0d013] | 157 | * The preferred method to add a new scheduler is to define the jump table |
---|
| 158 | * entries and add a case to the _Scheduler_Initialize routine. |
---|
[0faa9dad] | 159 | * |
---|
[1f0d013] | 160 | * Generic scheduling implementations that rely on the ready queue only can |
---|
[0faa9dad] | 161 | * be found in the _Scheduler_queue_XXX functions. |
---|
| 162 | */ |
---|
| 163 | |
---|
[1f0d013] | 164 | /* |
---|
| 165 | * Passing the Scheduler_Control* to these functions allows for multiple |
---|
| 166 | * scheduler's to exist simultaneously, which could be useful on an SMP |
---|
| 167 | * system. Then remote Schedulers may be accessible. How to protect such |
---|
[0faa9dad] | 168 | * accesses remains an open problem. |
---|
| 169 | */ |
---|
| 170 | |
---|
[1f0d013] | 171 | /** |
---|
[92635cb] | 172 | * @brief General scheduling decision. |
---|
[0faa9dad] | 173 | * |
---|
[1f0d013] | 174 | * This kernel routine implements the scheduling decision logic for |
---|
| 175 | * the scheduler. It does NOT dispatch. |
---|
[e5ca54c9] | 176 | * |
---|
[11e7893] | 177 | * @param the_thread The thread which state changed previously. |
---|
[0faa9dad] | 178 | */ |
---|
[92635cb] | 179 | RTEMS_INLINE_ROUTINE void _Scheduler_Schedule( Thread_Control *the_thread ) |
---|
[0faa9dad] | 180 | { |
---|
[bd12dda] | 181 | const Scheduler_Control *scheduler; |
---|
| 182 | ISR_lock_Context lock_context; |
---|
| 183 | |
---|
[2dd098a] | 184 | scheduler = _Thread_Scheduler_get_home( the_thread ); |
---|
[bd12dda] | 185 | _Scheduler_Acquire_critical( scheduler, &lock_context ); |
---|
[92635cb] | 186 | |
---|
[24934e36] | 187 | ( *scheduler->Operations.schedule )( scheduler, the_thread ); |
---|
[bd12dda] | 188 | |
---|
| 189 | _Scheduler_Release_critical( scheduler, &lock_context ); |
---|
[0faa9dad] | 190 | } |
---|
| 191 | |
---|
[1f0d013] | 192 | /** |
---|
[6eba7c85] | 193 | * @brief Scheduler yield with a particular thread. |
---|
[0faa9dad] | 194 | * |
---|
[6eba7c85] | 195 | * This routine is invoked when a thread wishes to voluntarily transfer control |
---|
| 196 | * of the processor to another thread. |
---|
| 197 | * |
---|
[11e7893] | 198 | * @param the_thread The yielding thread. |
---|
[0faa9dad] | 199 | */ |
---|
[92635cb] | 200 | RTEMS_INLINE_ROUTINE void _Scheduler_Yield( Thread_Control *the_thread ) |
---|
[0faa9dad] | 201 | { |
---|
[bd12dda] | 202 | const Scheduler_Control *scheduler; |
---|
| 203 | ISR_lock_Context lock_context; |
---|
[6a82f1ae] | 204 | |
---|
[2dd098a] | 205 | scheduler = _Thread_Scheduler_get_home( the_thread ); |
---|
[ca1e546e] | 206 | _Scheduler_Acquire_critical( scheduler, &lock_context ); |
---|
[2df4abc] | 207 | ( *scheduler->Operations.yield )( |
---|
| 208 | scheduler, |
---|
| 209 | the_thread, |
---|
| 210 | _Thread_Scheduler_get_home_node( the_thread ) |
---|
| 211 | ); |
---|
[ca1e546e] | 212 | _Scheduler_Release_critical( scheduler, &lock_context ); |
---|
[0faa9dad] | 213 | } |
---|
| 214 | |
---|
[1f0d013] | 215 | /** |
---|
[92635cb] | 216 | * @brief Blocks a thread with respect to the scheduler. |
---|
[0faa9dad] | 217 | * |
---|
[1f0d013] | 218 | * This routine removes @a the_thread from the scheduling decision for |
---|
| 219 | * the scheduler. The primary task is to remove the thread from the |
---|
[11e7893] | 220 | * ready queue. It performs any necessary scheduling operations |
---|
[1f0d013] | 221 | * including the selection of a new heir thread. |
---|
[92635cb] | 222 | * |
---|
[11e7893] | 223 | * @param the_thread The thread. |
---|
[0faa9dad] | 224 | */ |
---|
[92635cb] | 225 | RTEMS_INLINE_ROUTINE void _Scheduler_Block( Thread_Control *the_thread ) |
---|
[0faa9dad] | 226 | { |
---|
[351c14d] | 227 | #if defined(RTEMS_SMP) |
---|
| 228 | Chain_Node *node; |
---|
| 229 | const Chain_Node *tail; |
---|
| 230 | Scheduler_Node *scheduler_node; |
---|
[bd12dda] | 231 | const Scheduler_Control *scheduler; |
---|
| 232 | ISR_lock_Context lock_context; |
---|
| 233 | |
---|
[351c14d] | 234 | node = _Chain_First( &the_thread->Scheduler.Scheduler_nodes ); |
---|
| 235 | tail = _Chain_Immutable_tail( &the_thread->Scheduler.Scheduler_nodes ); |
---|
| 236 | |
---|
| 237 | scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node ); |
---|
| 238 | scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); |
---|
| 239 | |
---|
[bd12dda] | 240 | _Scheduler_Acquire_critical( scheduler, &lock_context ); |
---|
[351c14d] | 241 | ( *scheduler->Operations.block )( |
---|
| 242 | scheduler, |
---|
| 243 | the_thread, |
---|
| 244 | scheduler_node |
---|
| 245 | ); |
---|
| 246 | _Scheduler_Release_critical( scheduler, &lock_context ); |
---|
| 247 | |
---|
| 248 | node = _Chain_Next( node ); |
---|
| 249 | |
---|
| 250 | while ( node != tail ) { |
---|
| 251 | scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node ); |
---|
| 252 | scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); |
---|
[92635cb] | 253 | |
---|
[351c14d] | 254 | _Scheduler_Acquire_critical( scheduler, &lock_context ); |
---|
| 255 | ( *scheduler->Operations.withdraw_node )( |
---|
| 256 | scheduler, |
---|
| 257 | the_thread, |
---|
| 258 | scheduler_node, |
---|
| 259 | THREAD_SCHEDULER_BLOCKED |
---|
| 260 | ); |
---|
| 261 | _Scheduler_Release_critical( scheduler, &lock_context ); |
---|
| 262 | |
---|
| 263 | node = _Chain_Next( node ); |
---|
| 264 | } |
---|
| 265 | #else |
---|
| 266 | const Scheduler_Control *scheduler; |
---|
| 267 | |
---|
[2dd098a] | 268 | scheduler = _Thread_Scheduler_get_home( the_thread ); |
---|
[e382a1b] | 269 | ( *scheduler->Operations.block )( |
---|
| 270 | scheduler, |
---|
| 271 | the_thread, |
---|
| 272 | _Thread_Scheduler_get_home_node( the_thread ) |
---|
| 273 | ); |
---|
[351c14d] | 274 | #endif |
---|
[0faa9dad] | 275 | } |
---|
| 276 | |
---|
[1f0d013] | 277 | /** |
---|
[92635cb] | 278 | * @brief Unblocks a thread with respect to the scheduler. |
---|
[0faa9dad] | 279 | * |
---|
[9bfad8c] | 280 | * This operation must fetch the latest thread priority value for this |
---|
| 281 | * scheduler instance and update its internal state if necessary. |
---|
[92635cb] | 282 | * |
---|
[11e7893] | 283 | * @param the_thread The thread. |
---|
[9bfad8c] | 284 | * |
---|
| 285 | * @see _Scheduler_Node_get_priority(). |
---|
[0faa9dad] | 286 | */ |
---|
[92635cb] | 287 | RTEMS_INLINE_ROUTINE void _Scheduler_Unblock( Thread_Control *the_thread ) |
---|
[0faa9dad] | 288 | { |
---|
[d8bc0730] | 289 | Scheduler_Node *scheduler_node; |
---|
[bd12dda] | 290 | const Scheduler_Control *scheduler; |
---|
| 291 | ISR_lock_Context lock_context; |
---|
[351c14d] | 292 | |
---|
[d8bc0730] | 293 | #if defined(RTEMS_SMP) |
---|
| 294 | scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( |
---|
| 295 | _Chain_First( &the_thread->Scheduler.Scheduler_nodes ) |
---|
| 296 | ); |
---|
| 297 | scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); |
---|
| 298 | #else |
---|
| 299 | scheduler_node = _Thread_Scheduler_get_home_node( the_thread ); |
---|
[2dd098a] | 300 | scheduler = _Thread_Scheduler_get_home( the_thread ); |
---|
[d8bc0730] | 301 | #endif |
---|
| 302 | |
---|
[ca1e546e] | 303 | _Scheduler_Acquire_critical( scheduler, &lock_context ); |
---|
[d8bc0730] | 304 | ( *scheduler->Operations.unblock )( scheduler, the_thread, scheduler_node ); |
---|
[ca1e546e] | 305 | _Scheduler_Release_critical( scheduler, &lock_context ); |
---|
[0faa9dad] | 306 | } |
---|
| 307 | |
---|
[f39f667a] | 308 | /** |
---|
| 309 | * @brief Propagates a priority change of a thread to the scheduler. |
---|
| 310 | * |
---|
[9bfad8c] | 311 | * On uni-processor configurations, this operation must evaluate the thread |
---|
| 312 | * state. In case the thread is not ready, then the priority update should be |
---|
| 313 | * deferred to the next scheduler unblock operation. |
---|
[f39f667a] | 314 | * |
---|
[b8a5abf] | 315 | * The operation must update the heir and thread dispatch necessary variables |
---|
| 316 | * in case the set of scheduled threads changes. |
---|
| 317 | * |
---|
[11e7893] | 318 | * @param the_thread The thread changing its priority. |
---|
[9bfad8c] | 319 | * |
---|
| 320 | * @see _Scheduler_Node_get_priority(). |
---|
[f39f667a] | 321 | */ |
---|
[9bfad8c] | 322 | RTEMS_INLINE_ROUTINE void _Scheduler_Update_priority( Thread_Control *the_thread ) |
---|
[f39f667a] | 323 | { |
---|
[8568341] | 324 | #if defined(RTEMS_SMP) |
---|
[351c14d] | 325 | Chain_Node *node; |
---|
| 326 | const Chain_Node *tail; |
---|
[92635cb] | 327 | |
---|
[2403473] | 328 | _Thread_Scheduler_process_requests( the_thread ); |
---|
| 329 | |
---|
[351c14d] | 330 | node = _Chain_First( &the_thread->Scheduler.Scheduler_nodes ); |
---|
| 331 | tail = _Chain_Immutable_tail( &the_thread->Scheduler.Scheduler_nodes ); |
---|
[bd12dda] | 332 | |
---|
[351c14d] | 333 | do { |
---|
| 334 | Scheduler_Node *scheduler_node; |
---|
| 335 | const Scheduler_Control *scheduler; |
---|
| 336 | ISR_lock_Context lock_context; |
---|
| 337 | |
---|
| 338 | scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node ); |
---|
| 339 | scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); |
---|
| 340 | |
---|
| 341 | _Scheduler_Acquire_critical( scheduler, &lock_context ); |
---|
[97f7dac] | 342 | ( *scheduler->Operations.update_priority )( |
---|
[351c14d] | 343 | scheduler, |
---|
| 344 | the_thread, |
---|
| 345 | scheduler_node |
---|
| 346 | ); |
---|
| 347 | _Scheduler_Release_critical( scheduler, &lock_context ); |
---|
| 348 | |
---|
| 349 | node = _Chain_Next( node ); |
---|
| 350 | } while ( node != tail ); |
---|
| 351 | #else |
---|
| 352 | const Scheduler_Control *scheduler; |
---|
| 353 | |
---|
[2dd098a] | 354 | scheduler = _Thread_Scheduler_get_home( the_thread ); |
---|
[351c14d] | 355 | ( *scheduler->Operations.update_priority )( |
---|
| 356 | scheduler, |
---|
[501043a] | 357 | the_thread, |
---|
| 358 | _Thread_Scheduler_get_home_node( the_thread ) |
---|
| 359 | ); |
---|
[8568341] | 360 | #endif |
---|
[f39f667a] | 361 | } |
---|
| 362 | |
---|
[3a27248] | 363 | #if defined(RTEMS_SMP) |
---|
| 364 | /** |
---|
| 365 | * @brief Changes the sticky level of the home scheduler node and propagates a |
---|
| 366 | * priority change of a thread to the scheduler. |
---|
| 367 | * |
---|
[11e7893] | 368 | * @param the_thread The thread changing its priority or sticky level. |
---|
[3a27248] | 369 | * |
---|
| 370 | * @see _Scheduler_Update_priority(). |
---|
| 371 | */ |
---|
| 372 | RTEMS_INLINE_ROUTINE void _Scheduler_Priority_and_sticky_update( |
---|
| 373 | Thread_Control *the_thread, |
---|
| 374 | int sticky_level_change |
---|
| 375 | ) |
---|
| 376 | { |
---|
| 377 | Chain_Node *node; |
---|
| 378 | const Chain_Node *tail; |
---|
| 379 | Scheduler_Node *scheduler_node; |
---|
| 380 | const Scheduler_Control *scheduler; |
---|
| 381 | ISR_lock_Context lock_context; |
---|
| 382 | |
---|
| 383 | _Thread_Scheduler_process_requests( the_thread ); |
---|
| 384 | |
---|
| 385 | node = _Chain_First( &the_thread->Scheduler.Scheduler_nodes ); |
---|
| 386 | scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node ); |
---|
| 387 | scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); |
---|
| 388 | |
---|
| 389 | _Scheduler_Acquire_critical( scheduler, &lock_context ); |
---|
| 390 | |
---|
[6771359f] | 391 | scheduler_node->sticky_level += sticky_level_change; |
---|
| 392 | _Assert( scheduler_node->sticky_level >= 0 ); |
---|
| 393 | |
---|
[3a27248] | 394 | ( *scheduler->Operations.update_priority )( |
---|
| 395 | scheduler, |
---|
| 396 | the_thread, |
---|
| 397 | scheduler_node |
---|
| 398 | ); |
---|
| 399 | |
---|
| 400 | _Scheduler_Release_critical( scheduler, &lock_context ); |
---|
| 401 | |
---|
| 402 | tail = _Chain_Immutable_tail( &the_thread->Scheduler.Scheduler_nodes ); |
---|
| 403 | node = _Chain_Next( node ); |
---|
| 404 | |
---|
| 405 | while ( node != tail ) { |
---|
| 406 | scheduler_node = SCHEDULER_NODE_OF_THREAD_SCHEDULER_NODE( node ); |
---|
| 407 | scheduler = _Scheduler_Node_get_scheduler( scheduler_node ); |
---|
| 408 | |
---|
| 409 | _Scheduler_Acquire_critical( scheduler, &lock_context ); |
---|
| 410 | ( *scheduler->Operations.update_priority )( |
---|
| 411 | scheduler, |
---|
| 412 | the_thread, |
---|
| 413 | scheduler_node |
---|
| 414 | ); |
---|
| 415 | _Scheduler_Release_critical( scheduler, &lock_context ); |
---|
| 416 | |
---|
| 417 | node = _Chain_Next( node ); |
---|
| 418 | } |
---|
| 419 | } |
---|
| 420 | #endif |
---|
| 421 | |
---|
[77ff5599] | 422 | /** |
---|
| 423 | * @brief Maps a thread priority from the user domain to the scheduler domain. |
---|
| 424 | * |
---|
| 425 | * Let M be the maximum scheduler priority. The mapping must be bijective in |
---|
| 426 | * the closed interval [0, M], e.g. _Scheduler_Unmap_priority( scheduler, |
---|
| 427 | * _Scheduler_Map_priority( scheduler, p ) ) == p for all p in [0, M]. For |
---|
| 428 | * other values the mapping is undefined. |
---|
| 429 | * |
---|
[11e7893] | 430 | * @param scheduler The scheduler instance. |
---|
| 431 | * @param priority The user domain thread priority. |
---|
[77ff5599] | 432 | * |
---|
| 433 | * @return The corresponding thread priority of the scheduler domain is returned. |
---|
| 434 | */ |
---|
| 435 | RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Map_priority( |
---|
| 436 | const Scheduler_Control *scheduler, |
---|
| 437 | Priority_Control priority |
---|
| 438 | ) |
---|
| 439 | { |
---|
| 440 | return ( *scheduler->Operations.map_priority )( scheduler, priority ); |
---|
| 441 | } |
---|
| 442 | |
---|
| 443 | /** |
---|
| 444 | * @brief Unmaps a thread priority from the scheduler domain to the user domain. |
---|
| 445 | * |
---|
[11e7893] | 446 | * @param scheduler The scheduler instance. |
---|
| 447 | * @param priority The scheduler domain thread priority. |
---|
[77ff5599] | 448 | * |
---|
| 449 | * @return The corresponding thread priority of the user domain is returned. |
---|
| 450 | */ |
---|
| 451 | RTEMS_INLINE_ROUTINE Priority_Control _Scheduler_Unmap_priority( |
---|
| 452 | const Scheduler_Control *scheduler, |
---|
| 453 | Priority_Control priority |
---|
| 454 | ) |
---|
| 455 | { |
---|
| 456 | return ( *scheduler->Operations.unmap_priority )( scheduler, priority ); |
---|
| 457 | } |
---|
| 458 | |
---|
[1f0d013] | 459 | /** |
---|
[8e467384] | 460 | * @brief Initializes a scheduler node. |
---|
[0faa9dad] | 461 | * |
---|
[8e467384] | 462 | * The scheduler node contains arbitrary data on function entry. The caller |
---|
| 463 | * must ensure that _Scheduler_Node_destroy() will be called after a |
---|
| 464 | * _Scheduler_Node_initialize() before the memory of the scheduler node is |
---|
| 465 | * destroyed. |
---|
| 466 | * |
---|
[11e7893] | 467 | * @param scheduler The scheduler instance. |
---|
| 468 | * @param[out] node The scheduler node to initialize. |
---|
| 469 | * @param the_thread The thread of the scheduler node to initialize. |
---|
| 470 | * @param priority The thread priority. |
---|
[0faa9dad] | 471 | */ |
---|
[8e467384] | 472 | RTEMS_INLINE_ROUTINE void _Scheduler_Node_initialize( |
---|
[e1598a6] | 473 | const Scheduler_Control *scheduler, |
---|
[df2177ab] | 474 | Scheduler_Node *node, |
---|
[9bfad8c] | 475 | Thread_Control *the_thread, |
---|
| 476 | Priority_Control priority |
---|
[0faa9dad] | 477 | ) |
---|
| 478 | { |
---|
[9bfad8c] | 479 | ( *scheduler->Operations.node_initialize )( |
---|
| 480 | scheduler, |
---|
[df2177ab] | 481 | node, |
---|
[9bfad8c] | 482 | the_thread, |
---|
| 483 | priority |
---|
| 484 | ); |
---|
[0faa9dad] | 485 | } |
---|
| 486 | |
---|
[1f0d013] | 487 | /** |
---|
[8e467384] | 488 | * @brief Destroys a scheduler node. |
---|
[0faa9dad] | 489 | * |
---|
[8e467384] | 490 | * The caller must ensure that _Scheduler_Node_destroy() will be called only |
---|
| 491 | * after a corresponding _Scheduler_Node_initialize(). |
---|
| 492 | * |
---|
[11e7893] | 493 | * @param scheduler The scheduler instance. |
---|
| 494 | * @param[out] node The scheduler node to destroy. |
---|
[0faa9dad] | 495 | */ |
---|
[8e467384] | 496 | RTEMS_INLINE_ROUTINE void _Scheduler_Node_destroy( |
---|
[e1598a6] | 497 | const Scheduler_Control *scheduler, |
---|
[df2177ab] | 498 | Scheduler_Node *node |
---|
[0faa9dad] | 499 | ) |
---|
| 500 | { |
---|
[df2177ab] | 501 | ( *scheduler->Operations.node_destroy )( scheduler, node ); |
---|
[0faa9dad] | 502 | } |
---|
| 503 | |
---|
[ac9d2ecc] | 504 | /** |
---|
[92635cb] | 505 | * @brief Releases a job of a thread with respect to the scheduler. |
---|
[ac9d2ecc] | 506 | * |
---|
[11e7893] | 507 | * @param the_thread The thread. |
---|
| 508 | * @param priority_node The priority node of the job. |
---|
| 509 | * @param deadline The deadline in watchdog ticks since boot. |
---|
| 510 | * @param queue_context The thread queue context to provide the set of |
---|
[300f6a48] | 511 | * threads for _Thread_Priority_update(). |
---|
[ac9d2ecc] | 512 | */ |
---|
[300f6a48] | 513 | RTEMS_INLINE_ROUTINE void _Scheduler_Release_job( |
---|
| 514 | Thread_Control *the_thread, |
---|
| 515 | Priority_Node *priority_node, |
---|
| 516 | uint64_t deadline, |
---|
| 517 | Thread_queue_Context *queue_context |
---|
[ac9d2ecc] | 518 | ) |
---|
| 519 | { |
---|
[2dd098a] | 520 | const Scheduler_Control *scheduler = _Thread_Scheduler_get_home( the_thread ); |
---|
[92635cb] | 521 | |
---|
[300f6a48] | 522 | _Thread_queue_Context_clear_priority_updates( queue_context ); |
---|
| 523 | ( *scheduler->Operations.release_job )( |
---|
[ee0e4135] | 524 | scheduler, |
---|
| 525 | the_thread, |
---|
[300f6a48] | 526 | priority_node, |
---|
| 527 | deadline, |
---|
| 528 | queue_context |
---|
[ee0e4135] | 529 | ); |
---|
[ac9d2ecc] | 530 | } |
---|
| 531 | |
---|
[21bdca4] | 532 | /** |
---|
| 533 | * @brief Cancels a job of a thread with respect to the scheduler. |
---|
| 534 | * |
---|
[11e7893] | 535 | * @param the_thread The thread. |
---|
| 536 | * @param priority_node The priority node of the job. |
---|
| 537 | * @param queue_context The thread queue context to provide the set of |
---|
[300f6a48] | 538 | * threads for _Thread_Priority_update(). |
---|
[21bdca4] | 539 | */ |
---|
[300f6a48] | 540 | RTEMS_INLINE_ROUTINE void _Scheduler_Cancel_job( |
---|
| 541 | Thread_Control *the_thread, |
---|
| 542 | Priority_Node *priority_node, |
---|
| 543 | Thread_queue_Context *queue_context |
---|
[21bdca4] | 544 | ) |
---|
| 545 | { |
---|
[2dd098a] | 546 | const Scheduler_Control *scheduler = _Thread_Scheduler_get_home( the_thread ); |
---|
[21bdca4] | 547 | |
---|
[300f6a48] | 548 | _Thread_queue_Context_clear_priority_updates( queue_context ); |
---|
| 549 | ( *scheduler->Operations.cancel_job )( |
---|
| 550 | scheduler, |
---|
| 551 | the_thread, |
---|
| 552 | priority_node, |
---|
| 553 | queue_context |
---|
| 554 | ); |
---|
[21bdca4] | 555 | } |
---|
| 556 | |
---|
[1f0d013] | 557 | /** |
---|
| 558 | * @brief Scheduler method invoked at each clock tick. |
---|
[3203e09] | 559 | * |
---|
| 560 | * This method is invoked at each clock tick to allow the scheduler |
---|
[1f0d013] | 561 | * implementation to perform any activities required. For the |
---|
[3203e09] | 562 | * scheduler which support standard RTEMS features, this includes |
---|
| 563 | * time-slicing management. |
---|
[11e7893] | 564 | * |
---|
| 565 | * @param cpu The cpu control for the operation. |
---|
[3203e09] | 566 | */ |
---|
[03b900d] | 567 | RTEMS_INLINE_ROUTINE void _Scheduler_Tick( const Per_CPU_Control *cpu ) |
---|
[3203e09] | 568 | { |
---|
[03b900d] | 569 | const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu ); |
---|
| 570 | Thread_Control *executing = cpu->executing; |
---|
[c5831a3f] | 571 | |
---|
[03b900d] | 572 | if ( scheduler != NULL && executing != NULL ) { |
---|
| 573 | ( *scheduler->Operations.tick )( scheduler, executing ); |
---|
[c5831a3f] | 574 | } |
---|
[3203e09] | 575 | } |
---|
| 576 | |
---|
[1ccb64e1] | 577 | /** |
---|
| 578 | * @brief Starts the idle thread for a particular processor. |
---|
| 579 | * |
---|
[11e7893] | 580 | * @param scheduler The scheduler instance. |
---|
[24934e36] | 581 | * @param[in,out] the_thread The idle thread for the processor. |
---|
[a7e4de2] | 582 | * @param[in,out] cpu The processor for the idle thread. |
---|
[1ccb64e1] | 583 | * |
---|
| 584 | * @see _Thread_Create_idle(). |
---|
| 585 | */ |
---|
| 586 | RTEMS_INLINE_ROUTINE void _Scheduler_Start_idle( |
---|
[e1598a6] | 587 | const Scheduler_Control *scheduler, |
---|
| 588 | Thread_Control *the_thread, |
---|
| 589 | Per_CPU_Control *cpu |
---|
[1ccb64e1] | 590 | ) |
---|
| 591 | { |
---|
[24934e36] | 592 | ( *scheduler->Operations.start_idle )( scheduler, the_thread, cpu ); |
---|
[1ccb64e1] | 593 | } |
---|
| 594 | |
---|
[11e7893] | 595 | /** |
---|
| 596 | * @brief Checks if the scheduler of the cpu with the given index is equal |
---|
| 597 | * to the given scheduler. |
---|
| 598 | * |
---|
| 599 | * @param scheduler The scheduler for the comparison. |
---|
| 600 | * @param cpu_index The index of the cpu for the comparison. |
---|
| 601 | * |
---|
| 602 | * @retval true The scheduler of the cpu is the given @a scheduler. |
---|
| 603 | * @retval false The scheduler of the cpu is not the given @a scheduler. |
---|
| 604 | */ |
---|
[c5831a3f] | 605 | RTEMS_INLINE_ROUTINE bool _Scheduler_Has_processor_ownership( |
---|
| 606 | const Scheduler_Control *scheduler, |
---|
[1c46b80] | 607 | uint32_t cpu_index |
---|
[c5831a3f] | 608 | ) |
---|
| 609 | { |
---|
| 610 | #if defined(RTEMS_SMP) |
---|
[1c46b80] | 611 | const Per_CPU_Control *cpu; |
---|
| 612 | const Scheduler_Control *scheduler_of_cpu; |
---|
| 613 | |
---|
| 614 | cpu = _Per_CPU_Get_by_index( cpu_index ); |
---|
| 615 | scheduler_of_cpu = _Scheduler_Get_by_CPU( cpu ); |
---|
[c5831a3f] | 616 | |
---|
[1c46b80] | 617 | return scheduler_of_cpu == scheduler; |
---|
[c5831a3f] | 618 | #else |
---|
| 619 | (void) scheduler; |
---|
| 620 | (void) cpu_index; |
---|
| 621 | |
---|
| 622 | return true; |
---|
| 623 | #endif |
---|
| 624 | } |
---|
| 625 | |
---|
[11e7893] | 626 | /** |
---|
| 627 | * @brief Gets the processors of the scheduler |
---|
| 628 | * |
---|
| 629 | * @param scheduler The scheduler to get the processors of. |
---|
| 630 | * |
---|
| 631 | * @return The processors of the context of the given scheduler. |
---|
| 632 | */ |
---|
[6b1d8c7] | 633 | RTEMS_INLINE_ROUTINE const Processor_mask *_Scheduler_Get_processors( |
---|
| 634 | const Scheduler_Control *scheduler |
---|
[0712d17] | 635 | ) |
---|
| 636 | { |
---|
[c5831a3f] | 637 | #if defined(RTEMS_SMP) |
---|
[6b1d8c7] | 638 | return &_Scheduler_Get_context( scheduler )->Processors; |
---|
[c5831a3f] | 639 | #else |
---|
[6b1d8c7] | 640 | return &_Processor_mask_The_one_and_only; |
---|
[c5831a3f] | 641 | #endif |
---|
[0712d17] | 642 | } |
---|
| 643 | |
---|
[11e7893] | 644 | /** |
---|
| 645 | * @brief Copies the thread's scheduler's affinity to the given cpuset. |
---|
| 646 | * |
---|
| 647 | * @param the_thread The thread to get the affinity of its scheduler. |
---|
| 648 | * @param cpusetsize The size of @a cpuset. |
---|
| 649 | * @param[out] cpuset The cpuset that serves as destination for the copy operation |
---|
| 650 | * |
---|
| 651 | * @retval true The copy operation was lossless. |
---|
| 652 | * @retval false The copy operation was not lossless |
---|
| 653 | */ |
---|
[0712d17] | 654 | bool _Scheduler_Get_affinity( |
---|
[a92c488] | 655 | Thread_Control *the_thread, |
---|
| 656 | size_t cpusetsize, |
---|
| 657 | cpu_set_t *cpuset |
---|
[0712d17] | 658 | ); |
---|
| 659 | |
---|
[11e7893] | 660 | /** |
---|
| 661 | * @brief Checks if the affinity is a subset of the online processors. |
---|
| 662 | * |
---|
| 663 | * @param scheduler This parameter is unused. |
---|
| 664 | * @param the_thread This parameter is unused. |
---|
| 665 | * @param node This parameter is unused. |
---|
| 666 | * @param affinity The processor mask to check. |
---|
| 667 | * |
---|
| 668 | * @retval true @a affinity is a subset of the online processors. |
---|
| 669 | * @retval false @a affinity is not a subset of the online processors. |
---|
| 670 | */ |
---|
[0712d17] | 671 | RTEMS_INLINE_ROUTINE bool _Scheduler_default_Set_affinity_body( |
---|
| 672 | const Scheduler_Control *scheduler, |
---|
| 673 | Thread_Control *the_thread, |
---|
[197a614] | 674 | Scheduler_Node *node, |
---|
[0232b28] | 675 | const Processor_mask *affinity |
---|
[0712d17] | 676 | ) |
---|
| 677 | { |
---|
[16347a6] | 678 | (void) scheduler; |
---|
| 679 | (void) the_thread; |
---|
[197a614] | 680 | (void) node; |
---|
[16347a6] | 681 | return _Processor_mask_Is_subset( affinity, _SMP_Get_online_processors() ); |
---|
[0712d17] | 682 | } |
---|
| 683 | |
---|
[11e7893] | 684 | /** |
---|
| 685 | * @brief Sets the thread's scheduler's affinity. |
---|
| 686 | * |
---|
| 687 | * @param[in, out] the_thread The thread to set the affinity of. |
---|
| 688 | * @param cpusetsize The size of @a cpuset. |
---|
| 689 | * @param cpuset The cpuset to set the affinity. |
---|
| 690 | * |
---|
| 691 | * @retval true The operation succeeded. |
---|
| 692 | * @retval false The operation did not succeed. |
---|
| 693 | */ |
---|
[0712d17] | 694 | bool _Scheduler_Set_affinity( |
---|
[e135271] | 695 | Thread_Control *the_thread, |
---|
| 696 | size_t cpusetsize, |
---|
| 697 | const cpu_set_t *cpuset |
---|
[0712d17] | 698 | ); |
---|
| 699 | |
---|
[11e7893] | 700 | /** |
---|
| 701 | * @brief Blocks the thread. |
---|
| 702 | * |
---|
| 703 | * @param scheduler The scheduler instance. |
---|
| 704 | * @param the_thread The thread to block. |
---|
| 705 | * @param node The corresponding scheduler node. |
---|
| 706 | * @param extract Method to extract the thread. |
---|
| 707 | * @param schedule Method for scheduling threads. |
---|
| 708 | */ |
---|
[e5ca54c9] | 709 | RTEMS_INLINE_ROUTINE void _Scheduler_Generic_block( |
---|
[e1598a6] | 710 | const Scheduler_Control *scheduler, |
---|
| 711 | Thread_Control *the_thread, |
---|
[e382a1b] | 712 | Scheduler_Node *node, |
---|
[e1598a6] | 713 | void ( *extract )( |
---|
| 714 | const Scheduler_Control *, |
---|
[e382a1b] | 715 | Thread_Control *, |
---|
| 716 | Scheduler_Node * |
---|
| 717 | ), |
---|
[e1598a6] | 718 | void ( *schedule )( |
---|
| 719 | const Scheduler_Control *, |
---|
| 720 | Thread_Control *, |
---|
[e382a1b] | 721 | bool |
---|
| 722 | ) |
---|
[e5ca54c9] | 723 | ) |
---|
| 724 | { |
---|
[e382a1b] | 725 | ( *extract )( scheduler, the_thread, node ); |
---|
[e5ca54c9] | 726 | |
---|
| 727 | /* TODO: flash critical section? */ |
---|
| 728 | |
---|
[24934e36] | 729 | if ( _Thread_Is_executing( the_thread ) || _Thread_Is_heir( the_thread ) ) { |
---|
| 730 | ( *schedule )( scheduler, the_thread, true ); |
---|
[e5ca54c9] | 731 | } |
---|
| 732 | } |
---|
| 733 | |
---|
[11e7893] | 734 | /** |
---|
| 735 | * @brief Gets the number of processors of the scheduler. |
---|
| 736 | * |
---|
| 737 | * @param scheduler The scheduler instance to get the number of processors of. |
---|
| 738 | * |
---|
| 739 | * @return The number of processors. |
---|
| 740 | */ |
---|
[e239760] | 741 | RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_processor_count( |
---|
| 742 | const Scheduler_Control *scheduler |
---|
| 743 | ) |
---|
| 744 | { |
---|
| 745 | #if defined(RTEMS_SMP) |
---|
[6b1d8c7] | 746 | const Scheduler_Context *context = _Scheduler_Get_context( scheduler ); |
---|
| 747 | |
---|
| 748 | return _Processor_mask_Count( &context->Processors ); |
---|
[e239760] | 749 | #else |
---|
| 750 | (void) scheduler; |
---|
| 751 | |
---|
| 752 | return 1; |
---|
| 753 | #endif |
---|
| 754 | } |
---|
| 755 | |
---|
[11e7893] | 756 | /** |
---|
| 757 | * @brief Builds an object build id. |
---|
| 758 | * |
---|
| 759 | * @param scheduler_index The index to build the build id out of. |
---|
| 760 | * |
---|
| 761 | * @return The build id. |
---|
| 762 | */ |
---|
[b427a92] | 763 | RTEMS_INLINE_ROUTINE Objects_Id _Scheduler_Build_id( uint32_t scheduler_index ) |
---|
| 764 | { |
---|
| 765 | return _Objects_Build_id( |
---|
| 766 | OBJECTS_FAKE_OBJECTS_API, |
---|
| 767 | OBJECTS_FAKE_OBJECTS_SCHEDULERS, |
---|
| 768 | _Objects_Local_node, |
---|
[1d72f03] | 769 | (uint16_t) ( scheduler_index + 1 ) |
---|
[b427a92] | 770 | ); |
---|
| 771 | } |
---|
| 772 | |
---|
[11e7893] | 773 | /** |
---|
| 774 | * @brief Gets the scheduler index from the given object build id. |
---|
| 775 | * |
---|
| 776 | * @param id The object build id. |
---|
| 777 | * |
---|
| 778 | * @return The scheduler index. |
---|
| 779 | */ |
---|
[c8e83288] | 780 | RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index_by_id( Objects_Id id ) |
---|
| 781 | { |
---|
| 782 | uint32_t minimum_id = _Scheduler_Build_id( 0 ); |
---|
| 783 | |
---|
| 784 | return id - minimum_id; |
---|
| 785 | } |
---|
| 786 | |
---|
[11e7893] | 787 | /** |
---|
| 788 | * @brief Gets the scheduler from the given object build id. |
---|
| 789 | * |
---|
| 790 | * @param id The object build id. |
---|
| 791 | * |
---|
| 792 | * @return The scheduler to the object id. |
---|
| 793 | */ |
---|
[2612a0b] | 794 | RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_id( |
---|
| 795 | Objects_Id id |
---|
[1b67535d] | 796 | ) |
---|
| 797 | { |
---|
[2612a0b] | 798 | uint32_t index; |
---|
[1b67535d] | 799 | |
---|
[2612a0b] | 800 | index = _Scheduler_Get_index_by_id( id ); |
---|
[1b67535d] | 801 | |
---|
[2612a0b] | 802 | if ( index >= _Scheduler_Count ) { |
---|
| 803 | return NULL; |
---|
| 804 | } |
---|
| 805 | |
---|
| 806 | return &_Scheduler_Table[ index ]; |
---|
[1b67535d] | 807 | } |
---|
| 808 | |
---|
[11e7893] | 809 | /** |
---|
| 810 | * @brief Gets the index of the scheduler |
---|
| 811 | * |
---|
| 812 | * @param scheduler The scheduler to get the index of. |
---|
| 813 | * |
---|
| 814 | * @return The index of the given scheduler. |
---|
| 815 | */ |
---|
[27270b0d] | 816 | RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index( |
---|
| 817 | const Scheduler_Control *scheduler |
---|
| 818 | ) |
---|
| 819 | { |
---|
| 820 | return (uint32_t) (scheduler - &_Scheduler_Table[ 0 ]); |
---|
| 821 | } |
---|
| 822 | |
---|
[8f0c7a46] | 823 | #if defined(RTEMS_SMP) |
---|
[5c3d250] | 824 | /** |
---|
| 825 | * @brief Gets an idle thread from the scheduler instance. |
---|
| 826 | * |
---|
[11e7893] | 827 | * @param context The scheduler instance context. |
---|
[5c3d250] | 828 | * |
---|
[11e7893] | 829 | * @return idle An idle thread for use. This function must always return an |
---|
[5c3d250] | 830 | * idle thread. If none is available, then this is a fatal error. |
---|
| 831 | */ |
---|
| 832 | typedef Thread_Control *( *Scheduler_Get_idle_thread )( |
---|
| 833 | Scheduler_Context *context |
---|
| 834 | ); |
---|
| 835 | |
---|
| 836 | /** |
---|
| 837 | * @brief Releases an idle thread to the scheduler instance for reuse. |
---|
| 838 | * |
---|
[11e7893] | 839 | * @param context The scheduler instance context. |
---|
| 840 | * @param idle The idle thread to release. |
---|
[5c3d250] | 841 | */ |
---|
| 842 | typedef void ( *Scheduler_Release_idle_thread )( |
---|
| 843 | Scheduler_Context *context, |
---|
| 844 | Thread_Control *idle |
---|
| 845 | ); |
---|
| 846 | |
---|
[11e7893] | 847 | /** |
---|
| 848 | * @brief Changes the threads state to the given new state. |
---|
| 849 | * |
---|
| 850 | * @param[out] the_thread The thread to change the state of. |
---|
| 851 | * @param new_state The new state for @a the_thread. |
---|
| 852 | */ |
---|
[5c3d250] | 853 | RTEMS_INLINE_ROUTINE void _Scheduler_Thread_change_state( |
---|
| 854 | Thread_Control *the_thread, |
---|
| 855 | Thread_Scheduler_state new_state |
---|
| 856 | ) |
---|
| 857 | { |
---|
[a7a8ec03] | 858 | _Assert( |
---|
| 859 | _ISR_lock_Is_owner( &the_thread->Scheduler.Lock ) |
---|
| 860 | || the_thread->Scheduler.state == THREAD_SCHEDULER_BLOCKED |
---|
| 861 | || !_System_state_Is_up( _System_state_Get() ) |
---|
| 862 | ); |
---|
[5c3d250] | 863 | |
---|
| 864 | the_thread->Scheduler.state = new_state; |
---|
| 865 | } |
---|
| 866 | |
---|
[11e7893] | 867 | /** |
---|
| 868 | * @brief Sets the scheduler node's idle thread. |
---|
| 869 | * |
---|
| 870 | * @param[in, out] node The node to receive an idle thread. |
---|
| 871 | * @param idle The idle thread control for the operation. |
---|
| 872 | */ |
---|
[be0366b] | 873 | RTEMS_INLINE_ROUTINE void _Scheduler_Set_idle_thread( |
---|
| 874 | Scheduler_Node *node, |
---|
| 875 | Thread_Control *idle |
---|
| 876 | ) |
---|
| 877 | { |
---|
| 878 | _Assert( _Scheduler_Node_get_idle( node ) == NULL ); |
---|
| 879 | _Assert( |
---|
| 880 | _Scheduler_Node_get_owner( node ) == _Scheduler_Node_get_user( node ) |
---|
| 881 | ); |
---|
| 882 | |
---|
| 883 | _Scheduler_Node_set_user( node, idle ); |
---|
| 884 | node->idle = idle; |
---|
| 885 | } |
---|
| 886 | |
---|
[5c3d250] | 887 | /** |
---|
[11e7893] | 888 | * @brief Uses an idle thread for this scheduler node. |
---|
[5c3d250] | 889 | * |
---|
[11e7893] | 890 | * A thread whose home scheduler node has a sticky level greater than zero may |
---|
| 891 | * use an idle thread in the home scheduler instance in the case it executes |
---|
| 892 | * currently in another scheduler instance or in the case it is in a blocking |
---|
[6771359f] | 893 | * state. |
---|
[5c3d250] | 894 | * |
---|
[11e7893] | 895 | * @param context The scheduler instance context. |
---|
| 896 | * @param[in, out] node The node which wants to use the idle thread. |
---|
| 897 | * @param cpu The processor for the idle thread. |
---|
| 898 | * @param get_idle_thread Function to get an idle thread. |
---|
[5c3d250] | 899 | */ |
---|
| 900 | RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Use_idle_thread( |
---|
| 901 | Scheduler_Context *context, |
---|
| 902 | Scheduler_Node *node, |
---|
[6771359f] | 903 | Per_CPU_Control *cpu, |
---|
[5c3d250] | 904 | Scheduler_Get_idle_thread get_idle_thread |
---|
| 905 | ) |
---|
| 906 | { |
---|
| 907 | Thread_Control *idle = ( *get_idle_thread )( context ); |
---|
| 908 | |
---|
[be0366b] | 909 | _Scheduler_Set_idle_thread( node, idle ); |
---|
[6771359f] | 910 | _Thread_Set_CPU( idle, cpu ); |
---|
[5c3d250] | 911 | return idle; |
---|
| 912 | } |
---|
| 913 | |
---|
[be0366b] | 914 | typedef enum { |
---|
| 915 | SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE, |
---|
| 916 | SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE, |
---|
| 917 | SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK |
---|
| 918 | } Scheduler_Try_to_schedule_action; |
---|
| 919 | |
---|
[5c3d250] | 920 | /** |
---|
[11e7893] | 921 | * @brief Tries to schedule this scheduler node. |
---|
[5c3d250] | 922 | * |
---|
[11e7893] | 923 | * @param context The scheduler instance context. |
---|
| 924 | * @param[in, out] node The node which wants to get scheduled. |
---|
| 925 | * @param idle A potential idle thread used by a potential victim node. |
---|
| 926 | * @param get_idle_thread Function to get an idle thread. |
---|
[5c3d250] | 927 | * |
---|
| 928 | * @retval true This node can be scheduled. |
---|
[11e7893] | 929 | * @retval false This node cannot be scheduled. |
---|
[5c3d250] | 930 | */ |
---|
[be0366b] | 931 | RTEMS_INLINE_ROUTINE Scheduler_Try_to_schedule_action |
---|
| 932 | _Scheduler_Try_to_schedule_node( |
---|
[5c3d250] | 933 | Scheduler_Context *context, |
---|
| 934 | Scheduler_Node *node, |
---|
[be0366b] | 935 | Thread_Control *idle, |
---|
[5c3d250] | 936 | Scheduler_Get_idle_thread get_idle_thread |
---|
| 937 | ) |
---|
| 938 | { |
---|
[a7a8ec03] | 939 | ISR_lock_Context lock_context; |
---|
| 940 | Scheduler_Try_to_schedule_action action; |
---|
[76ad5e0c] | 941 | Thread_Control *owner; |
---|
[5c3d250] | 942 | |
---|
[be0366b] | 943 | action = SCHEDULER_TRY_TO_SCHEDULE_DO_SCHEDULE; |
---|
[76ad5e0c] | 944 | owner = _Scheduler_Node_get_owner( node ); |
---|
| 945 | _Assert( _Scheduler_Node_get_user( node ) == owner ); |
---|
| 946 | _Assert( _Scheduler_Node_get_idle( node ) == NULL ); |
---|
[a7a8ec03] | 947 | |
---|
[76ad5e0c] | 948 | _Thread_Scheduler_acquire_critical( owner, &lock_context ); |
---|
[be0366b] | 949 | |
---|
[76ad5e0c] | 950 | if ( owner->Scheduler.state == THREAD_SCHEDULER_READY ) { |
---|
| 951 | _Thread_Scheduler_cancel_need_for_help( owner, _Thread_Get_CPU( owner ) ); |
---|
| 952 | _Scheduler_Thread_change_state( owner, THREAD_SCHEDULER_SCHEDULED ); |
---|
[6771359f] | 953 | } else if ( |
---|
[76ad5e0c] | 954 | owner->Scheduler.state == THREAD_SCHEDULER_SCHEDULED |
---|
| 955 | && node->sticky_level <= 1 |
---|
[6771359f] | 956 | ) { |
---|
| 957 | action = SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK; |
---|
[76ad5e0c] | 958 | } else if ( node->sticky_level == 0 ) { |
---|
| 959 | action = SCHEDULER_TRY_TO_SCHEDULE_DO_BLOCK; |
---|
[6771359f] | 960 | } else if ( idle != NULL ) { |
---|
| 961 | action = SCHEDULER_TRY_TO_SCHEDULE_DO_IDLE_EXCHANGE; |
---|
| 962 | } else { |
---|
| 963 | _Scheduler_Use_idle_thread( |
---|
| 964 | context, |
---|
| 965 | node, |
---|
[76ad5e0c] | 966 | _Thread_Get_CPU( owner ), |
---|
[6771359f] | 967 | get_idle_thread |
---|
| 968 | ); |
---|
[a7a8ec03] | 969 | } |
---|
| 970 | |
---|
[76ad5e0c] | 971 | _Thread_Scheduler_release_critical( owner, &lock_context ); |
---|
[be0366b] | 972 | return action; |
---|
[5c3d250] | 973 | } |
---|
| 974 | |
---|
| 975 | /** |
---|
[11e7893] | 976 | * @brief Releases an idle thread using this scheduler node. |
---|
[5c3d250] | 977 | * |
---|
[11e7893] | 978 | * @param context The scheduler instance context. |
---|
| 979 | * @param[in, out] node The node which may have an idle thread as user. |
---|
| 980 | * @param release_idle_thread Function to release an idle thread. |
---|
[5c3d250] | 981 | * |
---|
| 982 | * @retval idle The idle thread which used this node. |
---|
| 983 | * @retval NULL This node had no idle thread as an user. |
---|
| 984 | */ |
---|
| 985 | RTEMS_INLINE_ROUTINE Thread_Control *_Scheduler_Release_idle_thread( |
---|
| 986 | Scheduler_Context *context, |
---|
| 987 | Scheduler_Node *node, |
---|
| 988 | Scheduler_Release_idle_thread release_idle_thread |
---|
| 989 | ) |
---|
| 990 | { |
---|
| 991 | Thread_Control *idle = _Scheduler_Node_get_idle( node ); |
---|
| 992 | |
---|
| 993 | if ( idle != NULL ) { |
---|
| 994 | Thread_Control *owner = _Scheduler_Node_get_owner( node ); |
---|
| 995 | |
---|
| 996 | node->idle = NULL; |
---|
| 997 | _Scheduler_Node_set_user( node, owner ); |
---|
| 998 | ( *release_idle_thread )( context, idle ); |
---|
| 999 | } |
---|
| 1000 | |
---|
| 1001 | return idle; |
---|
| 1002 | } |
---|
| 1003 | |
---|
[11e7893] | 1004 | /** |
---|
| 1005 | * @brief Exchanges an idle thread from the scheduler node that uses it |
---|
| 1006 | * right now to another scheduler node. |
---|
| 1007 | * |
---|
| 1008 | * @param needs_idle The scheduler node that needs an idle thread. |
---|
| 1009 | * @param uses_idle The scheduler node that used the idle thread. |
---|
| 1010 | * @param idle The idle thread that is exchanged. |
---|
| 1011 | */ |
---|
[be0366b] | 1012 | RTEMS_INLINE_ROUTINE void _Scheduler_Exchange_idle_thread( |
---|
| 1013 | Scheduler_Node *needs_idle, |
---|
| 1014 | Scheduler_Node *uses_idle, |
---|
| 1015 | Thread_Control *idle |
---|
| 1016 | ) |
---|
| 1017 | { |
---|
| 1018 | uses_idle->idle = NULL; |
---|
| 1019 | _Scheduler_Node_set_user( |
---|
| 1020 | uses_idle, |
---|
| 1021 | _Scheduler_Node_get_owner( uses_idle ) |
---|
| 1022 | ); |
---|
| 1023 | _Scheduler_Set_idle_thread( needs_idle, idle ); |
---|
| 1024 | } |
---|
| 1025 | |
---|
[5c3d250] | 1026 | /** |
---|
[11e7893] | 1027 | * @brief Blocks this scheduler node. |
---|
[5c3d250] | 1028 | * |
---|
[11e7893] | 1029 | * @param context The scheduler instance context. |
---|
| 1030 | * @param[in, out] thread The thread which wants to get blocked referencing this |
---|
[5bd822a7] | 1031 | * node. This is not necessarily the user of this node in case the node |
---|
| 1032 | * participates in the scheduler helping protocol. |
---|
[11e7893] | 1033 | * @param[in, out] node The node which wants to get blocked. |
---|
| 1034 | * @param is_scheduled This node is scheduled. |
---|
| 1035 | * @param get_idle_thread Function to get an idle thread. |
---|
[5c3d250] | 1036 | * |
---|
[edb020c] | 1037 | * @retval thread_cpu The processor of the thread. Indicates to continue with |
---|
| 1038 | * the blocking operation. |
---|
| 1039 | * @retval NULL Otherwise. |
---|
[5c3d250] | 1040 | */ |
---|
[edb020c] | 1041 | RTEMS_INLINE_ROUTINE Per_CPU_Control *_Scheduler_Block_node( |
---|
[5c3d250] | 1042 | Scheduler_Context *context, |
---|
[cceb19f4] | 1043 | Thread_Control *thread, |
---|
[5c3d250] | 1044 | Scheduler_Node *node, |
---|
| 1045 | bool is_scheduled, |
---|
| 1046 | Scheduler_Get_idle_thread get_idle_thread |
---|
| 1047 | ) |
---|
| 1048 | { |
---|
[6771359f] | 1049 | int sticky_level; |
---|
[a7a8ec03] | 1050 | ISR_lock_Context lock_context; |
---|
[edb020c] | 1051 | Per_CPU_Control *thread_cpu; |
---|
[5c3d250] | 1052 | |
---|
[6771359f] | 1053 | sticky_level = node->sticky_level; |
---|
| 1054 | --sticky_level; |
---|
| 1055 | node->sticky_level = sticky_level; |
---|
| 1056 | _Assert( sticky_level >= 0 ); |
---|
| 1057 | |
---|
[a7a8ec03] | 1058 | _Thread_Scheduler_acquire_critical( thread, &lock_context ); |
---|
[edb020c] | 1059 | thread_cpu = _Thread_Get_CPU( thread ); |
---|
[351c14d] | 1060 | _Thread_Scheduler_cancel_need_for_help( thread, thread_cpu ); |
---|
[5bd822a7] | 1061 | _Scheduler_Thread_change_state( thread, THREAD_SCHEDULER_BLOCKED ); |
---|
[a7a8ec03] | 1062 | _Thread_Scheduler_release_critical( thread, &lock_context ); |
---|
[5c3d250] | 1063 | |
---|
[6771359f] | 1064 | if ( sticky_level > 0 ) { |
---|
| 1065 | if ( is_scheduled && _Scheduler_Node_get_idle( node ) == NULL ) { |
---|
| 1066 | Thread_Control *idle; |
---|
| 1067 | |
---|
| 1068 | idle = _Scheduler_Use_idle_thread( |
---|
| 1069 | context, |
---|
| 1070 | node, |
---|
| 1071 | thread_cpu, |
---|
| 1072 | get_idle_thread |
---|
| 1073 | ); |
---|
| 1074 | _Thread_Dispatch_update_heir( _Per_CPU_Get(), thread_cpu, idle ); |
---|
| 1075 | } |
---|
[5c3d250] | 1076 | |
---|
[6771359f] | 1077 | return NULL; |
---|
[5bd822a7] | 1078 | } |
---|
| 1079 | |
---|
[6771359f] | 1080 | _Assert( thread == _Scheduler_Node_get_user( node ) ); |
---|
| 1081 | return thread_cpu; |
---|
| 1082 | } |
---|
[5bd822a7] | 1083 | |
---|
[11e7893] | 1084 | /** |
---|
| 1085 | * @brief Discard the idle thread from the scheduler node. |
---|
| 1086 | * |
---|
| 1087 | * @param context The scheduler context. |
---|
| 1088 | * @param[in, out] the_thread The thread for the operation. |
---|
| 1089 | * @param[in, out] node The scheduler node to discard the idle thread from. |
---|
| 1090 | * @param release_idle_thread Method to release the idle thread from the context. |
---|
| 1091 | */ |
---|
[6771359f] | 1092 | RTEMS_INLINE_ROUTINE void _Scheduler_Discard_idle_thread( |
---|
| 1093 | Scheduler_Context *context, |
---|
| 1094 | Thread_Control *the_thread, |
---|
| 1095 | Scheduler_Node *node, |
---|
| 1096 | Scheduler_Release_idle_thread release_idle_thread |
---|
| 1097 | ) |
---|
| 1098 | { |
---|
| 1099 | Thread_Control *idle; |
---|
| 1100 | Thread_Control *owner; |
---|
| 1101 | Per_CPU_Control *cpu; |
---|
[5c3d250] | 1102 | |
---|
[6771359f] | 1103 | idle = _Scheduler_Node_get_idle( node ); |
---|
| 1104 | owner = _Scheduler_Node_get_owner( node ); |
---|
[5c3d250] | 1105 | |
---|
[6771359f] | 1106 | node->idle = NULL; |
---|
| 1107 | _Assert( _Scheduler_Node_get_user( node ) == idle ); |
---|
| 1108 | _Scheduler_Node_set_user( node, owner ); |
---|
| 1109 | ( *release_idle_thread )( context, idle ); |
---|
[5c3d250] | 1110 | |
---|
[6771359f] | 1111 | cpu = _Thread_Get_CPU( idle ); |
---|
| 1112 | _Thread_Set_CPU( the_thread, cpu ); |
---|
| 1113 | _Thread_Dispatch_update_heir( _Per_CPU_Get(), cpu, the_thread ); |
---|
[5c3d250] | 1114 | } |
---|
| 1115 | |
---|
| 1116 | /** |
---|
[11e7893] | 1117 | * @brief Unblocks this scheduler node. |
---|
[5c3d250] | 1118 | * |
---|
[11e7893] | 1119 | * @param context The scheduler instance context. |
---|
| 1120 | * @param[in, out] the_thread The thread which wants to get unblocked. |
---|
| 1121 | * @param[in, out] node The node which wants to get unblocked. |
---|
| 1122 | * @param is_scheduled This node is scheduled. |
---|
| 1123 | * @param release_idle_thread Function to release an idle thread. |
---|
[5c3d250] | 1124 | * |
---|
| 1125 | * @retval true Continue with the unblocking operation. |
---|
[11e7893] | 1126 | * @retval false Do not continue with the unblocking operation. |
---|
[5c3d250] | 1127 | */ |
---|
| 1128 | RTEMS_INLINE_ROUTINE bool _Scheduler_Unblock_node( |
---|
| 1129 | Scheduler_Context *context, |
---|
| 1130 | Thread_Control *the_thread, |
---|
| 1131 | Scheduler_Node *node, |
---|
| 1132 | bool is_scheduled, |
---|
| 1133 | Scheduler_Release_idle_thread release_idle_thread |
---|
| 1134 | ) |
---|
| 1135 | { |
---|
| 1136 | bool unblock; |
---|
| 1137 | |
---|
[6771359f] | 1138 | ++node->sticky_level; |
---|
| 1139 | _Assert( node->sticky_level > 0 ); |
---|
| 1140 | |
---|
[5c3d250] | 1141 | if ( is_scheduled ) { |
---|
[6771359f] | 1142 | _Scheduler_Discard_idle_thread( |
---|
[5bd822a7] | 1143 | context, |
---|
[6771359f] | 1144 | the_thread, |
---|
[5bd822a7] | 1145 | node, |
---|
| 1146 | release_idle_thread |
---|
| 1147 | ); |
---|
[6771359f] | 1148 | _Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_SCHEDULED ); |
---|
[5c3d250] | 1149 | unblock = false; |
---|
| 1150 | } else { |
---|
| 1151 | _Scheduler_Thread_change_state( the_thread, THREAD_SCHEDULER_READY ); |
---|
| 1152 | unblock = true; |
---|
| 1153 | } |
---|
| 1154 | |
---|
| 1155 | return unblock; |
---|
| 1156 | } |
---|
[8f0c7a46] | 1157 | #endif |
---|
| 1158 | |
---|
[11e7893] | 1159 | /** |
---|
| 1160 | * @brief Updates the heir. |
---|
| 1161 | * |
---|
| 1162 | * @param[in, out] new_heir The new heir. |
---|
| 1163 | * @param force_dispatch Indicates whether the dispatch happens also if the |
---|
| 1164 | * currently running thread is set as not preemptible. |
---|
| 1165 | */ |
---|
[d37adfe5] | 1166 | RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir( |
---|
| 1167 | Thread_Control *new_heir, |
---|
| 1168 | bool force_dispatch |
---|
| 1169 | ) |
---|
| 1170 | { |
---|
| 1171 | Thread_Control *heir = _Thread_Heir; |
---|
| 1172 | |
---|
| 1173 | if ( heir != new_heir && ( heir->is_preemptible || force_dispatch ) ) { |
---|
| 1174 | #if defined(RTEMS_SMP) |
---|
[baa13626] | 1175 | /* |
---|
| 1176 | * We need this state only for _Thread_Get_CPU_time_used(). Cannot use |
---|
| 1177 | * _Scheduler_Thread_change_state() since THREAD_SCHEDULER_BLOCKED to |
---|
| 1178 | * THREAD_SCHEDULER_BLOCKED state changes are illegal for the real SMP |
---|
| 1179 | * schedulers. |
---|
| 1180 | */ |
---|
| 1181 | heir->Scheduler.state = THREAD_SCHEDULER_BLOCKED; |
---|
| 1182 | new_heir->Scheduler.state = THREAD_SCHEDULER_SCHEDULED; |
---|
[d37adfe5] | 1183 | #endif |
---|
| 1184 | _Thread_Update_CPU_time_used( heir, _Thread_Get_CPU( heir ) ); |
---|
| 1185 | _Thread_Heir = new_heir; |
---|
| 1186 | _Thread_Dispatch_necessary = true; |
---|
| 1187 | } |
---|
| 1188 | } |
---|
| 1189 | |
---|
[11e7893] | 1190 | /** |
---|
| 1191 | * @brief Sets a new scheduler. |
---|
| 1192 | * |
---|
| 1193 | * @param new_scheduler The new scheduler to set. |
---|
| 1194 | * @param[in, out] the_thread The thread for the operations. |
---|
| 1195 | * @param priority The initial priority for the thread with the new scheduler. |
---|
| 1196 | * |
---|
| 1197 | * @retval STATUS_SUCCESSFUL The operation succeeded. |
---|
| 1198 | * @retval STATUS_RESOURCE_IN_USE The thread's wait queue is not empty. |
---|
| 1199 | * @retval STATUS_UNSATISFIED The new scheduler has no processors. |
---|
| 1200 | */ |
---|
[c0bd006] | 1201 | RTEMS_INLINE_ROUTINE Status_Control _Scheduler_Set( |
---|
| 1202 | const Scheduler_Control *new_scheduler, |
---|
| 1203 | Thread_Control *the_thread, |
---|
| 1204 | Priority_Control priority |
---|
| 1205 | ) |
---|
| 1206 | { |
---|
[2612a0b] | 1207 | Scheduler_Node *new_scheduler_node; |
---|
| 1208 | Scheduler_Node *old_scheduler_node; |
---|
| 1209 | #if defined(RTEMS_SMP) |
---|
| 1210 | ISR_lock_Context lock_context; |
---|
| 1211 | const Scheduler_Control *old_scheduler; |
---|
| 1212 | |
---|
| 1213 | #endif |
---|
[c0bd006] | 1214 | |
---|
[9e7fa07] | 1215 | if ( the_thread->Wait.queue != NULL ) { |
---|
[c0bd006] | 1216 | return STATUS_RESOURCE_IN_USE; |
---|
| 1217 | } |
---|
| 1218 | |
---|
[7f742432] | 1219 | old_scheduler_node = _Thread_Scheduler_get_home_node( the_thread ); |
---|
[5d6b211] | 1220 | _Priority_Plain_extract( |
---|
| 1221 | &old_scheduler_node->Wait.Priority, |
---|
| 1222 | &the_thread->Real_priority |
---|
| 1223 | ); |
---|
[c0bd006] | 1224 | |
---|
[7097962] | 1225 | if ( |
---|
| 1226 | !_Priority_Is_empty( &old_scheduler_node->Wait.Priority ) |
---|
[5d6b211] | 1227 | #if defined(RTEMS_SMP) |
---|
[7097962] | 1228 | || !_Chain_Has_only_one_node( &the_thread->Scheduler.Wait_nodes ) |
---|
| 1229 | || the_thread->Scheduler.pin_level != 0 |
---|
| 1230 | #endif |
---|
| 1231 | ) { |
---|
[2612a0b] | 1232 | _Priority_Plain_insert( |
---|
| 1233 | &old_scheduler_node->Wait.Priority, |
---|
| 1234 | &the_thread->Real_priority, |
---|
| 1235 | the_thread->Real_priority.priority |
---|
| 1236 | ); |
---|
[9e7fa07] | 1237 | return STATUS_RESOURCE_IN_USE; |
---|
| 1238 | } |
---|
| 1239 | |
---|
[7097962] | 1240 | #if defined(RTEMS_SMP) |
---|
[2612a0b] | 1241 | old_scheduler = _Thread_Scheduler_get_home( the_thread ); |
---|
[4a1bdd30] | 1242 | new_scheduler_node = _Thread_Scheduler_get_node_by_index( |
---|
| 1243 | the_thread, |
---|
| 1244 | _Scheduler_Get_index( new_scheduler ) |
---|
| 1245 | ); |
---|
[2612a0b] | 1246 | |
---|
| 1247 | _Scheduler_Acquire_critical( new_scheduler, &lock_context ); |
---|
| 1248 | |
---|
[4a1bdd30] | 1249 | if ( |
---|
| 1250 | _Scheduler_Get_processor_count( new_scheduler ) == 0 |
---|
| 1251 | || !( *new_scheduler->Operations.set_affinity )( |
---|
| 1252 | new_scheduler, |
---|
| 1253 | the_thread, |
---|
| 1254 | new_scheduler_node, |
---|
| 1255 | &the_thread->Scheduler.Affinity |
---|
| 1256 | ) |
---|
| 1257 | ) { |
---|
[2612a0b] | 1258 | _Scheduler_Release_critical( new_scheduler, &lock_context ); |
---|
| 1259 | _Priority_Plain_insert( |
---|
| 1260 | &old_scheduler_node->Wait.Priority, |
---|
| 1261 | &the_thread->Real_priority, |
---|
| 1262 | the_thread->Real_priority.priority |
---|
| 1263 | ); |
---|
| 1264 | return STATUS_UNSATISFIED; |
---|
| 1265 | } |
---|
| 1266 | |
---|
[7097962] | 1267 | _Assert( the_thread->Scheduler.pinned_scheduler == NULL ); |
---|
| 1268 | the_thread->Scheduler.home_scheduler = new_scheduler; |
---|
[2612a0b] | 1269 | |
---|
| 1270 | _Scheduler_Release_critical( new_scheduler, &lock_context ); |
---|
| 1271 | |
---|
[2403473] | 1272 | _Thread_Scheduler_process_requests( the_thread ); |
---|
[5d6b211] | 1273 | #else |
---|
| 1274 | new_scheduler_node = old_scheduler_node; |
---|
| 1275 | #endif |
---|
| 1276 | |
---|
[300f6a48] | 1277 | the_thread->Start.initial_priority = priority; |
---|
| 1278 | _Priority_Node_set_priority( &the_thread->Real_priority, priority ); |
---|
| 1279 | _Priority_Initialize_one( |
---|
[5d6b211] | 1280 | &new_scheduler_node->Wait.Priority, |
---|
[300f6a48] | 1281 | &the_thread->Real_priority |
---|
| 1282 | ); |
---|
[c0bd006] | 1283 | |
---|
| 1284 | #if defined(RTEMS_SMP) |
---|
[2612a0b] | 1285 | if ( old_scheduler != new_scheduler ) { |
---|
| 1286 | States_Control current_state; |
---|
[c0bd006] | 1287 | |
---|
[2612a0b] | 1288 | current_state = the_thread->current_state; |
---|
[c0bd006] | 1289 | |
---|
[2612a0b] | 1290 | if ( _States_Is_ready( current_state ) ) { |
---|
| 1291 | _Scheduler_Block( the_thread ); |
---|
| 1292 | } |
---|
[6771359f] | 1293 | |
---|
[2612a0b] | 1294 | _Assert( old_scheduler_node->sticky_level == 0 ); |
---|
| 1295 | _Assert( new_scheduler_node->sticky_level == 0 ); |
---|
[6771359f] | 1296 | |
---|
[2612a0b] | 1297 | _Chain_Extract_unprotected( &old_scheduler_node->Thread.Wait_node ); |
---|
| 1298 | _Assert( _Chain_Is_empty( &the_thread->Scheduler.Wait_nodes ) ); |
---|
| 1299 | _Chain_Initialize_one( |
---|
| 1300 | &the_thread->Scheduler.Wait_nodes, |
---|
| 1301 | &new_scheduler_node->Thread.Wait_node |
---|
| 1302 | ); |
---|
| 1303 | _Chain_Extract_unprotected( |
---|
| 1304 | &old_scheduler_node->Thread.Scheduler_node.Chain |
---|
| 1305 | ); |
---|
| 1306 | _Assert( _Chain_Is_empty( &the_thread->Scheduler.Scheduler_nodes ) ); |
---|
| 1307 | _Chain_Initialize_one( |
---|
| 1308 | &the_thread->Scheduler.Scheduler_nodes, |
---|
| 1309 | &new_scheduler_node->Thread.Scheduler_node.Chain |
---|
| 1310 | ); |
---|
[c0bd006] | 1311 | |
---|
[2612a0b] | 1312 | _Scheduler_Node_set_priority( new_scheduler_node, priority, false ); |
---|
[c0bd006] | 1313 | |
---|
[2612a0b] | 1314 | if ( _States_Is_ready( current_state ) ) { |
---|
| 1315 | _Scheduler_Unblock( the_thread ); |
---|
[c0bd006] | 1316 | } |
---|
[2612a0b] | 1317 | |
---|
| 1318 | return STATUS_SUCCESSFUL; |
---|
[c0bd006] | 1319 | } |
---|
| 1320 | #endif |
---|
| 1321 | |
---|
[5d6b211] | 1322 | _Scheduler_Node_set_priority( new_scheduler_node, priority, false ); |
---|
[c0bd006] | 1323 | _Scheduler_Update_priority( the_thread ); |
---|
| 1324 | return STATUS_SUCCESSFUL; |
---|
| 1325 | } |
---|
| 1326 | |
---|
[1f0d013] | 1327 | /** @} */ |
---|
[0faa9dad] | 1328 | |
---|
[c6e21ee1] | 1329 | #ifdef __cplusplus |
---|
| 1330 | } |
---|
| 1331 | #endif |
---|
| 1332 | |
---|
[0faa9dad] | 1333 | #endif |
---|
| 1334 | /* end of include file */ |
---|