Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2016 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/init.h"
9 : : #include "spdk/log.h"
10 : : #include "spdk/queue.h"
11 : : #include "spdk/thread.h"
12 : :
13 : : #include "spdk_internal/init.h"
14 : : #include "spdk/env.h"
15 : :
16 : : #include "spdk/json.h"
17 : :
18 : : #include "subsystem.h"
19 : :
20 : : TAILQ_HEAD(spdk_subsystem_list, spdk_subsystem);
21 : : struct spdk_subsystem_list g_subsystems = TAILQ_HEAD_INITIALIZER(g_subsystems);
22 : :
23 : : TAILQ_HEAD(spdk_subsystem_depend_list, spdk_subsystem_depend);
24 : : struct spdk_subsystem_depend_list g_subsystems_deps = TAILQ_HEAD_INITIALIZER(g_subsystems_deps);
25 : : static struct spdk_subsystem *g_next_subsystem;
26 : : static bool g_subsystems_initialized = false;
27 : : static bool g_subsystems_init_interrupted = false;
28 : : static spdk_subsystem_init_fn g_subsystem_start_fn = NULL;
29 : : static void *g_subsystem_start_arg = NULL;
30 : : static spdk_msg_fn g_subsystem_stop_fn = NULL;
31 : : static void *g_subsystem_stop_arg = NULL;
32 : : static struct spdk_thread *g_fini_thread = NULL;
33 : :
34 : : void
35 : 22094 : spdk_add_subsystem(struct spdk_subsystem *subsystem)
36 : : {
37 : 22094 : TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq);
38 : 22094 : }
39 : :
40 : : void
41 : 22997 : spdk_add_subsystem_depend(struct spdk_subsystem_depend *depend)
42 : : {
43 : 22997 : TAILQ_INSERT_TAIL(&g_subsystems_deps, depend, tailq);
44 : 22997 : }
45 : :
46 : : static struct spdk_subsystem *
47 : 71816 : _subsystem_find(struct spdk_subsystem_list *list, const char *name)
48 : : {
49 : : struct spdk_subsystem *iter;
50 : :
51 [ + + ]: 345390 : TAILQ_FOREACH(iter, list, tailq) {
52 [ + + - + : 339359 : if (strcmp(name, iter->name) == 0) {
+ + ]
53 : 65785 : return iter;
54 : : }
55 : : }
56 : :
57 : 6031 : return NULL;
58 : : }
59 : :
60 : : struct spdk_subsystem *
61 : 44433 : subsystem_find(const char *name)
62 : : {
63 : 44433 : return _subsystem_find(&g_subsystems, name);
64 : : }
65 : :
66 : : bool
67 : 0 : spdk_subsystem_exists(const char *name)
68 : : {
69 : 0 : return subsystem_find(name) != NULL;
70 : : }
71 : :
72 : : struct spdk_subsystem *
73 : 1335 : subsystem_get_first(void)
74 : : {
75 : 1335 : return TAILQ_FIRST(&g_subsystems);
76 : : }
77 : :
78 : : struct spdk_subsystem *
79 : 13947 : subsystem_get_next(struct spdk_subsystem *cur_subsystem)
80 : : {
81 : 13947 : return TAILQ_NEXT(cur_subsystem, tailq);
82 : : }
83 : :
84 : :
85 : : struct spdk_subsystem_depend *
86 : 13947 : subsystem_get_first_depend(void)
87 : : {
88 : 13947 : return TAILQ_FIRST(&g_subsystems_deps);
89 : : }
90 : :
91 : : struct spdk_subsystem_depend *
92 : 158678 : subsystem_get_next_depend(struct spdk_subsystem_depend *cur_depend)
93 : : {
94 : 158678 : return TAILQ_NEXT(cur_depend, tailq);
95 : : }
96 : :
97 : : static void
98 : 2805 : subsystem_sort(void)
99 : : {
100 : : bool has_dependency, all_dependencies_met;
101 : : struct spdk_subsystem *subsystem, *subsystem_tmp;
102 : : struct spdk_subsystem_depend *subsystem_dep;
103 : 1325 : struct spdk_subsystem_list sorted_list;
104 : :
105 : 2805 : TAILQ_INIT(&sorted_list);
106 : : /* We will move subsystems from the original g_subsystems TAILQ to the temporary
107 : : * sorted_list one at a time. We can only move a subsystem if it either (a) has no
108 : : * dependencies, or (b) all of its dependencies have already been moved to the
109 : : * sorted_list.
110 : : *
111 : : * Once all of the subsystems have been moved to the temporary list, we will move
112 : : * the list as-is back to the original g_subsystems TAILQ - they will now be sorted
113 : : * in the order which they must be initialized.
114 : : */
115 [ + + ]: 7759 : while (!TAILQ_EMPTY(&g_subsystems)) {
116 [ + + ]: 31518 : TAILQ_FOREACH_SAFE(subsystem, &g_subsystems, tailq, subsystem_tmp) {
117 : 26564 : has_dependency = false;
118 : 26564 : all_dependencies_met = true;
119 [ + + ]: 259698 : TAILQ_FOREACH(subsystem_dep, &g_subsystems_deps, tailq) {
120 [ + + - + : 239157 : if (strcmp(subsystem->name, subsystem_dep->name) == 0) {
+ + ]
121 : 27383 : has_dependency = true;
122 [ + + ]: 27383 : if (!_subsystem_find(&sorted_list, subsystem_dep->depends_on)) {
123 : : /* We found a dependency that isn't in the sorted_list yet.
124 : : * Clear the flag and break from the inner loop, we know
125 : : * we can't move this subsystem to the sorted_list yet.
126 : : */
127 : 6023 : all_dependencies_met = false;
128 : 6023 : break;
129 : : }
130 : : }
131 : : }
132 : :
133 [ + + + + ]: 26564 : if (!has_dependency || all_dependencies_met) {
134 [ + + ]: 20541 : TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
135 : 20541 : TAILQ_INSERT_TAIL(&sorted_list, subsystem, tailq);
136 : : }
137 : : }
138 : : }
139 : :
140 [ - + + + ]: 2805 : TAILQ_SWAP(&sorted_list, &g_subsystems, spdk_subsystem, tailq);
141 : 2805 : }
142 : :
143 : : void
144 : 23346 : spdk_subsystem_init_next(int rc)
145 : : {
146 [ - + ]: 23346 : assert(spdk_thread_is_app_thread(NULL));
147 : :
148 : : /* The initialization is interrupted by the spdk_subsystem_fini, so just return */
149 [ - + - + ]: 23346 : if (g_subsystems_init_interrupted) {
150 : 0 : return;
151 : : }
152 : :
153 [ - + ]: 23346 : if (rc) {
154 : 0 : SPDK_ERRLOG("Init subsystem %s failed\n", g_next_subsystem->name);
155 : 0 : g_subsystem_start_fn(rc, g_subsystem_start_arg);
156 : 0 : return;
157 : : }
158 : :
159 [ + + ]: 23346 : if (!g_next_subsystem) {
160 : 2805 : g_next_subsystem = TAILQ_FIRST(&g_subsystems);
161 : : } else {
162 : 20541 : g_next_subsystem = TAILQ_NEXT(g_next_subsystem, tailq);
163 : : }
164 : :
165 [ + + ]: 23346 : if (!g_next_subsystem) {
166 : 2805 : g_subsystems_initialized = true;
167 : 2805 : g_subsystem_start_fn(0, g_subsystem_start_arg);
168 : 2805 : return;
169 : : }
170 : :
171 [ + + ]: 20541 : if (g_next_subsystem->init) {
172 : 20493 : g_next_subsystem->init();
173 : : } else {
174 : 48 : spdk_subsystem_init_next(0);
175 : : }
176 : : }
177 : :
178 : : void
179 : 2813 : spdk_subsystem_init(spdk_subsystem_init_fn cb_fn, void *cb_arg)
180 : : {
181 : : struct spdk_subsystem_depend *dep;
182 : :
183 [ - + ]: 2813 : assert(spdk_thread_is_app_thread(NULL));
184 : :
185 : 2813 : g_subsystem_start_fn = cb_fn;
186 : 2813 : g_subsystem_start_arg = cb_arg;
187 : :
188 : : /* Verify that all dependency name and depends_on subsystems are registered */
189 [ + + ]: 24173 : TAILQ_FOREACH(dep, &g_subsystems_deps, tailq) {
190 [ + + ]: 21368 : if (!subsystem_find(dep->name)) {
191 : 4 : SPDK_ERRLOG("subsystem %s is missing\n", dep->name);
192 : 4 : g_subsystem_start_fn(-1, g_subsystem_start_arg);
193 : 4 : return;
194 : : }
195 [ + + ]: 21364 : if (!subsystem_find(dep->depends_on)) {
196 : 4 : SPDK_ERRLOG("subsystem %s dependency %s is missing\n",
197 : : dep->name, dep->depends_on);
198 : 4 : g_subsystem_start_fn(-1, g_subsystem_start_arg);
199 : 4 : return;
200 : : }
201 : : }
202 : :
203 : 2805 : subsystem_sort();
204 : :
205 : 2805 : spdk_subsystem_init_next(0);
206 : : }
207 : :
208 : : static void
209 : 23363 : subsystem_fini_next(void *arg1)
210 : : {
211 [ - + ]: 23363 : assert(g_fini_thread == spdk_get_thread());
212 : :
213 [ + + ]: 23363 : if (!g_next_subsystem) {
214 : : /* If the initialized flag is false, then we've failed to initialize
215 : : * the very first subsystem and no de-init is needed
216 : : */
217 [ + + + + ]: 2870 : if (g_subsystems_initialized) {
218 : 2796 : g_next_subsystem = TAILQ_LAST(&g_subsystems, spdk_subsystem_list);
219 : : }
220 : : } else {
221 [ - + - + : 20493 : if (g_subsystems_initialized || g_subsystems_init_interrupted) {
- - - - ]
222 : 20493 : g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
223 : : } else {
224 : 0 : g_subsystems_init_interrupted = true;
225 : : }
226 : : }
227 : :
228 [ + + ]: 23363 : while (g_next_subsystem) {
229 [ + - ]: 20493 : if (g_next_subsystem->fini) {
230 : 20493 : g_next_subsystem->fini();
231 : 20493 : return;
232 : : }
233 : 0 : g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
234 : : }
235 : :
236 : 2870 : g_subsystem_stop_fn(g_subsystem_stop_arg);
237 : 2870 : return;
238 : : }
239 : :
240 : : void
241 : 23363 : spdk_subsystem_fini_next(void)
242 : : {
243 [ - + ]: 23363 : if (g_fini_thread != spdk_get_thread()) {
244 : 0 : spdk_thread_send_msg(g_fini_thread, subsystem_fini_next, NULL);
245 : : } else {
246 : 23363 : subsystem_fini_next(NULL);
247 : : }
248 : 23363 : }
249 : :
250 : : void
251 : 2870 : spdk_subsystem_fini(spdk_msg_fn cb_fn, void *cb_arg)
252 : : {
253 : 2870 : g_subsystem_stop_fn = cb_fn;
254 : 2870 : g_subsystem_stop_arg = cb_arg;
255 : :
256 : 2870 : g_fini_thread = spdk_get_thread();
257 : :
258 : 2870 : spdk_subsystem_fini_next();
259 : 2870 : }
260 : :
261 : : void
262 : 1701 : subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsystem *subsystem)
263 : : {
264 [ + - + + ]: 1701 : if (subsystem && subsystem->write_config_json) {
265 : 1586 : subsystem->write_config_json(w);
266 : : } else {
267 : 115 : spdk_json_write_null(w);
268 : : }
269 : 1701 : }
|