source: rtems/cpukit/score/src/smpmulticastaction.c @ e90486a

5
Last change on this file since e90486a was e90486a, checked in by Sebastian Huber <sebastian.huber@…>, on 04/11/19 at 13:16:40

score: Rework SMP multicast action

Use a FIFO list of jobs per processor to carry out the SMP multicast
action. Use a done indicator per job to reduce the bus traffic a bit.

  • Property mode set to 100644
File size: 5.8 KB
Line 
1/*
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2019 embedded brains GmbH
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include <rtems/score/smpimpl.h>
33#include <rtems/score/assert.h>
34#include <rtems/score/threaddispatch.h>
35#include <rtems/score/sysstate.h>
36
37typedef struct Per_CPU_Job Per_CPU_Job;
38
39typedef struct Per_CPU_Jobs Per_CPU_Jobs;
40
41/**
42 * @brief A per-processor job.
43 */
44struct Per_CPU_Job {
45  union {
46    /**
47     * @brief The next job in the corresponding per-processor job list.
48     */
49    Per_CPU_Job *next;
50
51    /**
52     * @brief Indication if the job is done.
53     *
54     * A job is done if this member has the value one.  This assumes that one
55     * is not a valid pointer value.
56     */
57    Atomic_Ulong done;
58  };
59
60  /**
61   * @brief Back pointer to the jobs to get the handler and argument.
62   */
63  Per_CPU_Jobs *jobs;
64};
65
66/**
67 * @brief A collection of jobs, one for each processor.
68 */
69struct Per_CPU_Jobs {
70  /**
71   * @brief The job handler.
72   */
73  SMP_Action_handler handler;
74
75  /**
76   * @brief The job handler argument.
77   */
78  void *arg;
79
80  /**
81   * @brief One job for each potential processor.
82   */
83  Per_CPU_Job Jobs[ CPU_MAXIMUM_PROCESSORS ];
84};
85
86void _Per_CPU_Perform_jobs( Per_CPU_Control *cpu )
87{
88  ISR_lock_Context  lock_context;
89  Per_CPU_Job      *job;
90
91  _ISR_lock_ISR_disable( &lock_context );
92  _Per_CPU_Acquire( cpu, &lock_context );
93
94  while ( ( job = cpu->Jobs.head ) != NULL ) {
95    Per_CPU_Jobs *jobs;
96
97    cpu->Jobs.head = job->next;
98    _Per_CPU_Release( cpu, &lock_context );
99    _ISR_lock_ISR_enable( &lock_context );
100
101    jobs = job->jobs;
102    ( *jobs->handler )( jobs->arg );
103    _Atomic_Store_ulong( &job->done, 1, ATOMIC_ORDER_RELEASE );
104
105     _ISR_lock_ISR_disable( &lock_context );
106    _Per_CPU_Acquire( cpu, &lock_context );
107  }
108
109  _Per_CPU_Release( cpu, &lock_context );
110  _ISR_lock_ISR_enable( &lock_context );
111}
112
113static void _Per_CPU_Try_perform_jobs( Per_CPU_Control *cpu_self )
114{
115  unsigned long message;
116
117  message = _Atomic_Load_ulong( &cpu_self->message, ATOMIC_ORDER_RELAXED );
118
119  if ( ( message & SMP_MESSAGE_PERFORM_JOBS ) != 0 ) {
120    bool success;
121
122    success = _Atomic_Compare_exchange_ulong(
123      &cpu_self->message, &message,
124      message & ~SMP_MESSAGE_PERFORM_JOBS, ATOMIC_ORDER_RELAXED,
125      ATOMIC_ORDER_RELAXED
126    );
127
128    if ( success ) {
129      _Per_CPU_Perform_jobs( cpu_self );
130    }
131  }
132}
133
134static void _SMP_Issue_action_jobs(
135  const Processor_mask *targets,
136  Per_CPU_Jobs         *jobs,
137  uint32_t              cpu_max
138)
139{
140  uint32_t cpu_index;
141
142  for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
143    if ( _Processor_mask_Is_set( targets, cpu_index ) ) {
144      ISR_lock_Context  lock_context;
145      Per_CPU_Job      *job;
146      Per_CPU_Control  *cpu;
147
148      job = &jobs->Jobs[ cpu_index ];
149      _Atomic_Store_ulong( &job->done, 0, ATOMIC_ORDER_RELAXED );
150      _Assert( job->next == NULL );
151      job->jobs = jobs;
152
153      cpu = _Per_CPU_Get_by_index( cpu_index );
154      _ISR_lock_ISR_disable( &lock_context );
155      _Per_CPU_Acquire( cpu, &lock_context );
156
157      if ( cpu->Jobs.head == NULL ) {
158        cpu->Jobs.head = job;
159      } else {
160        *cpu->Jobs.tail = job;
161      }
162
163      cpu->Jobs.tail = &job->next;
164
165      _Per_CPU_Release( cpu, &lock_context );
166      _ISR_lock_ISR_enable( &lock_context );
167      _SMP_Send_message( cpu_index, SMP_MESSAGE_PERFORM_JOBS );
168    }
169  }
170}
171
172static void _SMP_Wait_for_action_jobs(
173  const Processor_mask *targets,
174  const Per_CPU_Jobs   *jobs,
175  uint32_t              cpu_max,
176  Per_CPU_Control      *cpu_self
177)
178{
179  uint32_t cpu_index;
180
181  for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
182    if ( _Processor_mask_Is_set( targets, cpu_index ) ) {
183      const Per_CPU_Job *job;
184
185      job = &jobs->Jobs[ cpu_index ];
186
187      while ( _Atomic_Load_ulong( &job->done, ATOMIC_ORDER_ACQUIRE ) == 0 ) {
188        _Per_CPU_Try_perform_jobs( cpu_self );
189      }
190    }
191  }
192}
193
194void _SMP_Multicast_action(
195  const Processor_mask *targets,
196  SMP_Action_handler    handler,
197  void                 *arg
198)
199{
200  Per_CPU_Jobs     jobs;
201  uint32_t         cpu_max;
202  Per_CPU_Control *cpu_self;
203
204  cpu_max = _SMP_Get_processor_maximum();
205  _Assert( cpu_max <= CPU_MAXIMUM_PROCESSORS );
206
207  if ( ! _System_state_Is_up( _System_state_Get() ) ) {
208    ( *handler )( arg );
209    return;
210  }
211
212  if ( targets == NULL ) {
213    targets = _SMP_Get_online_processors();
214  }
215
216  jobs.handler = handler;
217  jobs.arg = arg;
218
219  cpu_self = _Thread_Dispatch_disable();
220  _SMP_Issue_action_jobs( targets, &jobs, cpu_max );
221  _SMP_Wait_for_action_jobs( targets, &jobs, cpu_max, cpu_self );
222  _Thread_Dispatch_enable( cpu_self );
223}
Note: See TracBrowser for help on using the repository browser.