source: rtems/cpukit/score/src/mpci.c

Last change on this file was 1ac4a85, checked in by Sebastian Huber <sebastian.huber@…>, on Feb 25, 2021 at 6:08:52 PM

score: Fix thread initialization

Close the thread object if a thread create extension fails. Also call
the delete extension to avoid resource leaks in early extensions if a
late extension fails.

Close #4270.

  • Property mode set to 100644
File size: 12.6 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSScoreMPCI
5 *
6 * @brief This source file contains the definition of
7 *   ::_System_state_Is_multiprocessing, ::_MPCI_Semaphore,
8 *   ::_MPCI_Remote_blocked_threads, ::_MPCI_table, ::_MPCI_Receive_server_tcb,
9 *   ::_MPCI_Packet_processors and the implementation of
10 *   _MPCI_Register_packet_processor(), _MPCI_Get_packet(),
11 *   _MPCI_Send_process_packet(), _MPCI_Send_request_packet(),
12 *   _MPCI_Send_response_packet(), _MPCI_Receive_packet(),
13 *   _MPCI_Process_response(), _MPCI_Receive_server(), _MPCI_Announce(),
14 *   _MPCI_Internal_packets_Send_process_packet(),
15 *   _MPCI_Internal_packets_Process_packet(),
16 *   _MPCI_Internal_packets_Get_packet(), and the MPCI Handler system
17 *   initialization.
18 */
19
20/*
21 *  COPYRIGHT (c) 1989-2014.
22 *  On-Line Applications Research Corporation (OAR).
23 *
24 *  The license and distribution terms for this file may be
25 *  found in the file LICENSE in this distribution or at
26 *  http://www.rtems.org/license/LICENSE.
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <rtems/score/mpciimpl.h>
34#include <rtems/score/coresemimpl.h>
35#include <rtems/score/interr.h>
36#include <rtems/score/objectmp.h>
37#include <rtems/score/stackimpl.h>
38#include <rtems/score/sysstate.h>
39#include <rtems/score/schedulerimpl.h>
40#include <rtems/score/threadimpl.h>
41#include <rtems/score/threadqimpl.h>
42#include <rtems/sysinit.h>
43
44#include <string.h>
45
46RTEMS_STATIC_ASSERT(
47  sizeof(MPCI_Internal_packet) <= MP_PACKET_MINIMUM_PACKET_SIZE,
48  MPCI_Internal_packet
49);
50
51#define MPCI_SEMAPHORE_TQ_OPERATIONS &_Thread_queue_Operations_FIFO
52
53bool _System_state_Is_multiprocessing;
54
55/**
56 *  This is the core semaphore which the MPCI Receive Server blocks on.
57 */
58CORE_semaphore_Control _MPCI_Semaphore;
59
60Thread_queue_Control _MPCI_Remote_blocked_threads =
61  THREAD_QUEUE_INITIALIZER( "MPCI Remote Blocked Threads" );
62
63MPCI_Control *_MPCI_table;
64
65Thread_Control *_MPCI_Receive_server_tcb;
66
67MPCI_Packet_processor _MPCI_Packet_processors[ MP_PACKET_CLASSES_LAST + 1 ];
68
69static void _MPCI_Handler_early_initialization( void )
70{
71  /*
72   *  Initialize the system state based on whether this is an MP system.
73   *  In an MP configuration, internally we view single processor
74   *  systems as a very restricted multiprocessor system.
75   */
76  if ( _MPCI_Configuration.maximum_nodes > 1 ) {
77    _System_state_Is_multiprocessing = true;
78  }
79
80  _Objects_MP_Handler_early_initialization();
81}
82
83static void _MPCI_Handler_initialization( void )
84{
85  MPCI_Control               *users_mpci_table;
86
87  _Objects_MP_Handler_initialization();
88
89  users_mpci_table = _MPCI_Configuration.User_mpci_table;
90
91  if ( _System_state_Is_multiprocessing && !users_mpci_table )
92    _Internal_error( INTERNAL_ERROR_NO_MPCI );
93
94  _MPCI_table = users_mpci_table;
95
96  if ( !_System_state_Is_multiprocessing )
97    return;
98
99  /*
100   *  Register the MP Process Packet routine.
101   */
102
103  _MPCI_Register_packet_processor(
104    MP_PACKET_MPCI_INTERNAL,
105    _MPCI_Internal_packets_Process_packet
106  );
107
108  /*
109   *  Create the counting semaphore used by the MPCI Receive Server.
110   */
111
112  _CORE_semaphore_Initialize(
113    &_MPCI_Semaphore,
114    0                         /* initial_value */
115  );
116}
117
118static void _MPCI_Create_server( void )
119{
120  Thread_Entry_information entry = {
121    .adaptor = _Thread_Entry_adaptor_numeric,
122    .Kinds = {
123      .Numeric = {
124        .entry = _MPCI_Receive_server
125      }
126    }
127  };
128  Thread_Configuration config;
129  Status_Control       status;
130  ISR_lock_Context     lock_context;
131
132
133  if ( !_System_state_Is_multiprocessing )
134    return;
135
136  /*
137   *  Initialize the MPCI Receive Server
138   */
139
140  _MPCI_Receive_server_tcb = _Thread_Internal_allocate();
141  _Assert( _MPCI_Receive_server_tcb != NULL );
142
143  memset( &config, 0, sizeof( config ) );
144  config.scheduler = &_Scheduler_Table[ 0 ];
145  config.name = _Objects_Build_name( 'M', 'P', 'C', 'I' );
146  config.priority = PRIORITY_PSEUDO_ISR;
147  config.budget_algorithm = THREAD_CPU_BUDGET_ALGORITHM_NONE;
148  config.is_fp = CPU_ALL_TASKS_ARE_FP;
149  config.stack_size = _Stack_Minimum()
150    + _MPCI_Configuration.extra_mpci_receive_server_stack
151    + CPU_MPCI_RECEIVE_SERVER_EXTRA_STACK
152    + CPU_ALL_TASKS_ARE_FP * CONTEXT_FP_SIZE;
153  config.stack_area = _MPCI_Receive_server_stack;
154
155  status = _Thread_Initialize(
156    &_Thread_Information,
157    _MPCI_Receive_server_tcb,
158    &config
159  );
160  _Assert_Unused_variable_equals( status, STATUS_SUCCESSFUL );
161
162  _ISR_lock_ISR_disable( &lock_context );
163  _Thread_Start( _MPCI_Receive_server_tcb, &entry, &lock_context );
164}
165
166static void _MPCI_Initialization( void )
167{
168  (*_MPCI_table->initialization)();
169}
170
171void _MPCI_Register_packet_processor(
172  MP_packet_Classes      the_class,
173  MPCI_Packet_processor  the_packet_processor
174
175)
176{
177  _MPCI_Packet_processors[ the_class ] = the_packet_processor;
178}
179
180MP_packet_Prefix *_MPCI_Get_packet ( void )
181{
182  MP_packet_Prefix  *the_packet;
183
184  (*_MPCI_table->get_packet)( &the_packet );
185
186  if ( the_packet == NULL )
187    _Internal_error( INTERNAL_ERROR_OUT_OF_PACKETS );
188
189  /*
190   *  Put in a default timeout that will be used for
191   *  all packets that do not otherwise have a timeout.
192   */
193
194  the_packet->timeout = MPCI_DEFAULT_TIMEOUT;
195
196  return the_packet;
197}
198
199void _MPCI_Return_packet (
200  MP_packet_Prefix   *the_packet
201)
202{
203  (*_MPCI_table->return_packet)( the_packet );
204}
205
206void _MPCI_Send_process_packet (
207  uint32_t            destination,
208  MP_packet_Prefix   *the_packet
209)
210{
211  the_packet->source_tid = _Thread_Executing->Object.id;
212  the_packet->to_convert =
213     ( the_packet->to_convert - sizeof(MP_packet_Prefix) ) / sizeof(uint32_t);
214
215  (*_MPCI_table->send_packet)( destination, the_packet );
216}
217
218static void _MPCI_Enqueue_callout(
219  Thread_queue_Queue     *queue,
220  Thread_Control         *the_thread,
221  struct Per_CPU_Control *cpu_self,
222  Thread_queue_Context   *queue_context
223)
224{
225  _Thread_queue_Add_timeout_ticks( queue, the_thread, cpu_self, queue_context );
226  _Thread_Dispatch_unnest( cpu_self );
227}
228
229Status_Control _MPCI_Send_request_packet(
230  uint32_t          destination,
231  MP_packet_Prefix *the_packet,
232  States_Control    extra_state
233)
234{
235  Per_CPU_Control      *cpu_self;
236  Thread_queue_Context  queue_context;
237  Thread_Control       *executing;
238
239  /*
240   *  See if we need a default timeout
241   */
242
243  if (the_packet->timeout == MPCI_DEFAULT_TIMEOUT)
244      the_packet->timeout = _MPCI_table->default_timeout;
245
246  _Thread_queue_Context_initialize( &queue_context );
247  _Thread_queue_Context_set_thread_state(
248    &queue_context,
249    STATES_WAITING_FOR_RPC_REPLY | extra_state
250  );
251  _Thread_queue_Context_set_timeout_ticks( &queue_context, the_packet->timeout );
252  _Thread_queue_Context_set_enqueue_callout(
253    &queue_context,
254    _MPCI_Enqueue_callout
255  );
256
257  cpu_self = _Thread_Dispatch_disable();
258
259  executing = _Per_CPU_Get_executing( cpu_self );
260  executing->Wait.remote_id = the_packet->id;
261
262  the_packet->source_tid      = executing->Object.id;
263  the_packet->source_priority = _Thread_Get_priority( executing );
264  the_packet->to_convert =
265     ( the_packet->to_convert - sizeof(MP_packet_Prefix) ) / sizeof(uint32_t);
266
267  (*_MPCI_table->send_packet)( destination, the_packet );
268
269  _Thread_queue_Acquire( &_MPCI_Remote_blocked_threads, &queue_context );
270  _Thread_queue_Enqueue(
271    &_MPCI_Remote_blocked_threads.Queue,
272    &_Thread_queue_Operations_FIFO,
273    executing,
274    &queue_context
275  );
276  return _Thread_Wait_get_status( executing );
277}
278
279void _MPCI_Send_response_packet (
280  uint32_t            destination,
281  MP_packet_Prefix   *the_packet
282)
283{
284  the_packet->source_tid = _Thread_Executing->Object.id;
285
286  (*_MPCI_table->send_packet)( destination, the_packet );
287}
288
289MP_packet_Prefix  *_MPCI_Receive_packet ( void )
290{
291  MP_packet_Prefix  *the_packet;
292
293  (*_MPCI_table->receive_packet)( &the_packet );
294
295  return the_packet;
296}
297
298Thread_Control *_MPCI_Process_response (
299  MP_packet_Prefix  *the_packet
300)
301{
302  ISR_lock_Context  lock_context;
303  Thread_Control   *the_thread;
304
305  the_thread = _Thread_Get( the_packet->id, &lock_context );
306  _Assert( the_thread != NULL );
307
308  /*
309   * FIXME: This is broken on SMP, see https://devel.rtems.org/ticket/2703.
310   *
311   * Should use _Thread_queue_Extract_critical() instead with a handler
312   * function provided by the caller of _MPCI_Process_response().  Similar to
313   * the filter function in _Thread_queue_Flush_critical().
314   */
315  _ISR_lock_ISR_enable( &lock_context );
316  _Thread_queue_Extract( the_thread );
317  the_thread->Wait.return_code = the_packet->return_code;
318  return the_thread;
319}
320
321/*
322 *  _MPCI_Receive_server
323 *
324 */
325
326void _MPCI_Receive_server(
327  Thread_Entry_numeric_type ignored
328)
329{
330
331  MP_packet_Prefix      *the_packet;
332  MPCI_Packet_processor  the_function;
333  Thread_Control        *executing;
334  Thread_queue_Context   queue_context;
335
336  executing = _Thread_Get_executing();
337  _Thread_queue_Context_initialize( &queue_context );
338  _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context );
339
340  for ( ; ; ) {
341
342    executing->receive_packet = NULL;
343
344    _ISR_lock_ISR_disable( &queue_context.Lock_context.Lock_context );
345    _CORE_semaphore_Seize(
346      &_MPCI_Semaphore,
347      MPCI_SEMAPHORE_TQ_OPERATIONS,
348      executing,
349      true,
350      &queue_context
351    );
352
353    for ( ; ; ) {
354      executing->receive_packet = NULL;
355
356      the_packet = _MPCI_Receive_packet();
357
358      if ( !the_packet )
359        break;
360
361      executing->receive_packet = the_packet;
362
363      if ( !_Mp_packet_Is_valid_packet_class ( the_packet->the_class ) )
364        break;
365
366      the_function = _MPCI_Packet_processors[ the_packet->the_class ];
367
368      if ( !the_function )
369        _Internal_error( INTERNAL_ERROR_BAD_PACKET );
370
371       (*the_function)( the_packet );
372    }
373  }
374}
375
376void _MPCI_Announce ( void )
377{
378  Thread_queue_Context queue_context;
379
380  _ISR_lock_ISR_disable( &queue_context.Lock_context.Lock_context );
381  (void) _CORE_semaphore_Surrender(
382    &_MPCI_Semaphore,
383    MPCI_SEMAPHORE_TQ_OPERATIONS,
384    UINT32_MAX,
385    &queue_context
386  );
387}
388
389void _MPCI_Internal_packets_Send_process_packet (
390   MPCI_Internal_Remote_operations operation
391)
392{
393  MPCI_Internal_packet *the_packet;
394
395  switch ( operation ) {
396
397    case MPCI_PACKETS_SYSTEM_VERIFY:
398
399      the_packet                    = _MPCI_Internal_packets_Get_packet();
400      the_packet->Prefix.the_class  = MP_PACKET_MPCI_INTERNAL;
401      the_packet->Prefix.length     = sizeof ( MPCI_Internal_packet );
402      the_packet->Prefix.to_convert = sizeof ( MPCI_Internal_packet );
403      the_packet->operation         = operation;
404
405      the_packet->maximum_nodes = _Objects_Maximum_nodes;
406
407      the_packet->maximum_global_objects = _Objects_MP_Maximum_global_objects;
408
409      _MPCI_Send_process_packet( MPCI_ALL_NODES, &the_packet->Prefix );
410      break;
411  }
412}
413
414/*
415 *  _MPCI_Internal_packets_Send_request_packet
416 *
417 *  This subprogram is not needed since there are no request
418 *  packets to be sent by this manager.
419 *
420 */
421
422/*
423 *  _MPCI_Internal_packets_Send_response_packet
424 *
425 *  This subprogram is not needed since there are no response
426 *  packets to be sent by this manager.
427 *
428 */
429
430void _MPCI_Internal_packets_Process_packet (
431  MP_packet_Prefix  *the_packet_prefix
432)
433{
434  MPCI_Internal_packet *the_packet;
435  uint32_t                    maximum_nodes;
436  uint32_t                    maximum_global_objects;
437
438  the_packet = (MPCI_Internal_packet *) the_packet_prefix;
439
440  switch ( the_packet->operation ) {
441
442    case MPCI_PACKETS_SYSTEM_VERIFY:
443
444      maximum_nodes          = the_packet->maximum_nodes;
445      maximum_global_objects = the_packet->maximum_global_objects;
446      if ( maximum_nodes != _Objects_Maximum_nodes ||
447           maximum_global_objects != _Objects_MP_Maximum_global_objects ) {
448
449        _MPCI_Return_packet( the_packet_prefix );
450
451        _Internal_error( INTERNAL_ERROR_INCONSISTENT_MP_INFORMATION );
452      }
453
454      _MPCI_Return_packet( the_packet_prefix );
455
456      break;
457  }
458}
459
460/*
461 *  _MPCI_Internal_packets_Send_object_was_deleted
462 *
463 *  This subprogram is not needed since there are no objects
464 *  deleted by this manager.
465 *
466 */
467
468/*
469 *  _MPCI_Internal_packets_Send_extract_proxy
470 *
471 *  This subprogram is not needed since there are no objects
472 *  deleted by this manager.
473 *
474 */
475
476MPCI_Internal_packet *_MPCI_Internal_packets_Get_packet ( void )
477{
478  return ( (MPCI_Internal_packet *) _MPCI_Get_packet() );
479}
480
481static void _MPCI_Finalize( void )
482{
483  if ( _System_state_Is_multiprocessing ) {
484    _MPCI_Initialization();
485    _MPCI_Internal_packets_Send_process_packet( MPCI_PACKETS_SYSTEM_VERIFY );
486  }
487}
488
489RTEMS_SYSINIT_ITEM(
490  _MPCI_Handler_early_initialization,
491  RTEMS_SYSINIT_MP_EARLY,
492  RTEMS_SYSINIT_ORDER_MIDDLE
493);
494
495RTEMS_SYSINIT_ITEM(
496  _MPCI_Handler_initialization,
497  RTEMS_SYSINIT_MP,
498  RTEMS_SYSINIT_ORDER_MIDDLE
499);
500
501RTEMS_SYSINIT_ITEM(
502  _MPCI_Create_server,
503  RTEMS_SYSINIT_MP_SERVER,
504  RTEMS_SYSINIT_ORDER_MIDDLE
505);
506
507RTEMS_SYSINIT_ITEM(
508  _MPCI_Finalize,
509  RTEMS_SYSINIT_MP_FINALIZE,
510  RTEMS_SYSINIT_ORDER_MIDDLE
511);
512
513/* end of file */
Note: See TracBrowser for help on using the repository browser.