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