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 14 : spdk_add_subsystem(struct spdk_subsystem *subsystem)
36 : {
37 14 : TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq);
38 14 : }
39 :
40 : void
41 13 : spdk_add_subsystem_depend(struct spdk_subsystem_depend *depend)
42 : {
43 13 : TAILQ_INSERT_TAIL(&g_subsystems_deps, depend, tailq);
44 13 : }
45 :
46 : static struct spdk_subsystem *
47 49 : _subsystem_find(struct spdk_subsystem_list *list, const char *name)
48 : {
49 : struct spdk_subsystem *iter;
50 :
51 142 : TAILQ_FOREACH(iter, list, tailq) {
52 127 : if (strcmp(name, iter->name) == 0) {
53 34 : return iter;
54 : }
55 : }
56 :
57 15 : return NULL;
58 : }
59 :
60 : struct spdk_subsystem *
61 25 : subsystem_find(const char *name)
62 : {
63 25 : 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 0 : subsystem_get_first(void)
74 : {
75 0 : return TAILQ_FIRST(&g_subsystems);
76 : }
77 :
78 : struct spdk_subsystem *
79 0 : subsystem_get_next(struct spdk_subsystem *cur_subsystem)
80 : {
81 0 : return TAILQ_NEXT(cur_subsystem, tailq);
82 : }
83 :
84 :
85 : struct spdk_subsystem_depend *
86 0 : subsystem_get_first_depend(void)
87 : {
88 0 : return TAILQ_FIRST(&g_subsystems_deps);
89 : }
90 :
91 : struct spdk_subsystem_depend *
92 0 : subsystem_get_next_depend(struct spdk_subsystem_depend *cur_depend)
93 : {
94 0 : return TAILQ_NEXT(cur_depend, tailq);
95 : }
96 :
97 : static void
98 2 : 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 2 : struct spdk_subsystem_list sorted_list;
104 :
105 2 : 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 9 : while (!TAILQ_EMPTY(&g_subsystems)) {
116 32 : TAILQ_FOREACH_SAFE(subsystem, &g_subsystems, tailq, subsystem_tmp) {
117 25 : has_dependency = false;
118 25 : all_dependencies_met = true;
119 125 : TAILQ_FOREACH(subsystem_dep, &g_subsystems_deps, tailq) {
120 113 : if (strcmp(subsystem->name, subsystem_dep->name) == 0) {
121 24 : has_dependency = true;
122 24 : 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 13 : all_dependencies_met = false;
128 13 : break;
129 : }
130 : }
131 : }
132 :
133 25 : if (!has_dependency || all_dependencies_met) {
134 12 : TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
135 12 : TAILQ_INSERT_TAIL(&sorted_list, subsystem, tailq);
136 : }
137 : }
138 : }
139 :
140 2 : TAILQ_SWAP(&sorted_list, &g_subsystems, spdk_subsystem, tailq);
141 2 : }
142 :
143 : void
144 14 : spdk_subsystem_init_next(int rc)
145 : {
146 14 : assert(spdk_thread_is_app_thread(NULL));
147 :
148 : /* The initialization is interrupted by the spdk_subsystem_fini, so just return */
149 14 : if (g_subsystems_init_interrupted) {
150 0 : return;
151 : }
152 :
153 14 : 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 14 : if (!g_next_subsystem) {
160 2 : g_next_subsystem = TAILQ_FIRST(&g_subsystems);
161 : } else {
162 12 : g_next_subsystem = TAILQ_NEXT(g_next_subsystem, tailq);
163 : }
164 :
165 14 : if (!g_next_subsystem) {
166 2 : g_subsystems_initialized = true;
167 2 : g_subsystem_start_fn(0, g_subsystem_start_arg);
168 2 : return;
169 : }
170 :
171 12 : if (g_next_subsystem->init) {
172 0 : g_next_subsystem->init();
173 : } else {
174 12 : spdk_subsystem_init_next(0);
175 : }
176 : }
177 :
178 : void
179 4 : spdk_subsystem_init(spdk_subsystem_init_fn cb_fn, void *cb_arg)
180 : {
181 : struct spdk_subsystem_depend *dep;
182 :
183 4 : assert(spdk_thread_is_app_thread(NULL));
184 :
185 4 : g_subsystem_start_fn = cb_fn;
186 4 : g_subsystem_start_arg = cb_arg;
187 :
188 : /* Verify that all dependency name and depends_on subsystems are registered */
189 15 : TAILQ_FOREACH(dep, &g_subsystems_deps, tailq) {
190 13 : if (!subsystem_find(dep->name)) {
191 1 : SPDK_ERRLOG("subsystem %s is missing\n", dep->name);
192 1 : g_subsystem_start_fn(-1, g_subsystem_start_arg);
193 1 : return;
194 : }
195 12 : if (!subsystem_find(dep->depends_on)) {
196 1 : SPDK_ERRLOG("subsystem %s dependency %s is missing\n",
197 : dep->name, dep->depends_on);
198 1 : g_subsystem_start_fn(-1, g_subsystem_start_arg);
199 1 : return;
200 : }
201 : }
202 :
203 2 : subsystem_sort();
204 :
205 2 : spdk_subsystem_init_next(0);
206 : }
207 :
208 : static void
209 0 : subsystem_fini_next(void *arg1)
210 : {
211 0 : assert(g_fini_thread == spdk_get_thread());
212 :
213 0 : 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 0 : if (g_subsystems_initialized) {
218 0 : g_next_subsystem = TAILQ_LAST(&g_subsystems, spdk_subsystem_list);
219 : }
220 : } else {
221 0 : if (g_subsystems_initialized || g_subsystems_init_interrupted) {
222 0 : 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 0 : while (g_next_subsystem) {
229 0 : if (g_next_subsystem->fini) {
230 0 : g_next_subsystem->fini();
231 0 : return;
232 : }
233 0 : g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
234 : }
235 :
236 0 : g_subsystem_stop_fn(g_subsystem_stop_arg);
237 0 : return;
238 : }
239 :
240 : void
241 0 : spdk_subsystem_fini_next(void)
242 : {
243 0 : if (g_fini_thread != spdk_get_thread()) {
244 0 : spdk_thread_send_msg(g_fini_thread, subsystem_fini_next, NULL);
245 : } else {
246 0 : subsystem_fini_next(NULL);
247 : }
248 0 : }
249 :
250 : void
251 0 : spdk_subsystem_fini(spdk_msg_fn cb_fn, void *cb_arg)
252 : {
253 0 : g_subsystem_stop_fn = cb_fn;
254 0 : g_subsystem_stop_arg = cb_arg;
255 :
256 0 : g_fini_thread = spdk_get_thread();
257 :
258 0 : spdk_subsystem_fini_next();
259 0 : }
260 :
261 : void
262 0 : subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsystem *subsystem)
263 : {
264 0 : if (subsystem && subsystem->write_config_json) {
265 0 : subsystem->write_config_json(w);
266 : } else {
267 0 : spdk_json_write_null(w);
268 : }
269 0 : }
|