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 : struct spdk_subsystem *
67 0 : subsystem_get_first(void)
68 : {
69 0 : return TAILQ_FIRST(&g_subsystems);
70 : }
71 :
72 : struct spdk_subsystem *
73 0 : subsystem_get_next(struct spdk_subsystem *cur_subsystem)
74 : {
75 0 : return TAILQ_NEXT(cur_subsystem, tailq);
76 : }
77 :
78 :
79 : struct spdk_subsystem_depend *
80 0 : subsystem_get_first_depend(void)
81 : {
82 0 : return TAILQ_FIRST(&g_subsystems_deps);
83 : }
84 :
85 : struct spdk_subsystem_depend *
86 0 : subsystem_get_next_depend(struct spdk_subsystem_depend *cur_depend)
87 : {
88 0 : return TAILQ_NEXT(cur_depend, tailq);
89 : }
90 :
91 : static void
92 2 : 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 2 : struct spdk_subsystem_list sorted_list;
98 :
99 2 : 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 9 : while (!TAILQ_EMPTY(&g_subsystems)) {
110 32 : TAILQ_FOREACH_SAFE(subsystem, &g_subsystems, tailq, subsystem_tmp) {
111 25 : has_dependency = false;
112 25 : all_dependencies_met = true;
113 125 : TAILQ_FOREACH(subsystem_dep, &g_subsystems_deps, tailq) {
114 113 : if (strcmp(subsystem->name, subsystem_dep->name) == 0) {
115 24 : has_dependency = true;
116 24 : 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 13 : all_dependencies_met = false;
122 13 : break;
123 : }
124 : }
125 : }
126 :
127 25 : if (!has_dependency || all_dependencies_met) {
128 12 : TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
129 12 : TAILQ_INSERT_TAIL(&sorted_list, subsystem, tailq);
130 : }
131 : }
132 : }
133 :
134 2 : TAILQ_SWAP(&sorted_list, &g_subsystems, spdk_subsystem, tailq);
135 2 : }
136 :
137 : void
138 14 : spdk_subsystem_init_next(int rc)
139 : {
140 14 : assert(spdk_thread_is_app_thread(NULL));
141 :
142 : /* The initialization is interrupted by the spdk_subsystem_fini, so just return */
143 14 : if (g_subsystems_init_interrupted) {
144 0 : return;
145 : }
146 :
147 14 : 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 14 : if (!g_next_subsystem) {
154 2 : g_next_subsystem = TAILQ_FIRST(&g_subsystems);
155 : } else {
156 12 : g_next_subsystem = TAILQ_NEXT(g_next_subsystem, tailq);
157 : }
158 :
159 14 : if (!g_next_subsystem) {
160 2 : g_subsystems_initialized = true;
161 2 : g_subsystem_start_fn(0, g_subsystem_start_arg);
162 2 : return;
163 : }
164 :
165 12 : if (g_next_subsystem->init) {
166 0 : g_next_subsystem->init();
167 : } else {
168 12 : spdk_subsystem_init_next(0);
169 : }
170 : }
171 :
172 : void
173 4 : spdk_subsystem_init(spdk_subsystem_init_fn cb_fn, void *cb_arg)
174 : {
175 : struct spdk_subsystem_depend *dep;
176 :
177 4 : assert(spdk_thread_is_app_thread(NULL));
178 :
179 4 : g_subsystem_start_fn = cb_fn;
180 4 : g_subsystem_start_arg = cb_arg;
181 :
182 : /* Verify that all dependency name and depends_on subsystems are registered */
183 15 : TAILQ_FOREACH(dep, &g_subsystems_deps, tailq) {
184 13 : if (!subsystem_find(dep->name)) {
185 1 : SPDK_ERRLOG("subsystem %s is missing\n", dep->name);
186 1 : g_subsystem_start_fn(-1, g_subsystem_start_arg);
187 1 : return;
188 : }
189 12 : if (!subsystem_find(dep->depends_on)) {
190 1 : SPDK_ERRLOG("subsystem %s dependency %s is missing\n",
191 : dep->name, dep->depends_on);
192 1 : g_subsystem_start_fn(-1, g_subsystem_start_arg);
193 1 : return;
194 : }
195 : }
196 :
197 2 : subsystem_sort();
198 :
199 2 : spdk_subsystem_init_next(0);
200 : }
201 :
202 : static void
203 0 : subsystem_fini_next(void *arg1)
204 : {
205 0 : assert(g_fini_thread == spdk_get_thread());
206 :
207 0 : 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 0 : if (g_subsystems_initialized) {
212 0 : g_next_subsystem = TAILQ_LAST(&g_subsystems, spdk_subsystem_list);
213 : }
214 : } else {
215 0 : if (g_subsystems_initialized || g_subsystems_init_interrupted) {
216 0 : 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 0 : while (g_next_subsystem) {
223 0 : if (g_next_subsystem->fini) {
224 0 : g_next_subsystem->fini();
225 0 : return;
226 : }
227 0 : g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
228 : }
229 :
230 0 : g_subsystem_stop_fn(g_subsystem_stop_arg);
231 0 : return;
232 : }
233 :
234 : void
235 0 : spdk_subsystem_fini_next(void)
236 : {
237 0 : if (g_fini_thread != spdk_get_thread()) {
238 0 : spdk_thread_send_msg(g_fini_thread, subsystem_fini_next, NULL);
239 : } else {
240 0 : subsystem_fini_next(NULL);
241 : }
242 0 : }
243 :
244 : void
245 0 : spdk_subsystem_fini(spdk_msg_fn cb_fn, void *cb_arg)
246 : {
247 0 : g_subsystem_stop_fn = cb_fn;
248 0 : g_subsystem_stop_arg = cb_arg;
249 :
250 0 : g_fini_thread = spdk_get_thread();
251 :
252 0 : spdk_subsystem_fini_next();
253 0 : }
254 :
255 : void
256 0 : subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsystem *subsystem)
257 : {
258 0 : if (subsystem && subsystem->write_config_json) {
259 0 : subsystem->write_config_json(w);
260 : } else {
261 0 : spdk_json_write_null(w);
262 : }
263 0 : }
|