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 : 17196 : spdk_add_subsystem(struct spdk_subsystem *subsystem)
36 : : {
37 [ + - + - : 17196 : TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq);
+ - + - +
- + - + -
+ - + - +
- + - +
- ]
38 : 17196 : }
39 : :
40 : : void
41 : 16680 : spdk_add_subsystem_depend(struct spdk_subsystem_depend *depend)
42 : : {
43 [ + - + - : 16680 : TAILQ_INSERT_TAIL(&g_subsystems_deps, depend, tailq);
+ - + - +
- + - + -
+ - + - +
- + - +
- ]
44 : 16680 : }
45 : :
46 : : static struct spdk_subsystem *
47 : 53708 : _subsystem_find(struct spdk_subsystem_list *list, const char *name)
48 : : {
49 : 49 : struct spdk_subsystem *iter;
50 : :
51 [ + + + - : 225511 : TAILQ_FOREACH(iter, list, tailq) {
+ + + - +
- + - ]
52 [ + + + + : 220630 : if (strcmp(name, iter->name) == 0) {
+ + + - +
+ ]
53 : 48827 : return iter;
54 : : }
55 : 9338 : }
56 : :
57 : 4881 : return NULL;
58 : 2487 : }
59 : :
60 : : struct spdk_subsystem *
61 : 32925 : subsystem_find(const char *name)
62 : : {
63 : 32925 : return _subsystem_find(&g_subsystems, name);
64 : : }
65 : :
66 : : struct spdk_subsystem *
67 : 1048 : subsystem_get_first(void)
68 : : {
69 : 1048 : return TAILQ_FIRST(&g_subsystems);
70 : : }
71 : :
72 : : struct spdk_subsystem *
73 : 9690 : subsystem_get_next(struct spdk_subsystem *cur_subsystem)
74 : : {
75 [ # # # # : 9690 : return TAILQ_NEXT(cur_subsystem, tailq);
# # ]
76 : : }
77 : :
78 : :
79 : : struct spdk_subsystem_depend *
80 : 9690 : subsystem_get_first_depend(void)
81 : : {
82 : 9690 : return TAILQ_FIRST(&g_subsystems_deps);
83 : : }
84 : :
85 : : struct spdk_subsystem_depend *
86 : 95940 : subsystem_get_next_depend(struct spdk_subsystem_depend *cur_depend)
87 : : {
88 [ # # # # : 95940 : return TAILQ_NEXT(cur_depend, tailq);
# # ]
89 : : }
90 : :
91 : : static void
92 : 2871 : subsystem_sort(void)
93 : : {
94 : 2 : bool has_dependency, all_dependencies_met;
95 : 2 : struct spdk_subsystem *subsystem, *subsystem_tmp;
96 : 2 : struct spdk_subsystem_depend *subsystem_dep;
97 : 1170 : struct spdk_subsystem_list sorted_list;
98 : :
99 [ + - ]: 2871 : 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 [ + + ]: 7401 : while (!TAILQ_EMPTY(&g_subsystems)) {
110 [ + + + - : 25801 : TAILQ_FOREACH_SAFE(subsystem, &g_subsystems, tailq, subsystem_tmp) {
+ - + - +
+ ]
111 : 21271 : has_dependency = false;
112 : 21271 : all_dependencies_met = true;
113 [ + + + - : 177558 : TAILQ_FOREACH(subsystem_dep, &g_subsystems_deps, tailq) {
+ - + - ]
114 [ + + + + : 161156 : if (strcmp(subsystem->name, subsystem_dep->name) == 0) {
+ + + - +
- + - +
+ ]
115 : 20783 : has_dependency = true;
116 [ + + + - : 20783 : 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 : 4869 : all_dependencies_met = false;
122 : 4869 : break;
123 : : }
124 : 577 : }
125 : 8556 : }
126 : :
127 [ + + + + : 21271 : if (!has_dependency || all_dependencies_met) {
+ - + + ]
128 [ + + + - : 16402 : TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
129 [ + - + - : 16402 : TAILQ_INSERT_TAIL(&sorted_list, subsystem, tailq);
+ - + - +
- + - + -
+ - + - +
- + - +
- ]
130 : 621 : }
131 : 1374 : }
132 : : }
133 : :
134 [ + + + + : 2871 : TAILQ_SWAP(&sorted_list, &g_subsystems, spdk_subsystem, tailq);
+ - + - +
- # # # #
# # + - +
+ + - + -
+ - + - ]
135 : 2871 : }
136 : :
137 : : void
138 : 19273 : spdk_subsystem_init_next(int rc)
139 : : {
140 [ + + # # ]: 19273 : assert(spdk_thread_is_app_thread(NULL));
141 : :
142 : : /* The initialization is interrupted by the spdk_subsystem_fini, so just return */
143 [ + + - + ]: 19273 : if (g_subsystems_init_interrupted) {
144 : 0 : return;
145 : : }
146 : :
147 [ - + ]: 19273 : 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 [ + + ]: 19273 : if (!g_next_subsystem) {
154 : 2871 : g_next_subsystem = TAILQ_FIRST(&g_subsystems);
155 : 107 : } else {
156 [ + - + - : 16402 : g_next_subsystem = TAILQ_NEXT(g_next_subsystem, tailq);
+ - ]
157 : : }
158 : :
159 [ + + ]: 19273 : if (!g_next_subsystem) {
160 : 2871 : g_subsystems_initialized = true;
161 [ - + + - ]: 2871 : g_subsystem_start_fn(0, g_subsystem_start_arg);
162 : 2871 : return;
163 : : }
164 : :
165 [ + + + - : 16402 : if (g_next_subsystem->init) {
+ + ]
166 [ + - + - : 16330 : g_next_subsystem->init();
- + + - ]
167 : 609 : } else {
168 : 72 : spdk_subsystem_init_next(0);
169 : : }
170 : 728 : }
171 : :
172 : : void
173 : 2883 : spdk_subsystem_init(spdk_subsystem_init_fn cb_fn, void *cb_arg)
174 : : {
175 : 4 : struct spdk_subsystem_depend *dep;
176 : :
177 [ + + # # ]: 2883 : assert(spdk_thread_is_app_thread(NULL));
178 : :
179 : 2883 : g_subsystem_start_fn = cb_fn;
180 : 2883 : g_subsystem_start_arg = cb_arg;
181 : :
182 : : /* Verify that all dependency name and depends_on subsystems are registered */
183 [ + + + - : 18797 : TAILQ_FOREACH(dep, &g_subsystems_deps, tailq) {
+ - + - ]
184 [ + + + - : 15926 : 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 [ + + + - : 15920 : 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 : 577 : }
196 : :
197 : 2871 : subsystem_sort();
198 : :
199 : 2871 : spdk_subsystem_init_next(0);
200 [ - + ]: 109 : }
201 : :
202 : : static void
203 : 19239 : subsystem_fini_next(void *arg1)
204 : : {
205 [ + + # # ]: 19239 : assert(g_fini_thread == spdk_get_thread());
206 : :
207 [ + + ]: 19239 : 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 [ + + + + ]: 2909 : if (g_subsystems_initialized) {
212 [ + - + - : 2858 : g_next_subsystem = TAILQ_LAST(&g_subsystems, spdk_subsystem_list);
+ - + - ]
213 : 105 : }
214 : 105 : } else {
215 [ + + - + : 16330 : if (g_subsystems_initialized || g_subsystems_init_interrupted) {
- - - - ]
216 [ + - + - : 16330 : g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
+ - + - +
- + - ]
217 : 609 : } else {
218 : 0 : g_subsystems_init_interrupted = true;
219 : : }
220 : : }
221 : :
222 [ + + ]: 19239 : while (g_next_subsystem) {
223 [ + - + - : 16330 : if (g_next_subsystem->fini) {
+ - ]
224 [ + - + - : 16330 : g_next_subsystem->fini();
- + + - ]
225 : 16330 : return;
226 : : }
227 [ # # # # : 0 : g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
# # # # #
# # # ]
228 : : }
229 : :
230 [ - + + - ]: 2909 : g_subsystem_stop_fn(g_subsystem_stop_arg);
231 : 2909 : return;
232 : 714 : }
233 : :
234 : : void
235 : 19239 : spdk_subsystem_fini_next(void)
236 : : {
237 [ - + ]: 19239 : if (g_fini_thread != spdk_get_thread()) {
238 : 0 : spdk_thread_send_msg(g_fini_thread, subsystem_fini_next, NULL);
239 : 0 : } else {
240 : 19239 : subsystem_fini_next(NULL);
241 : : }
242 : 19239 : }
243 : :
244 : : void
245 : 2909 : spdk_subsystem_fini(spdk_msg_fn cb_fn, void *cb_arg)
246 : : {
247 : 2909 : g_subsystem_stop_fn = cb_fn;
248 : 2909 : g_subsystem_stop_arg = cb_arg;
249 : :
250 : 2909 : g_fini_thread = spdk_get_thread();
251 : :
252 : 2909 : spdk_subsystem_fini_next();
253 : 2909 : }
254 : :
255 : : void
256 : 1079 : subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsystem *subsystem)
257 : : {
258 [ + - + + : 1079 : if (subsystem && subsystem->write_config_json) {
# # # # ]
259 [ # # # # : 1001 : subsystem->write_config_json(w);
# # # # ]
260 : 0 : } else {
261 : 78 : spdk_json_write_null(w);
262 : : }
263 : 1079 : }
|