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 : 16871 : spdk_add_subsystem(struct spdk_subsystem *subsystem)
36 : : {
37 : 16871 : TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq);
38 : 16871 : }
39 : :
40 : : void
41 : 16368 : spdk_add_subsystem_depend(struct spdk_subsystem_depend *depend)
42 : : {
43 : 16368 : TAILQ_INSERT_TAIL(&g_subsystems_deps, depend, tailq);
44 : 16368 : }
45 : :
46 : : static struct spdk_subsystem *
47 : 52863 : _subsystem_find(struct spdk_subsystem_list *list, const char *name)
48 : : {
49 : : struct spdk_subsystem *iter;
50 : :
51 [ + + ]: 220355 : TAILQ_FOREACH(iter, list, tailq) {
52 [ + + - + : 215271 : if (strcmp(name, iter->name) == 0) {
+ + ]
53 : 47779 : return iter;
54 : : }
55 : : }
56 : :
57 : 5084 : return NULL;
58 : : }
59 : :
60 : : struct spdk_subsystem *
61 : 32251 : subsystem_find(const char *name)
62 : : {
63 : 32251 : return _subsystem_find(&g_subsystems, name);
64 : : }
65 : :
66 : : struct spdk_subsystem *
67 : 1297 : subsystem_get_first(void)
68 : : {
69 : 1297 : return TAILQ_FIRST(&g_subsystems);
70 : : }
71 : :
72 : : struct spdk_subsystem *
73 : 12189 : subsystem_get_next(struct spdk_subsystem *cur_subsystem)
74 : : {
75 : 12189 : return TAILQ_NEXT(cur_subsystem, tailq);
76 : : }
77 : :
78 : :
79 : : struct spdk_subsystem_depend *
80 : 12189 : subsystem_get_first_depend(void)
81 : : {
82 : 12189 : return TAILQ_FIRST(&g_subsystems_deps);
83 : : }
84 : :
85 : : struct spdk_subsystem_depend *
86 : 118578 : subsystem_get_next_depend(struct spdk_subsystem_depend *cur_depend)
87 : : {
88 : 118578 : return TAILQ_NEXT(cur_depend, tailq);
89 : : }
90 : :
91 : : static void
92 : 2805 : subsystem_sort(void)
93 : : {
94 : : bool has_dependency, all_dependencies_met;
95 : : struct spdk_subsystem *subsystem, *subsystem_tmp;
96 : : struct spdk_subsystem_depend *subsystem_dep;
97 : 1436 : struct spdk_subsystem_list sorted_list;
98 : :
99 : 2805 : TAILQ_INIT(&sorted_list);
100 : : /* We will move subsystems from the original g_subsystems TAILQ to the temporary
101 : : * sorted_list one at a time. We can only move a subsystem if it either (a) has no
102 : : * dependencies, or (b) all of its dependencies have already been moved to the
103 : : * sorted_list.
104 : : *
105 : : * Once all of the subsystems have been moved to the temporary list, we will move
106 : : * the list as-is back to the original g_subsystems TAILQ - they will now be sorted
107 : : * in the order which they must be initialized.
108 : : */
109 [ + + ]: 7446 : while (!TAILQ_EMPTY(&g_subsystems)) {
110 [ + + ]: 25726 : TAILQ_FOREACH_SAFE(subsystem, &g_subsystems, tailq, subsystem_tmp) {
111 : 21085 : has_dependency = false;
112 : 21085 : all_dependencies_met = true;
113 [ + + ]: 173416 : TAILQ_FOREACH(subsystem_dep, &g_subsystems_deps, tailq) {
114 [ + + - + : 157403 : if (strcmp(subsystem->name, subsystem_dep->name) == 0) {
+ + ]
115 : 20612 : has_dependency = true;
116 [ + + ]: 20612 : if (!_subsystem_find(&sorted_list, subsystem_dep->depends_on)) {
117 : : /* We found a dependency that isn't in the sorted_list yet.
118 : : * Clear the flag and break from the inner loop, we know
119 : : * we can't move this subsystem to the sorted_list yet.
120 : : */
121 : 5072 : all_dependencies_met = false;
122 : 5072 : break;
123 : : }
124 : : }
125 : : }
126 : :
127 [ + + + + ]: 21085 : if (!has_dependency || all_dependencies_met) {
128 [ + + ]: 16013 : TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
129 : 16013 : TAILQ_INSERT_TAIL(&sorted_list, subsystem, tailq);
130 : : }
131 : : }
132 : : }
133 : :
134 [ - + + + ]: 2805 : TAILQ_SWAP(&sorted_list, &g_subsystems, spdk_subsystem, tailq);
135 : 2805 : }
136 : :
137 : : void
138 : 18818 : spdk_subsystem_init_next(int rc)
139 : : {
140 [ - + ]: 18818 : assert(spdk_thread_is_app_thread(NULL));
141 : :
142 : : /* The initialization is interrupted by the spdk_subsystem_fini, so just return */
143 [ - + - + ]: 18818 : if (g_subsystems_init_interrupted) {
144 : 0 : return;
145 : : }
146 : :
147 [ - + ]: 18818 : if (rc) {
148 : 0 : SPDK_ERRLOG("Init subsystem %s failed\n", g_next_subsystem->name);
149 : 0 : g_subsystem_start_fn(rc, g_subsystem_start_arg);
150 : 0 : return;
151 : : }
152 : :
153 [ + + ]: 18818 : if (!g_next_subsystem) {
154 : 2805 : g_next_subsystem = TAILQ_FIRST(&g_subsystems);
155 : : } else {
156 : 16013 : g_next_subsystem = TAILQ_NEXT(g_next_subsystem, tailq);
157 : : }
158 : :
159 [ + + ]: 18818 : if (!g_next_subsystem) {
160 : 2805 : g_subsystems_initialized = true;
161 : 2805 : g_subsystem_start_fn(0, g_subsystem_start_arg);
162 : 2805 : return;
163 : : }
164 : :
165 [ + + ]: 16013 : if (g_next_subsystem->init) {
166 : 15941 : g_next_subsystem->init();
167 : : } else {
168 : 72 : spdk_subsystem_init_next(0);
169 : : }
170 : : }
171 : :
172 : : void
173 : 2817 : spdk_subsystem_init(spdk_subsystem_init_fn cb_fn, void *cb_arg)
174 : : {
175 : : struct spdk_subsystem_depend *dep;
176 : :
177 [ - + ]: 2817 : assert(spdk_thread_is_app_thread(NULL));
178 : :
179 : 2817 : g_subsystem_start_fn = cb_fn;
180 : 2817 : g_subsystem_start_arg = cb_arg;
181 : :
182 : : /* Verify that all dependency name and depends_on subsystems are registered */
183 [ + + ]: 18357 : TAILQ_FOREACH(dep, &g_subsystems_deps, tailq) {
184 [ + + ]: 15552 : if (!subsystem_find(dep->name)) {
185 : 6 : SPDK_ERRLOG("subsystem %s is missing\n", dep->name);
186 : 6 : g_subsystem_start_fn(-1, g_subsystem_start_arg);
187 : 6 : return;
188 : : }
189 [ + + ]: 15546 : if (!subsystem_find(dep->depends_on)) {
190 : 6 : SPDK_ERRLOG("subsystem %s dependency %s is missing\n",
191 : : dep->name, dep->depends_on);
192 : 6 : g_subsystem_start_fn(-1, g_subsystem_start_arg);
193 : 6 : return;
194 : : }
195 : : }
196 : :
197 : 2805 : subsystem_sort();
198 : :
199 : 2805 : spdk_subsystem_init_next(0);
200 : : }
201 : :
202 : : static void
203 : 18787 : subsystem_fini_next(void *arg1)
204 : : {
205 [ - + ]: 18787 : assert(g_fini_thread == spdk_get_thread());
206 : :
207 [ + + ]: 18787 : if (!g_next_subsystem) {
208 : : /* If the initialized flag is false, then we've failed to initialize
209 : : * the very first subsystem and no de-init is needed
210 : : */
211 [ + + + + ]: 2846 : if (g_subsystems_initialized) {
212 : 2792 : g_next_subsystem = TAILQ_LAST(&g_subsystems, spdk_subsystem_list);
213 : : }
214 : : } else {
215 [ - + - + : 15941 : if (g_subsystems_initialized || g_subsystems_init_interrupted) {
- - - - ]
216 : 15941 : g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
217 : : } else {
218 : 0 : g_subsystems_init_interrupted = true;
219 : : }
220 : : }
221 : :
222 [ + + ]: 18787 : while (g_next_subsystem) {
223 [ + - ]: 15941 : if (g_next_subsystem->fini) {
224 : 15941 : g_next_subsystem->fini();
225 : 15941 : return;
226 : : }
227 : 0 : g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
228 : : }
229 : :
230 : 2846 : g_subsystem_stop_fn(g_subsystem_stop_arg);
231 : 2846 : return;
232 : : }
233 : :
234 : : void
235 : 18787 : spdk_subsystem_fini_next(void)
236 : : {
237 [ - + ]: 18787 : if (g_fini_thread != spdk_get_thread()) {
238 : 0 : spdk_thread_send_msg(g_fini_thread, subsystem_fini_next, NULL);
239 : : } else {
240 : 18787 : subsystem_fini_next(NULL);
241 : : }
242 : 18787 : }
243 : :
244 : : void
245 : 2846 : spdk_subsystem_fini(spdk_msg_fn cb_fn, void *cb_arg)
246 : : {
247 : 2846 : g_subsystem_stop_fn = cb_fn;
248 : 2846 : g_subsystem_stop_arg = cb_arg;
249 : :
250 : 2846 : g_fini_thread = spdk_get_thread();
251 : :
252 : 2846 : spdk_subsystem_fini_next();
253 : 2846 : }
254 : :
255 : : void
256 : 1153 : subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsystem *subsystem)
257 : : {
258 [ + - + + ]: 1153 : if (subsystem && subsystem->write_config_json) {
259 : 1067 : subsystem->write_config_json(w);
260 : : } else {
261 : 86 : spdk_json_write_null(w);
262 : : }
263 : 1153 : }
|