Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:43

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2014, 2017 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031 
0032 #include <rtems.h>
0033 #include <rtems/libcsupport.h>
0034 #include <rtems/score/threadimpl.h>
0035 #include <rtems/score/schedulersmpimpl.h>
0036 
0037 #include "tmacros.h"
0038 
0039 void Init(rtems_task_argument arg);
0040 
0041 static Scheduler_SMP_Node *get_scheduler_node(Thread_Control *thread)
0042 {
0043   return _Scheduler_SMP_Node_downcast(_Thread_Scheduler_get_home_node(thread));
0044 }
0045 
0046 static void apply_priority(
0047   Thread_Control *thread,
0048   Priority_Control new_priority,
0049   Priority_Group_order priority_group_order,
0050   Thread_queue_Context *queue_context
0051 )
0052 {
0053   const Scheduler_Control *scheduler;
0054 
0055   scheduler = _Thread_Scheduler_get_home(thread);
0056   new_priority = _Scheduler_Map_priority(scheduler, new_priority);
0057 
0058   _Thread_queue_Context_initialize(queue_context);
0059   _Thread_queue_Context_clear_priority_updates(queue_context);
0060   _Thread_Wait_acquire(thread, queue_context);
0061   _Thread_Priority_change(
0062     thread,
0063     &thread->Real_priority,
0064     new_priority,
0065     priority_group_order,
0066     queue_context
0067   );
0068   _Thread_Wait_release(thread, queue_context);
0069 }
0070 
0071 static void change_priority(
0072   Thread_Control *thread,
0073   Priority_Control new_priority,
0074   Priority_Group_order priority_group_order
0075 )
0076 {
0077   Thread_queue_Context queue_context;
0078 
0079   apply_priority(thread, new_priority, priority_group_order, &queue_context);
0080   _Thread_Priority_update(&queue_context);
0081 }
0082 
0083 static void task(rtems_task_argument arg)
0084 {
0085   rtems_test_assert(0);
0086 }
0087 
0088 static rtems_id start_task(rtems_task_priority prio)
0089 {
0090   rtems_status_code sc;
0091   rtems_id task_id;
0092 
0093   sc = rtems_task_create(
0094     rtems_build_name('T', 'A', 'S', 'K'),
0095     prio,
0096     RTEMS_MINIMUM_STACK_SIZE,
0097     RTEMS_DEFAULT_MODES,
0098     RTEMS_DEFAULT_ATTRIBUTES,
0099     &task_id
0100   );
0101   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0102 
0103   sc = rtems_task_start(task_id, task, 0);
0104   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0105 
0106   return task_id;
0107 }
0108 
0109 static Thread_Control *get_thread_by_id(rtems_id task_id)
0110 {
0111   ISR_lock_Context lock_context;
0112   Thread_Control *thread;
0113 
0114   thread = _Thread_Get(task_id, &lock_context);
0115   rtems_test_assert(thread != NULL);
0116   _ISR_lock_ISR_enable(&lock_context);
0117 
0118   return thread;
0119 }
0120 
0121 static void test_case_change_priority(
0122   Thread_Control *executing,
0123   Scheduler_SMP_Node *executing_node,
0124   Scheduler_SMP_Node_state start_state,
0125   Priority_Control prio,
0126   Priority_Group_order priority_group_order,
0127   Scheduler_SMP_Node_state new_state
0128 )
0129 {
0130   Per_CPU_Control *cpu_self;
0131 
0132   cpu_self = _Thread_Dispatch_disable();
0133 
0134   switch (start_state) {
0135     case SCHEDULER_SMP_NODE_SCHEDULED:
0136       change_priority(executing, 1, PRIORITY_GROUP_FIRST);
0137       break;
0138     case SCHEDULER_SMP_NODE_READY:
0139       change_priority(executing, 4, PRIORITY_GROUP_FIRST);
0140       break;
0141     default:
0142       rtems_test_assert(0);
0143       break;
0144   }
0145   rtems_test_assert(executing_node->state == start_state);
0146 
0147   change_priority(executing, prio, priority_group_order);
0148   rtems_test_assert(executing_node->state == new_state);
0149 
0150   change_priority(executing, 1, PRIORITY_GROUP_FIRST);
0151   rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
0152 
0153   _Thread_Dispatch_enable( cpu_self );
0154 }
0155 
0156 static const Scheduler_SMP_Node_state states[2] = {
0157   SCHEDULER_SMP_NODE_SCHEDULED,
0158   SCHEDULER_SMP_NODE_READY
0159 };
0160 
0161 static const Priority_Control priorities[2] = { 2, 5 };
0162 
0163 static const Priority_Group_order priority_group_order[2] = {
0164   PRIORITY_GROUP_FIRST,
0165   PRIORITY_GROUP_LAST
0166 };
0167 
0168 static void test_change_priority(void)
0169 {
0170   rtems_status_code sc;
0171   rtems_id task_id;
0172   Thread_Control *executing;
0173   Scheduler_SMP_Node *executing_node;
0174   size_t i;
0175   size_t j;
0176   size_t k;
0177 
0178   task_id = start_task(3);
0179   executing = _Thread_Get_executing();
0180   executing_node = get_scheduler_node(executing);
0181 
0182   for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) {
0183     for (j = 0; j < RTEMS_ARRAY_SIZE(priorities); ++j) {
0184       for (k = 0; k < RTEMS_ARRAY_SIZE(priority_group_order); ++k) {
0185         test_case_change_priority(
0186           executing,
0187           executing_node,
0188           states[i],
0189           priorities[j],
0190           priority_group_order[k],
0191           states[j]
0192         );
0193       }
0194     }
0195   }
0196 
0197   sc = rtems_task_delete(task_id);
0198   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0199 }
0200 
0201 static void update_priority_op(
0202   Thread_Control *thread,
0203   Scheduler_SMP_Node *scheduler_node,
0204   Priority_Control new_priority,
0205   Priority_Group_order priority_group_order
0206 )
0207 {
0208   const Scheduler_Control *scheduler;
0209   ISR_lock_Context state_lock_context;
0210   ISR_lock_Context scheduler_lock_context;
0211   Thread_queue_Context queue_context;
0212 
0213   apply_priority(thread, new_priority, priority_group_order, &queue_context);
0214 
0215   _Thread_State_acquire( thread, &state_lock_context );
0216   scheduler = _Thread_Scheduler_get_home( thread );
0217   _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
0218 
0219   (*scheduler->Operations.update_priority)(
0220     scheduler,
0221     thread,
0222     &scheduler_node->Base
0223   );
0224 
0225   _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
0226   _Thread_State_release( thread, &state_lock_context );
0227 }
0228 
0229 static void test_case_update_priority_op(
0230   Thread_Control *executing,
0231   Scheduler_SMP_Node *executing_node,
0232   Thread_Control *other,
0233   Scheduler_SMP_Node_state start_state,
0234   Priority_Control prio,
0235   Priority_Group_order priority_group_order,
0236   Scheduler_SMP_Node_state new_state
0237 )
0238 {
0239   Per_CPU_Control *cpu_self;
0240 
0241   cpu_self = _Thread_Dispatch_disable();
0242 
0243   switch (start_state) {
0244     case SCHEDULER_SMP_NODE_SCHEDULED:
0245       change_priority(executing, 1, PRIORITY_GROUP_FIRST);
0246       break;
0247     case SCHEDULER_SMP_NODE_READY:
0248       change_priority(executing, 4, PRIORITY_GROUP_FIRST);
0249       break;
0250     default:
0251       rtems_test_assert(0);
0252       break;
0253   }
0254   rtems_test_assert(executing_node->state == start_state);
0255 
0256   update_priority_op(executing, executing_node, prio, priority_group_order);
0257   rtems_test_assert(executing_node->state == new_state);
0258 
0259   if (start_state != new_state) {
0260     switch (start_state) {
0261       case SCHEDULER_SMP_NODE_SCHEDULED:
0262         rtems_test_assert(cpu_self->heir == other);
0263         break;
0264       case SCHEDULER_SMP_NODE_READY:
0265         rtems_test_assert(cpu_self->heir == executing);
0266         break;
0267       default:
0268         rtems_test_assert(0);
0269         break;
0270     }
0271   }
0272 
0273   change_priority(executing, 1, PRIORITY_GROUP_FIRST);
0274   rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
0275 
0276   _Thread_Dispatch_enable( cpu_self );
0277 }
0278 
0279 static void test_update_priority_op(void)
0280 {
0281   rtems_status_code sc;
0282   rtems_id task_id;
0283   Thread_Control *executing;
0284   Scheduler_SMP_Node *executing_node;
0285   Thread_Control *other;
0286   size_t i;
0287   size_t j;
0288   size_t k;
0289 
0290   task_id = start_task(3);
0291   executing = _Thread_Get_executing();
0292   executing_node = get_scheduler_node(executing);
0293 
0294   other = get_thread_by_id(task_id);
0295 
0296   for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) {
0297     for (j = 0; j < RTEMS_ARRAY_SIZE(priorities); ++j) {
0298       for (k = 0; k < RTEMS_ARRAY_SIZE(priority_group_order); ++k) {
0299         test_case_update_priority_op(
0300           executing,
0301           executing_node,
0302           other,
0303           states[i],
0304           priorities[j],
0305           priority_group_order[k],
0306           states[j]
0307         );
0308       }
0309     }
0310   }
0311 
0312   sc = rtems_task_delete(task_id);
0313   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0314 }
0315 
0316 static void yield_op(
0317   Thread_Control *thread,
0318   Scheduler_SMP_Node *scheduler_node
0319 )
0320 {
0321   const Scheduler_Control *scheduler;
0322   ISR_lock_Context state_lock_context;
0323   ISR_lock_Context scheduler_lock_context;
0324 
0325   _Thread_State_acquire( thread, &state_lock_context );
0326   scheduler = _Thread_Scheduler_get_home( thread );
0327   _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
0328 
0329   (*scheduler->Operations.yield)(
0330     scheduler,
0331     thread,
0332     &scheduler_node->Base
0333   );
0334 
0335   _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
0336   _Thread_State_release( thread, &state_lock_context );
0337 }
0338 
0339 static void test_case_yield_op(
0340   Thread_Control *executing,
0341   Scheduler_SMP_Node *executing_node,
0342   Thread_Control *other,
0343   Scheduler_SMP_Node_state start_state,
0344   Scheduler_SMP_Node_state new_state
0345 )
0346 {
0347   Per_CPU_Control *cpu_self;
0348 
0349   cpu_self = _Thread_Dispatch_disable();
0350 
0351   change_priority(executing, 4, PRIORITY_GROUP_LAST);
0352   change_priority(other, 4, PRIORITY_GROUP_LAST);
0353 
0354   switch (start_state) {
0355     case SCHEDULER_SMP_NODE_SCHEDULED:
0356       switch (new_state) {
0357         case SCHEDULER_SMP_NODE_SCHEDULED:
0358           change_priority(executing, 2, PRIORITY_GROUP_LAST);
0359           change_priority(other, 3, PRIORITY_GROUP_LAST);
0360           break;
0361         case SCHEDULER_SMP_NODE_READY:
0362           change_priority(executing, 2, PRIORITY_GROUP_LAST);
0363           change_priority(other, 2, PRIORITY_GROUP_LAST);
0364           break;
0365         default:
0366           rtems_test_assert(0);
0367           break;
0368       }
0369       break;
0370     case SCHEDULER_SMP_NODE_READY:
0371       switch (new_state) {
0372         case SCHEDULER_SMP_NODE_SCHEDULED:
0373           rtems_test_assert(0);
0374           break;
0375         case SCHEDULER_SMP_NODE_READY:
0376           change_priority(executing, 3, PRIORITY_GROUP_LAST);
0377           change_priority(other, 2, PRIORITY_GROUP_LAST);
0378           break;
0379         default:
0380           rtems_test_assert(0);
0381           break;
0382       }
0383       break;
0384     default:
0385       rtems_test_assert(0);
0386       break;
0387   }
0388   rtems_test_assert(executing_node->state == start_state);
0389 
0390   yield_op(executing, executing_node);
0391   rtems_test_assert(executing_node->state == new_state);
0392 
0393   switch (new_state) {
0394     case SCHEDULER_SMP_NODE_SCHEDULED:
0395     case SCHEDULER_SMP_NODE_READY:
0396       break;
0397     default:
0398       rtems_test_assert(0);
0399       break;
0400   }
0401 
0402   change_priority(executing, 1, PRIORITY_GROUP_FIRST);
0403   rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
0404 
0405   _Thread_Dispatch_enable( cpu_self );
0406 }
0407 
0408 static void test_yield_op(void)
0409 {
0410   rtems_status_code sc;
0411   rtems_id task_id;
0412   Thread_Control *executing;
0413   Scheduler_SMP_Node *executing_node;
0414   Thread_Control *other;
0415   size_t i;
0416   size_t j;
0417 
0418   task_id = start_task(2);
0419   executing = _Thread_Get_executing();
0420   executing_node = get_scheduler_node(executing);
0421 
0422   other = get_thread_by_id(task_id);
0423 
0424   for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) {
0425     for (j = 0; j < RTEMS_ARRAY_SIZE(states); ++j) {
0426       if (
0427         states[i] != SCHEDULER_SMP_NODE_READY
0428           || states[j] != SCHEDULER_SMP_NODE_SCHEDULED
0429       ) {
0430         test_case_yield_op(
0431           executing,
0432           executing_node,
0433           other,
0434           states[i],
0435           states[j]
0436         );
0437       }
0438     }
0439   }
0440 
0441   sc = rtems_task_delete(task_id);
0442   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0443 }
0444 
0445 static void block_op(
0446   Thread_Control *thread,
0447   Scheduler_SMP_Node *scheduler_node
0448 )
0449 {
0450   const Scheduler_Control *scheduler;
0451   ISR_lock_Context state_lock_context;
0452   ISR_lock_Context scheduler_lock_context;
0453 
0454   _Thread_State_acquire( thread, &state_lock_context );
0455   scheduler = _Thread_Scheduler_get_home( thread );
0456   _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
0457 
0458   (*scheduler->Operations.block)(scheduler, thread, &scheduler_node->Base);
0459 
0460   _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
0461   _Thread_State_release( thread, &state_lock_context );
0462 }
0463 
0464 static void unblock_op(
0465   Thread_Control *thread,
0466   Scheduler_SMP_Node *scheduler_node
0467 )
0468 {
0469   const Scheduler_Control *scheduler;
0470   ISR_lock_Context state_lock_context;
0471   ISR_lock_Context scheduler_lock_context;
0472 
0473   _Thread_State_acquire( thread, &state_lock_context );
0474   scheduler = _Thread_Scheduler_get_home( thread );
0475   _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
0476 
0477   (*scheduler->Operations.unblock)(
0478     scheduler,
0479     thread,
0480     &scheduler_node->Base
0481   );
0482 
0483   _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
0484   _Thread_State_release( thread, &state_lock_context );
0485 }
0486 
0487 static void test_case_unblock_op(
0488   Thread_Control *executing,
0489   Scheduler_SMP_Node *executing_node,
0490   Thread_Control *other,
0491   Scheduler_SMP_Node_state new_state
0492 )
0493 {
0494   Per_CPU_Control *cpu_self;
0495 
0496   cpu_self = _Thread_Dispatch_disable();
0497 
0498   switch (new_state) {
0499     case SCHEDULER_SMP_NODE_SCHEDULED:
0500       change_priority(executing, 2, PRIORITY_GROUP_LAST);
0501       rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
0502       break;
0503     case SCHEDULER_SMP_NODE_READY:
0504       change_priority(executing, 4, PRIORITY_GROUP_LAST);
0505       rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_READY);
0506       break;
0507     default:
0508       rtems_test_assert(0);
0509       break;
0510   }
0511 
0512   block_op(executing, executing_node);
0513   rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_BLOCKED);
0514 
0515   unblock_op(executing, executing_node);
0516   rtems_test_assert(executing_node->state == new_state);
0517 
0518   switch (new_state) {
0519     case SCHEDULER_SMP_NODE_SCHEDULED:
0520     case SCHEDULER_SMP_NODE_READY:
0521       break;
0522     default:
0523       rtems_test_assert(0);
0524       break;
0525   }
0526 
0527   change_priority(executing, 1, PRIORITY_GROUP_FIRST);
0528   rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
0529 
0530   _Thread_Dispatch_enable( cpu_self );
0531 }
0532 
0533 static void test_unblock_op(void)
0534 {
0535   rtems_status_code sc;
0536   rtems_id task_id;
0537   Thread_Control *executing;
0538   Scheduler_SMP_Node *executing_node;
0539   Thread_Control *other;
0540   size_t i;
0541 
0542   task_id = start_task(3);
0543   executing = _Thread_Get_executing();
0544   executing_node = get_scheduler_node(executing);
0545 
0546   other = get_thread_by_id(task_id);
0547 
0548   for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) {
0549     test_case_unblock_op(
0550       executing,
0551       executing_node,
0552       other,
0553       states[i]
0554     );
0555   }
0556 
0557   sc = rtems_task_delete(task_id);
0558   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0559 }
0560 
0561 void Init(rtems_task_argument arg)
0562 {
0563   rtems_resource_snapshot snapshot;
0564   rtems_status_code sc;
0565   rtems_id task_id;
0566 
0567   TEST_BEGIN();
0568 
0569   rtems_resource_snapshot_take(&snapshot);
0570 
0571   sc = rtems_task_create(
0572     rtems_build_name('T', 'A', 'S', 'K'),
0573     255,
0574     RTEMS_MINIMUM_STACK_SIZE,
0575     RTEMS_DEFAULT_MODES,
0576     RTEMS_DEFAULT_ATTRIBUTES,
0577     &task_id
0578   );
0579   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0580 
0581   test_change_priority();
0582   test_update_priority_op();
0583   test_yield_op();
0584   test_unblock_op();
0585 
0586   sc = rtems_task_delete(task_id);
0587   rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0588 
0589   rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
0590 
0591   TEST_END();
0592   rtems_test_exit(0);
0593 }