1 | /* SPDX-License-Identifier: BSD-2-Clause */ |
---|
2 | |
---|
3 | /** |
---|
4 | * @file |
---|
5 | * |
---|
6 | * @ingroup ScoreThreadValSmp |
---|
7 | */ |
---|
8 | |
---|
9 | /* |
---|
10 | * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) |
---|
11 | * |
---|
12 | * Redistribution and use in source and binary forms, with or without |
---|
13 | * modification, are permitted provided that the following conditions |
---|
14 | * are met: |
---|
15 | * 1. Redistributions of source code must retain the above copyright |
---|
16 | * notice, this list of conditions and the following disclaimer. |
---|
17 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
18 | * notice, this list of conditions and the following disclaimer in the |
---|
19 | * documentation and/or other materials provided with the distribution. |
---|
20 | * |
---|
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
---|
25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
31 | * POSSIBILITY OF SUCH DAMAGE. |
---|
32 | */ |
---|
33 | |
---|
34 | /* |
---|
35 | * This file is part of the RTEMS quality process and was automatically |
---|
36 | * generated. If you find something that needs to be fixed or |
---|
37 | * worded better please post a report or patch to an RTEMS mailing list |
---|
38 | * or raise a bug report: |
---|
39 | * |
---|
40 | * https://www.rtems.org/bugs.html |
---|
41 | * |
---|
42 | * For information on updating and regenerating please refer to the How-To |
---|
43 | * section in the Software Requirements Engineering chapter of the |
---|
44 | * RTEMS Software Engineering manual. The manual is provided as a part of |
---|
45 | * a release. For development sources please refer to the online |
---|
46 | * documentation at: |
---|
47 | * |
---|
48 | * https://docs.rtems.org |
---|
49 | */ |
---|
50 | |
---|
51 | #ifdef HAVE_CONFIG_H |
---|
52 | #include "config.h" |
---|
53 | #endif |
---|
54 | |
---|
55 | #include <rtems.h> |
---|
56 | #include <rtems/test-scheduler.h> |
---|
57 | #include <rtems/score/smpbarrier.h> |
---|
58 | #include <rtems/score/threadimpl.h> |
---|
59 | |
---|
60 | #include "ts-config.h" |
---|
61 | #include "tx-support.h" |
---|
62 | |
---|
63 | #include <rtems/test.h> |
---|
64 | |
---|
65 | /** |
---|
66 | * @defgroup ScoreThreadValSmp spec:/score/thread/val/smp |
---|
67 | * |
---|
68 | * @ingroup TestsuitesValidationSmpOnly0 |
---|
69 | * |
---|
70 | * @brief Tests SMP-specific thread behaviour. |
---|
71 | * |
---|
72 | * This test case performs the following actions: |
---|
73 | * |
---|
74 | * - Create three worker threads and a mutex. Use the mutex and the worker to |
---|
75 | * move to a helping scheduler. |
---|
76 | * |
---|
77 | * - Pin the runner thread while it executes on a processor owned by a |
---|
78 | * helping scheduler. |
---|
79 | * |
---|
80 | * - Pin and unpin the runner thread. This is a nested operation. |
---|
81 | * |
---|
82 | * - Preempt the pinned runner thread. Worker B and C execute at the same |
---|
83 | * time on processor 0 and 1 respectively for some point in time. This |
---|
84 | * shows that the pinning of the runner thread is maintained. |
---|
85 | * |
---|
86 | * - Unpin the runner thread. The runner moves back to its home scheduler. |
---|
87 | * |
---|
88 | * - Release the mutex. |
---|
89 | * |
---|
90 | * - Pin the runner thread. Unpin the runner thread while it is suspended. |
---|
91 | * |
---|
92 | * - Make sure the worker released the mutex. |
---|
93 | * |
---|
94 | * - Clean up all used resources. |
---|
95 | * |
---|
96 | * - Create three worker threads and a mutex. Use the mutex and the worker to |
---|
97 | * check that a suspended thread does not reconsider help requests. |
---|
98 | * |
---|
99 | * - Let worker B help worker A through the mutex. Preempt worker A. Delay |
---|
100 | * the thread switch to worker A. |
---|
101 | * |
---|
102 | * - Suspend worker A and let it wait on its thread state lock. Check that |
---|
103 | * worker A did not reconsider help requests. |
---|
104 | * |
---|
105 | * - Resume worker A. Check that worker A did reconsider help requests after |
---|
106 | * the thread dispatch. |
---|
107 | * |
---|
108 | * - Clean up all used resources. |
---|
109 | * |
---|
110 | * @{ |
---|
111 | */ |
---|
112 | |
---|
113 | /** |
---|
114 | * @brief Test context for spec:/score/thread/val/smp test case. |
---|
115 | */ |
---|
116 | typedef struct { |
---|
117 | /** |
---|
118 | * @brief This member contains the worker A identifier. |
---|
119 | */ |
---|
120 | rtems_id worker_a_id; |
---|
121 | |
---|
122 | /** |
---|
123 | * @brief This member contains the worker B identifier. |
---|
124 | */ |
---|
125 | rtems_id worker_b_id; |
---|
126 | |
---|
127 | /** |
---|
128 | * @brief This member contains the worker C identifier. |
---|
129 | */ |
---|
130 | rtems_id worker_c_id; |
---|
131 | |
---|
132 | /** |
---|
133 | * @brief This member contains the mutex identifier. |
---|
134 | */ |
---|
135 | rtems_id mutex_id; |
---|
136 | |
---|
137 | /** |
---|
138 | * @brief If this member is true, then the worker shall busy wait. |
---|
139 | */ |
---|
140 | volatile bool busy; |
---|
141 | |
---|
142 | /** |
---|
143 | * @brief This member contains a counter for EVENT_COUNT. |
---|
144 | */ |
---|
145 | volatile uint32_t counter; |
---|
146 | |
---|
147 | /** |
---|
148 | * @brief This member contains the barrier to synchronize the runner and the |
---|
149 | * workers. |
---|
150 | */ |
---|
151 | SMP_barrier_Control barrier; |
---|
152 | |
---|
153 | /** |
---|
154 | * @brief This member contains the barrier state for the runner processor. |
---|
155 | */ |
---|
156 | SMP_barrier_State barrier_state; |
---|
157 | } ScoreThreadValSmp_Context; |
---|
158 | |
---|
159 | static ScoreThreadValSmp_Context |
---|
160 | ScoreThreadValSmp_Instance; |
---|
161 | |
---|
162 | #define EVENT_OBTAIN RTEMS_EVENT_0 |
---|
163 | |
---|
164 | #define EVENT_RELEASE RTEMS_EVENT_1 |
---|
165 | |
---|
166 | #define EVENT_COUNT_EARLY RTEMS_EVENT_2 |
---|
167 | |
---|
168 | #define EVENT_BUSY RTEMS_EVENT_3 |
---|
169 | |
---|
170 | #define EVENT_COUNT RTEMS_EVENT_4 |
---|
171 | |
---|
172 | #define EVENT_LET_WORKER_C_COUNT RTEMS_EVENT_5 |
---|
173 | |
---|
174 | #define EVENT_SET_TASK_SWITCH_EXTENSION RTEMS_EVENT_6 |
---|
175 | |
---|
176 | typedef ScoreThreadValSmp_Context Context; |
---|
177 | |
---|
178 | static void TaskSwitchExtension( rtems_tcb *executing, rtems_tcb *heir ) |
---|
179 | { |
---|
180 | Context *ctx; |
---|
181 | Thread_Control *thread; |
---|
182 | |
---|
183 | (void) executing; |
---|
184 | (void) heir; |
---|
185 | |
---|
186 | ctx = T_fixture_context(); |
---|
187 | thread = GetThread( ctx->worker_a_id ); |
---|
188 | |
---|
189 | if ( thread == heir ) { |
---|
190 | SMP_barrier_State state; |
---|
191 | |
---|
192 | _SMP_barrier_State_initialize( &state ); |
---|
193 | |
---|
194 | /* B0 */ |
---|
195 | _SMP_barrier_Wait( &ctx->barrier, &state, 2 ); |
---|
196 | |
---|
197 | /* B1 */ |
---|
198 | _SMP_barrier_Wait( &ctx->barrier, &state, 2 ); |
---|
199 | } |
---|
200 | } |
---|
201 | |
---|
202 | static void WorkerTask( rtems_task_argument arg ) |
---|
203 | { |
---|
204 | Context *ctx; |
---|
205 | |
---|
206 | ctx = (Context *) arg; |
---|
207 | |
---|
208 | while ( true ) { |
---|
209 | rtems_event_set events; |
---|
210 | |
---|
211 | events = ReceiveAnyEvents(); |
---|
212 | |
---|
213 | if ( ( events & EVENT_OBTAIN ) != 0 ) { |
---|
214 | ObtainMutex( ctx->mutex_id ); |
---|
215 | } |
---|
216 | |
---|
217 | if ( ( events & EVENT_RELEASE ) != 0 ) { |
---|
218 | ReleaseMutex( ctx->mutex_id ); |
---|
219 | } |
---|
220 | |
---|
221 | if ( ( events & EVENT_COUNT_EARLY ) != 0 ) { |
---|
222 | ++ctx->counter; |
---|
223 | } |
---|
224 | |
---|
225 | if ( ( events & EVENT_BUSY ) != 0 ) { |
---|
226 | while ( ctx->busy ) { |
---|
227 | /* Do nothing */ |
---|
228 | } |
---|
229 | } |
---|
230 | |
---|
231 | if ( ( events & EVENT_COUNT ) != 0 ) { |
---|
232 | ++ctx->counter; |
---|
233 | } |
---|
234 | |
---|
235 | if ( ( events & EVENT_LET_WORKER_C_COUNT ) != 0 ) { |
---|
236 | uint32_t counter; |
---|
237 | |
---|
238 | counter = ctx->counter; |
---|
239 | SendEvents( ctx->worker_c_id, EVENT_COUNT ); |
---|
240 | |
---|
241 | while ( ctx->counter == counter ) { |
---|
242 | /* Wait */ |
---|
243 | } |
---|
244 | } |
---|
245 | |
---|
246 | if ( ( events & EVENT_SET_TASK_SWITCH_EXTENSION ) != 0 ) { |
---|
247 | SetTaskSwitchExtension( TaskSwitchExtension ); |
---|
248 | } |
---|
249 | } |
---|
250 | } |
---|
251 | |
---|
252 | static void SchedulerBlock( |
---|
253 | void *arg, |
---|
254 | const T_scheduler_event *event, |
---|
255 | T_scheduler_when when |
---|
256 | ) |
---|
257 | { |
---|
258 | Context *ctx; |
---|
259 | |
---|
260 | ctx = arg; |
---|
261 | |
---|
262 | if ( |
---|
263 | when == T_SCHEDULER_BEFORE && |
---|
264 | event->operation == T_SCHEDULER_BLOCK |
---|
265 | ) { |
---|
266 | Thread_Control *thread; |
---|
267 | |
---|
268 | T_scheduler_set_event_handler( NULL, NULL ); |
---|
269 | |
---|
270 | /* B1 */ |
---|
271 | _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 ); |
---|
272 | |
---|
273 | thread = GetThread( ctx->worker_a_id ); |
---|
274 | TicketLockWaitForOthers( &thread->Join_queue.Queue.Lock, 1 ); |
---|
275 | } |
---|
276 | } |
---|
277 | |
---|
278 | static void Suspend( void *arg ) |
---|
279 | { |
---|
280 | Thread_Control *thread; |
---|
281 | |
---|
282 | thread = arg; |
---|
283 | SuspendTask( thread->Object.id ); |
---|
284 | } |
---|
285 | |
---|
286 | static void Resume( void *arg ) |
---|
287 | { |
---|
288 | Thread_Control *thread; |
---|
289 | |
---|
290 | thread = arg; |
---|
291 | ResumeTask( thread->Object.id ); |
---|
292 | } |
---|
293 | |
---|
294 | static void WaitForCounter( const Context *ctx, uint32_t expected ) |
---|
295 | { |
---|
296 | while ( ctx->counter != expected ) { |
---|
297 | /* Wait */ |
---|
298 | } |
---|
299 | } |
---|
300 | |
---|
301 | static void ScoreThreadValSmp_Setup( ScoreThreadValSmp_Context *ctx ) |
---|
302 | { |
---|
303 | SetSelfPriority( PRIO_NORMAL ); |
---|
304 | } |
---|
305 | |
---|
306 | static void ScoreThreadValSmp_Setup_Wrap( void *arg ) |
---|
307 | { |
---|
308 | ScoreThreadValSmp_Context *ctx; |
---|
309 | |
---|
310 | ctx = arg; |
---|
311 | ScoreThreadValSmp_Setup( ctx ); |
---|
312 | } |
---|
313 | |
---|
314 | static void ScoreThreadValSmp_Teardown( ScoreThreadValSmp_Context *ctx ) |
---|
315 | { |
---|
316 | RestoreRunnerPriority(); |
---|
317 | } |
---|
318 | |
---|
319 | static void ScoreThreadValSmp_Teardown_Wrap( void *arg ) |
---|
320 | { |
---|
321 | ScoreThreadValSmp_Context *ctx; |
---|
322 | |
---|
323 | ctx = arg; |
---|
324 | ScoreThreadValSmp_Teardown( ctx ); |
---|
325 | } |
---|
326 | |
---|
327 | static T_fixture ScoreThreadValSmp_Fixture = { |
---|
328 | .setup = ScoreThreadValSmp_Setup_Wrap, |
---|
329 | .stop = NULL, |
---|
330 | .teardown = ScoreThreadValSmp_Teardown_Wrap, |
---|
331 | .scope = NULL, |
---|
332 | .initial_context = &ScoreThreadValSmp_Instance |
---|
333 | }; |
---|
334 | |
---|
335 | /** |
---|
336 | * @brief Create three worker threads and a mutex. Use the mutex and the |
---|
337 | * worker to move to a helping scheduler. |
---|
338 | */ |
---|
339 | static void ScoreThreadValSmp_Action_0( ScoreThreadValSmp_Context *ctx ) |
---|
340 | { |
---|
341 | Per_CPU_Control*cpu_self; |
---|
342 | Thread_Control *executing; |
---|
343 | |
---|
344 | executing = _Thread_Get_executing(); |
---|
345 | ctx->counter = 0; |
---|
346 | |
---|
347 | ctx->mutex_id = CreateMutex(); |
---|
348 | |
---|
349 | ctx->worker_a_id = CreateTask( "WRKA", PRIO_NORMAL ); |
---|
350 | SetScheduler( ctx->worker_a_id, SCHEDULER_B_ID, PRIO_NORMAL ); |
---|
351 | StartTask( ctx->worker_a_id, WorkerTask, ctx ); |
---|
352 | |
---|
353 | ctx->worker_b_id = CreateTask( "WRKB", PRIO_HIGH ); |
---|
354 | StartTask( ctx->worker_b_id, WorkerTask, ctx ); |
---|
355 | |
---|
356 | ctx->worker_c_id = CreateTask( "WRKC", PRIO_LOW ); |
---|
357 | StartTask( ctx->worker_c_id, WorkerTask, ctx ); |
---|
358 | |
---|
359 | ObtainMutex( ctx->mutex_id ); |
---|
360 | SendEvents( ctx->worker_a_id, EVENT_OBTAIN | EVENT_RELEASE ); |
---|
361 | |
---|
362 | ctx->busy = true; |
---|
363 | SendEvents( ctx->worker_b_id, EVENT_BUSY ); |
---|
364 | |
---|
365 | /* |
---|
366 | * Pin the runner thread while it executes on a processor owned by a helping |
---|
367 | * scheduler. |
---|
368 | */ |
---|
369 | T_eq_u32( rtems_scheduler_get_processor(), 1 ); |
---|
370 | _Thread_Pin( executing ); |
---|
371 | |
---|
372 | /* |
---|
373 | * Pin and unpin the runner thread. This is a nested operation. |
---|
374 | */ |
---|
375 | T_eq_u32( rtems_scheduler_get_processor(), 1 ); |
---|
376 | _Thread_Pin( executing ); |
---|
377 | _Thread_Unpin( executing, _Per_CPU_Get_snapshot() ); |
---|
378 | |
---|
379 | /* |
---|
380 | * Preempt the pinned runner thread. Worker B and C execute at the same time |
---|
381 | * on processor 0 and 1 respectively for some point in time. This shows that |
---|
382 | * the pinning of the runner thread is maintained. |
---|
383 | */ |
---|
384 | ctx->busy = false; |
---|
385 | SetScheduler( ctx->worker_b_id, SCHEDULER_B_ID, PRIO_HIGH ); |
---|
386 | SendEvents( ctx->worker_b_id, EVENT_LET_WORKER_C_COUNT ); |
---|
387 | |
---|
388 | T_eq_u32( rtems_scheduler_get_processor(), 1 ); |
---|
389 | T_eq_u32( ctx->counter, 1 ); |
---|
390 | |
---|
391 | /* |
---|
392 | * Unpin the runner thread. The runner moves back to its home scheduler. |
---|
393 | */ |
---|
394 | cpu_self = _Thread_Dispatch_disable(); |
---|
395 | _Thread_Unpin( executing, cpu_self ); |
---|
396 | _Thread_Dispatch_direct( cpu_self ); |
---|
397 | |
---|
398 | T_eq_u32( rtems_scheduler_get_processor(), 0 ); |
---|
399 | |
---|
400 | /* |
---|
401 | * Release the mutex. |
---|
402 | */ |
---|
403 | ReleaseMutex( ctx->mutex_id); |
---|
404 | T_eq_u32( rtems_scheduler_get_processor(), 0 ); |
---|
405 | |
---|
406 | /* |
---|
407 | * Pin the runner thread. Unpin the runner thread while it is suspended. |
---|
408 | */ |
---|
409 | _Thread_Pin( executing ); |
---|
410 | |
---|
411 | /* We have to preempt the runner to end up in _Thread_Do_unpin() */ |
---|
412 | SetPriority( ctx->worker_c_id, PRIO_HIGH ); |
---|
413 | SendEvents( ctx->worker_c_id, EVENT_COUNT ); |
---|
414 | T_eq_u32( ctx->counter, 2 ); |
---|
415 | |
---|
416 | cpu_self = _Thread_Dispatch_disable(); |
---|
417 | CallWithinISR( Suspend, executing ); |
---|
418 | _Thread_Unpin( executing, cpu_self ); |
---|
419 | CallWithinISR( Resume, executing ); |
---|
420 | _Thread_Dispatch_direct( cpu_self ); |
---|
421 | |
---|
422 | /* |
---|
423 | * Make sure the worker released the mutex. |
---|
424 | */ |
---|
425 | SetSelfScheduler( SCHEDULER_B_ID, PRIO_LOW ); |
---|
426 | SetSelfScheduler( SCHEDULER_A_ID, PRIO_NORMAL ); |
---|
427 | |
---|
428 | /* |
---|
429 | * Clean up all used resources. |
---|
430 | */ |
---|
431 | DeleteTask( ctx->worker_a_id ); |
---|
432 | DeleteTask( ctx->worker_b_id ); |
---|
433 | DeleteTask( ctx->worker_c_id ); |
---|
434 | DeleteMutex( ctx->mutex_id ); |
---|
435 | } |
---|
436 | |
---|
437 | /** |
---|
438 | * @brief Create three worker threads and a mutex. Use the mutex and the |
---|
439 | * worker to check that a suspended thread does not reconsider help requests. |
---|
440 | */ |
---|
441 | static void ScoreThreadValSmp_Action_1( ScoreThreadValSmp_Context *ctx ) |
---|
442 | { |
---|
443 | T_scheduler_log_10 scheduler_log; |
---|
444 | size_t index; |
---|
445 | const T_scheduler_event *event; |
---|
446 | |
---|
447 | _SMP_barrier_Control_initialize( &ctx->barrier ); |
---|
448 | _SMP_barrier_State_initialize( &ctx->barrier_state ); |
---|
449 | |
---|
450 | ctx->counter = 0; |
---|
451 | ctx->mutex_id = CreateMutex(); |
---|
452 | |
---|
453 | ctx->worker_a_id = CreateTask( "WRKA", PRIO_NORMAL ); |
---|
454 | SetScheduler( ctx->worker_a_id, SCHEDULER_B_ID, PRIO_NORMAL ); |
---|
455 | StartTask( ctx->worker_a_id, WorkerTask, ctx ); |
---|
456 | |
---|
457 | ctx->worker_b_id = CreateTask( "WRKB", PRIO_HIGH ); |
---|
458 | StartTask( ctx->worker_b_id, WorkerTask, ctx ); |
---|
459 | |
---|
460 | ctx->worker_c_id = CreateTask( "WRKC", PRIO_NORMAL ); |
---|
461 | SetScheduler( ctx->worker_c_id, SCHEDULER_B_ID, PRIO_HIGH ); |
---|
462 | StartTask( ctx->worker_c_id, WorkerTask, ctx ); |
---|
463 | |
---|
464 | /* |
---|
465 | * Let worker B help worker A through the mutex. Preempt worker A. Delay |
---|
466 | * the thread switch to worker A. |
---|
467 | */ |
---|
468 | ctx->busy = true; |
---|
469 | SendEvents( |
---|
470 | ctx->worker_a_id, |
---|
471 | EVENT_OBTAIN | EVENT_COUNT_EARLY | EVENT_BUSY | EVENT_COUNT |
---|
472 | ); |
---|
473 | WaitForCounter( ctx, 1 ); |
---|
474 | |
---|
475 | SendEvents( ctx->worker_b_id, EVENT_OBTAIN ); |
---|
476 | SetPriority( ctx->worker_b_id, PRIO_LOW ); |
---|
477 | SendEvents( ctx->worker_c_id, EVENT_SET_TASK_SWITCH_EXTENSION ); |
---|
478 | |
---|
479 | /* B0 */ |
---|
480 | _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 ); |
---|
481 | |
---|
482 | /* |
---|
483 | * Suspend worker A and let it wait on its thread state lock. Check that |
---|
484 | * worker A did not reconsider help requests. |
---|
485 | */ |
---|
486 | T_scheduler_record_10( &scheduler_log ); |
---|
487 | T_scheduler_set_event_handler( SchedulerBlock, ctx ); |
---|
488 | SuspendTask( ctx->worker_a_id ); |
---|
489 | WaitForExecutionStop( ctx->worker_a_id ); |
---|
490 | T_scheduler_record( NULL ); |
---|
491 | T_eq_sz( scheduler_log.header.recorded, 2 ); |
---|
492 | index = 0; |
---|
493 | event = T_scheduler_next_any( &scheduler_log.header, &index ); |
---|
494 | T_eq_int( event->operation, T_SCHEDULER_BLOCK ); |
---|
495 | event = T_scheduler_next_any( &scheduler_log.header, &index ); |
---|
496 | T_eq_int( event->operation, T_SCHEDULER_WITHDRAW_NODE ); |
---|
497 | event = T_scheduler_next_any( &scheduler_log.header, &index ); |
---|
498 | T_eq_ptr( event, &T_scheduler_event_null ); |
---|
499 | SetTaskSwitchExtension( NULL ); |
---|
500 | |
---|
501 | /* |
---|
502 | * Resume worker A. Check that worker A did reconsider help requests after |
---|
503 | * the thread dispatch. |
---|
504 | */ |
---|
505 | T_scheduler_record_10( &scheduler_log ); |
---|
506 | ResumeTask( ctx->worker_a_id ); |
---|
507 | ctx->busy = false; |
---|
508 | WaitForCounter( ctx, 2 ); |
---|
509 | WaitForExecutionStop( ctx->worker_a_id ); |
---|
510 | T_scheduler_record( NULL ); |
---|
511 | T_eq_sz( scheduler_log.header.recorded, 5 ); |
---|
512 | index = 0; |
---|
513 | event = T_scheduler_next_any( &scheduler_log.header, &index ); |
---|
514 | T_eq_int( event->operation, T_SCHEDULER_UNBLOCK ); |
---|
515 | event = T_scheduler_next_any( &scheduler_log.header, &index ); |
---|
516 | T_eq_int( event->operation, T_SCHEDULER_RECONSIDER_HELP_REQUEST ); |
---|
517 | event = T_scheduler_next_any( &scheduler_log.header, &index ); |
---|
518 | T_eq_int( event->operation, T_SCHEDULER_RECONSIDER_HELP_REQUEST ); |
---|
519 | event = T_scheduler_next_any( &scheduler_log.header, &index ); |
---|
520 | T_eq_int( event->operation, T_SCHEDULER_BLOCK ); |
---|
521 | event = T_scheduler_next_any( &scheduler_log.header, &index ); |
---|
522 | T_eq_int( event->operation, T_SCHEDULER_WITHDRAW_NODE ); |
---|
523 | event = T_scheduler_next_any( &scheduler_log.header, &index ); |
---|
524 | T_eq_ptr( event, &T_scheduler_event_null ); |
---|
525 | |
---|
526 | /* |
---|
527 | * Clean up all used resources. |
---|
528 | */ |
---|
529 | SendEvents( ctx->worker_a_id, EVENT_RELEASE | EVENT_COUNT ); |
---|
530 | WaitForCounter( ctx, 3 ); |
---|
531 | |
---|
532 | SetPriority( ctx->worker_b_id, PRIO_HIGH ); |
---|
533 | SendEvents( ctx->worker_b_id, EVENT_RELEASE ); |
---|
534 | |
---|
535 | DeleteTask( ctx->worker_a_id ); |
---|
536 | DeleteTask( ctx->worker_b_id ); |
---|
537 | DeleteTask( ctx->worker_c_id ); |
---|
538 | DeleteMutex( ctx->mutex_id ); |
---|
539 | } |
---|
540 | |
---|
541 | /** |
---|
542 | * @fn void T_case_body_ScoreThreadValSmp( void ) |
---|
543 | */ |
---|
544 | T_TEST_CASE_FIXTURE( ScoreThreadValSmp, &ScoreThreadValSmp_Fixture ) |
---|
545 | { |
---|
546 | ScoreThreadValSmp_Context *ctx; |
---|
547 | |
---|
548 | ctx = T_fixture_context(); |
---|
549 | |
---|
550 | ScoreThreadValSmp_Action_0( ctx ); |
---|
551 | ScoreThreadValSmp_Action_1( ctx ); |
---|
552 | } |
---|
553 | |
---|
554 | /** @} */ |
---|