xref: /spdk/lib/init/subsystem.c (revision aaba5d9c9e8fca9925d5812030ff3ec9ba869fa3)
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 || depends_on_sorted) {
115 				TAILQ_REMOVE(&g_subsystems, subsystem, tailq);
116 				TAILQ_INSERT_TAIL(&subsystems_list, subsystem, tailq);
117 			}
118 		}
119 	}
120 
121 	TAILQ_FOREACH_SAFE(subsystem, &subsystems_list, tailq, subsystem_tmp) {
122 		TAILQ_REMOVE(&subsystems_list, subsystem, tailq);
123 		TAILQ_INSERT_TAIL(&g_subsystems, subsystem, tailq);
124 	}
125 }
126 
127 void
128 spdk_subsystem_init_next(int rc)
129 {
130 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
131 
132 	/* The initialization is interrupted by the spdk_subsystem_fini, so just return */
133 	if (g_subsystems_init_interrupted) {
134 		return;
135 	}
136 
137 	if (rc) {
138 		SPDK_ERRLOG("Init subsystem %s failed\n", g_next_subsystem->name);
139 		g_subsystem_start_fn(rc, g_subsystem_start_arg);
140 		return;
141 	}
142 
143 	if (!g_next_subsystem) {
144 		g_next_subsystem = TAILQ_FIRST(&g_subsystems);
145 	} else {
146 		g_next_subsystem = TAILQ_NEXT(g_next_subsystem, tailq);
147 	}
148 
149 	if (!g_next_subsystem) {
150 		g_subsystems_initialized = true;
151 		g_subsystem_start_fn(0, g_subsystem_start_arg);
152 		return;
153 	}
154 
155 	if (g_next_subsystem->init) {
156 		g_next_subsystem->init();
157 	} else {
158 		spdk_subsystem_init_next(0);
159 	}
160 }
161 
162 void
163 spdk_subsystem_init(spdk_subsystem_init_fn cb_fn, void *cb_arg)
164 {
165 	struct spdk_subsystem_depend *dep;
166 
167 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
168 
169 	g_subsystem_start_fn = cb_fn;
170 	g_subsystem_start_arg = cb_arg;
171 
172 	/* Verify that all dependency name and depends_on subsystems are registered */
173 	TAILQ_FOREACH(dep, &g_subsystems_deps, tailq) {
174 		if (!subsystem_find(dep->name)) {
175 			SPDK_ERRLOG("subsystem %s is missing\n", dep->name);
176 			g_subsystem_start_fn(-1, g_subsystem_start_arg);
177 			return;
178 		}
179 		if (!subsystem_find(dep->depends_on)) {
180 			SPDK_ERRLOG("subsystem %s dependency %s is missing\n",
181 				    dep->name, dep->depends_on);
182 			g_subsystem_start_fn(-1, g_subsystem_start_arg);
183 			return;
184 		}
185 	}
186 
187 	subsystem_sort();
188 
189 	spdk_subsystem_init_next(0);
190 }
191 
192 static void
193 subsystem_fini_next(void *arg1)
194 {
195 	assert(g_fini_thread == spdk_get_thread());
196 
197 	if (!g_next_subsystem) {
198 		/* If the initialized flag is false, then we've failed to initialize
199 		 * the very first subsystem and no de-init is needed
200 		 */
201 		if (g_subsystems_initialized) {
202 			g_next_subsystem = TAILQ_LAST(&g_subsystems, spdk_subsystem_list);
203 		}
204 	} else {
205 		if (g_subsystems_initialized || g_subsystems_init_interrupted) {
206 			g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
207 		} else {
208 			g_subsystems_init_interrupted = true;
209 		}
210 	}
211 
212 	while (g_next_subsystem) {
213 		if (g_next_subsystem->fini) {
214 			g_next_subsystem->fini();
215 			return;
216 		}
217 		g_next_subsystem = TAILQ_PREV(g_next_subsystem, spdk_subsystem_list, tailq);
218 	}
219 
220 	g_subsystem_stop_fn(g_subsystem_stop_arg);
221 	return;
222 }
223 
224 void
225 spdk_subsystem_fini_next(void)
226 {
227 	if (g_fini_thread != spdk_get_thread()) {
228 		spdk_thread_send_msg(g_fini_thread, subsystem_fini_next, NULL);
229 	} else {
230 		subsystem_fini_next(NULL);
231 	}
232 }
233 
234 void
235 spdk_subsystem_fini(spdk_msg_fn cb_fn, void *cb_arg)
236 {
237 	g_subsystem_stop_fn = cb_fn;
238 	g_subsystem_stop_arg = cb_arg;
239 
240 	g_fini_thread = spdk_get_thread();
241 
242 	spdk_subsystem_fini_next();
243 }
244 
245 void
246 subsystem_config_json(struct spdk_json_write_ctx *w, struct spdk_subsystem *subsystem)
247 {
248 	if (subsystem && subsystem->write_config_json) {
249 		subsystem->write_config_json(w);
250 	} else {
251 		spdk_json_write_null(w);
252 	}
253 }
254