xref: /spdk/lib/init/subsystem.c (revision fecffda6ecf8853b82edccde429b68252f0a62c5)
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 spdk_add_subsystem(struct spdk_subsystem *subsystem)
36 {
37 	TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq);
38 }
39 
40 void
41 spdk_add_subsystem_depend(struct spdk_subsystem_depend *depend)
42 {
43 	TAILQ_INSERT_TAIL(&g_subsystems_deps, depend, tailq);
44 }
45 
46 static struct spdk_subsystem *
47 _subsystem_find(struct spdk_subsystem_list *list, const char *name)
48 {
49 	struct spdk_subsystem *iter;
50 
51 	TAILQ_FOREACH(iter, list, tailq) {
52 		if (strcmp(name, iter->name) == 0) {
53 			return iter;
54 		}
55 	}
56 
57 	return NULL;
58 }
59 
60 struct spdk_subsystem *
61 subsystem_find(const char *name)
62 {
63 	return _subsystem_find(&g_subsystems, name);
64 }
65 
66 struct spdk_subsystem *
67 subsystem_get_first(void)
68 {
69 	return TAILQ_FIRST(&g_subsystems);
70 }
71 
72 struct spdk_subsystem *
73 subsystem_get_next(struct spdk_subsystem *cur_subsystem)
74 {
75 	return TAILQ_NEXT(cur_subsystem, tailq);
76 }
77 
78 
79 struct spdk_subsystem_depend *
80 subsystem_get_first_depend(void)
81 {
82 	return TAILQ_FIRST(&g_subsystems_deps);
83 }
84 
85 struct spdk_subsystem_depend *
86 subsystem_get_next_depend(struct spdk_subsystem_depend *cur_depend)
87 {
88 	return TAILQ_NEXT(cur_depend, tailq);
89 }
90 
91 static void
92 subsystem_sort(void)
93 {
94 	bool depends_on, depends_on_sorted;
95 	struct spdk_subsystem *subsystem, *subsystem_tmp;
96 	struct spdk_subsystem_depend *subsystem_dep;
97 
98 	struct spdk_subsystem_list subsystems_list = TAILQ_HEAD_INITIALIZER(subsystems_list);
99 
100 	while (!TAILQ_EMPTY(&g_subsystems)) {
101 		TAILQ_FOREACH_SAFE(subsystem, &g_subsystems, tailq, subsystem_tmp) {
102 			depends_on = false;
103 			TAILQ_FOREACH(subsystem_dep, &g_subsystems_deps, tailq) {
104 				if (strcmp(subsystem->name, subsystem_dep->name) == 0) {
105 					depends_on = true;
106 					depends_on_sorted = !!_subsystem_find(&subsystems_list, subsystem_dep->depends_on);
107 					if (depends_on_sorted) {
108 						continue;
109 					}
110 					break;
111 				}
112 			}
113 
114 			if (depends_on == false) {
115 				TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
116 				TAILQ_INSERT_TAIL(&subsystems_list, subsystem, tailq);
117 			} else {
118 				if (depends_on_sorted == true) {
119 					TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
120 					TAILQ_INSERT_TAIL(&subsystems_list, subsystem, tailq);
121 				}
122 			}
123 		}
124 	}
125 
126 	TAILQ_FOREACH_SAFE(subsystem, &subsystems_list, tailq, subsystem_tmp) {
127 		TAILQ_REMOVE(&subsystems_list, subsystem, tailq);
128 		TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq);
129 	}
130 }
131 
132 void
133 spdk_subsystem_init_next(int rc)
134 {
135 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
136 
137 	/* The initialization is interrupted by the spdk_subsystem_fini, so just return */
138 	if (g_subsystems_init_interrupted) {
139 		return;
140 	}
141 
142 	if (rc) {
143 		SPDK_ERRLOG("Init subsystem %s failed\n", g_next_subsystem->name);
144 		g_subsystem_start_fn(rc, g_subsystem_start_arg);
145 		return;
146 	}
147 
148 	if (!g_next_subsystem) {
149 		g_next_subsystem = TAILQ_FIRST(&g_subsystems);
150 	} else {
151 		g_next_subsystem = TAILQ_NEXT(g_next_subsystem, tailq);
152 	}
153 
154 	if (!g_next_subsystem) {
155 		g_subsystems_initialized = true;
156 		g_subsystem_start_fn(0, g_subsystem_start_arg);
157 		return;
158 	}
159 
160 	if (g_next_subsystem->init) {
161 		g_next_subsystem->init();
162 	} else {
163 		spdk_subsystem_init_next(0);
164 	}
165 }
166 
167 void
168 spdk_subsystem_init(spdk_subsystem_init_fn cb_fn, void *cb_arg)
169 {
170 	struct spdk_subsystem_depend *dep;
171 
172 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
173 
174 	g_subsystem_start_fn = cb_fn;
175 	g_subsystem_start_arg = cb_arg;
176 
177 	/* Verify that all dependency name and depends_on subsystems are registered */
178 	TAILQ_FOREACH(dep, &g_subsystems_deps, tailq) {
179 		if (!subsystem_find(dep->name)) {
180 			SPDK_ERRLOG("subsystem %s is missing\n", dep->name);
181 			g_subsystem_start_fn(-1, g_subsystem_start_arg);
182 			return;
183 		}
184 		if (!subsystem_find(dep->depends_on)) {
185 			SPDK_ERRLOG("subsystem %s dependency %s is missing\n",
186 				    dep->name, dep->depends_on);
187 			g_subsystem_start_fn(-1, g_subsystem_start_arg);
188 			return;
189 		}
190 	}
191 
192 	subsystem_sort();
193 
194 	spdk_subsystem_init_next(0);
195 }
196 
197 static void
198 subsystem_fini_next(void *arg1)
199 {
200 	assert(g_fini_thread == spdk_get_thread());
201 
202 	if (!g_next_subsystem) {
203 		/* If the initialized flag is false, then we've failed to initialize
204 		 * the very first subsystem and no de-init is needed
205 		 */
206 		if (g_subsystems_initialized) {
207 			g_next_subsystem = TAILQ_LAST(&g_subsystems, spdk_subsystem_list);
208 		}
209 	} else {
210 		if (g_subsystems_initialized || g_subsystems_init_interrupted) {
211 			g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
212 		} else {
213 			g_subsystems_init_interrupted = true;
214 		}
215 	}
216 
217 	while (g_next_subsystem) {
218 		if (g_next_subsystem->fini) {
219 			g_next_subsystem->fini();
220 			return;
221 		}
222 		g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
223 	}
224 
225 	g_subsystem_stop_fn(g_subsystem_stop_arg);
226 	return;
227 }
228 
229 void
230 spdk_subsystem_fini_next(void)
231 {
232 	if (g_fini_thread != spdk_get_thread()) {
233 		spdk_thread_send_msg(g_fini_thread, subsystem_fini_next, NULL);
234 	} else {
235 		subsystem_fini_next(NULL);
236 	}
237 }
238 
239 void
240 spdk_subsystem_fini(spdk_msg_fn cb_fn, void *cb_arg)
241 {
242 	g_subsystem_stop_fn = cb_fn;
243 	g_subsystem_stop_arg = cb_arg;
244 
245 	g_fini_thread = spdk_get_thread();
246 
247 	spdk_subsystem_fini_next();
248 }
249 
250 void
251 subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsystem *subsystem)
252 {
253 	if (subsystem && subsystem->write_config_json) {
254 		subsystem->write_config_json(w);
255 	} else {
256 		spdk_json_write_null(w);
257 	}
258 }
259