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