Motr  M0
module.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2014-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #include "module/instance.h"
24 #include "module/param.h"
25 #include "lib/string.h" /* m0_streq */
26 #include "lib/thread.h" /* m0_thread */
27 #include "ut/ut.h"
28 
29 static char g_log[32] = "";
30 static struct m0 *g_instance;
31 
32 static void _log(char c1, char c2)
33 {
34  int rc;
35  size_t len = strlen(g_log);
36 
37  M0_PRE(len + 2 < sizeof g_log);
38 
39  rc = snprintf(g_log + len, sizeof(g_log) - len, "%c%c", c1, c2);
40  M0_ASSERT(rc == 2);
41 }
42 
43 static int modlev_enter(struct m0_module *module)
44 {
45  /* Append "<module name> <next level>" record (2 chars) to the log. */
46  _log(*module->m_name, '0' + module->m_cur + 1);
47  return 0;
48 }
49 
50 static void modlev_leave(struct m0_module *module)
51 {
52  /* Append "<module name> <current level>" record to the log. */
53  _log(*module->m_name, '0' + module->m_cur);
54 }
55 
56 static struct m0_module modules[] = {
57  { .m_name = "a" },
58  { .m_name = "b" },
59  { .m_name = "c" },
60  { .m_name = "d" },
61  { .m_name = "e" },
62  { .m_name = "f" },
63  { .m_name = "g" },
64  { .m_name = "h" },
65  { .m_name = "i" }
66 };
67 enum module_id { A, B, C, D, E, F, G, H, I };
68 
69 /* +------+
70  * | c1 |
71  * +------+ +------+
72  * | b3 |----->| c0 |---.
73  * +------+ +------+ +------+ |
74  * | a3 | ~~-> | b2 |<--. |
75  * +------+ +------+ | |
76  * | a2 | | b1 | | |
77  * +------+ +------+ | +------+ |
78  * | a1 |<-----| b0 | | | d2 |<--'
79  * +------+ +------+ | +------+
80  * | a0 | `--| d1 |
81  * +------+ +------+
82  * | d0 |
83  * +------+
84  */
85 
86 static const struct m0_modlev levels[] = {
87  { .ml_enter = modlev_enter, .ml_leave = modlev_leave },
88  { .ml_enter = modlev_enter, .ml_leave = modlev_leave },
89  { .ml_enter = modlev_enter, .ml_leave = modlev_leave },
90  { .ml_enter = modlev_enter, .ml_leave = modlev_leave }
91 };
92 
93 static struct m0_moddep dep_a[] = { /* no dependencies initially */ };
94 static struct m0_moddep inv_a[] = { M0_MODDEP_INIT(&modules[B], 0, 1) };
95 
96 static struct m0_moddep dep_b[] = {
97  M0_MODDEP_INIT(&modules[A], 0, 1),
98  M0_MODDEP_INIT(&modules[C], 3, 0)
99 };
100 static struct m0_moddep inv_b[] = { M0_MODDEP_INIT(&modules[D], 1, 2) };
101 
102 static struct m0_moddep dep_c[] = { M0_MODDEP_INIT(&modules[D], 0, 2) };
103 static struct m0_moddep inv_c[] = { M0_MODDEP_INIT(&modules[B], 3, 0) };
104 
105 static struct m0_moddep dep_d[] = { M0_MODDEP_INIT(&modules[B], 1, 2) };
106 static struct m0_moddep inv_d[] = { M0_MODDEP_INIT(&modules[C], 0, 2) };
107 
108 /* +------+
109  * +------+ ,--------------->| i0 |---.
110  * | f3 |---' +------+ |
111  * +------+ +------+ |
112  * | f2 |----->| g2 |<----------------{
113  * +------+ +------+ |
114  * ,-->| f1 | | g1 | |
115  * +------+ | +------+ +------+ +------+ |
116  * | e0 |--' | f0 | | g0 |----->| h0 |<--'
117  * +------+ +------+ +------+ +------+
118  */
119 
120 static struct m0_moddep dep_e[] = { M0_MODDEP_INIT(&modules[F], 0, 1) };
121 static struct m0_moddep inv_e[0];
122 
123 static struct m0_moddep dep_f[] = {
124  M0_MODDEP_INIT(&modules[G], 2, 2),
125  M0_MODDEP_INIT(&modules[I], 3, 0)
126 };
127 static struct m0_moddep inv_f[] = { M0_MODDEP_INIT(&modules[E], 0, 1) };
128 
129 static struct m0_moddep dep_g[] = { M0_MODDEP_INIT(&modules[H], 0, 0) };
130 static struct m0_moddep inv_g[] = {
131  M0_MODDEP_INIT(&modules[F], 2, 2),
132  M0_MODDEP_INIT(&modules[I], 0, 2)
133 };
134 
135 static struct m0_moddep dep_h[0];
136 static struct m0_moddep inv_h[] = {
137  M0_MODDEP_INIT(&modules[G], 0, 0),
138  M0_MODDEP_INIT(&modules[I], 0, 0)
139 };
140 
141 static struct m0_moddep dep_i[] = {
142  M0_MODDEP_INIT(&modules[G], 0, 2),
143  M0_MODDEP_INIT(&modules[H], 0, 0)
144 };
145 static struct m0_moddep inv_i[] = { M0_MODDEP_INIT(&modules[F], 3, 0) };
146 
147 static void _reset(void)
148 {
149  static struct {
150  int level_nr;
151  struct m0_moddep *dep;
152  unsigned dep_nr;
153  struct m0_moddep *inv;
154  unsigned inv_nr;
155  } mods[] = {
156 #define ARR_INIT(name) name, ARRAY_SIZE(name)
157 #define MOD_REC(name, nr_levels) \
158  { (nr_levels), ARR_INIT(dep_ ## name), ARR_INIT(inv_ ## name) }
159 
160  MOD_REC(a, 4),
161  MOD_REC(b, 4),
162  MOD_REC(c, 2),
163  MOD_REC(d, 3),
164  MOD_REC(e, 1),
165  MOD_REC(f, 4),
166  MOD_REC(g, 3),
167  MOD_REC(h, 1),
168  MOD_REC(i, 1)
169 #undef MOD_REC
170 #undef ARR_INIT
171  };
172  unsigned i;
173 
175  for (i = 0; i < ARRAY_SIZE(mods); ++i) {
176  modules[i].m_m0 = m0_get();
178  M0_ASSERT(mods[i].level_nr <= ARRAY_SIZE(levels));
179  modules[i].m_level = levels;
180  modules[i].m_level_nr = mods[i].level_nr;
181  modules[i].m_dep_nr = mods[i].dep_nr;
182  modules[i].m_inv_nr = mods[i].inv_nr;
183  memcpy(modules[i].m_dep, mods[i].dep,
184  mods[i].dep_nr * sizeof modules[i].m_dep[0]);
185  memcpy(modules[i].m_inv, mods[i].inv,
186  mods[i].inv_nr * sizeof modules[i].m_inv[0]);
187  }
188  *g_log = 0;
189 }
190 
191 static int cur(enum module_id id)
192 {
193  M0_PRE(IS_IN_ARRAY(id, modules));
194  return modules[id].m_cur;
195 }
196 
197 static void _test_module_init(void)
198 {
199  int rc;
200 
201  _reset();
202 
204  cur(i) == M0_MODLEV_NONE));
205  rc = m0_module_init(&modules[B], 1);
206  M0_UT_ASSERT(rc == 0);
207  M0_UT_ASSERT(cur(A) == 1);
208  M0_UT_ASSERT(cur(B) == 1);
211  M0_UT_ASSERT(m0_streq(g_log, "a0a1b0b1"));
212 
213  rc = m0_module_init(&modules[B], 3);
214  M0_UT_ASSERT(rc == 0);
215  M0_UT_ASSERT(cur(A) == 1);
216  M0_UT_ASSERT(cur(B) == 3);
217  M0_UT_ASSERT(cur(C) == 0);
218  M0_UT_ASSERT(cur(D) == 2);
219  M0_UT_ASSERT(m0_streq(g_log, "a0a1b0b1b2d0d1d2c0b3"));
220 }
221 
222 static void _test_module_fini(void)
223 {
224  *g_log = 0;
225 
231  M0_UT_ASSERT(m0_streq(g_log, "b3c0d2d1b2b1b0a1a0d0"));
232 
233  m0_module_fini(&modules[A], M0_MODLEV_NONE); /* a noop */
234 }
235 
236 static int modlev_a2_enter(struct m0_module *module)
237 {
238  M0_PRE(module == &modules[A]);
239 
240  m0_module_dep_add(module, 3, &modules[B], 2);
241  return modlev_enter(module);
242 }
243 
244 static void _test_module_dep_add(void)
245 {
246  struct m0_modlev levels_a[ARRAY_SIZE(levels)];
247  int rc;
248 
249  _reset();
250 
251  memcpy(levels_a, levels, sizeof levels);
252  levels_a[2].ml_enter = modlev_a2_enter;
253  M0_ASSERT(modules[A].m_level == levels);
254  modules[A].m_level = levels_a;
255 
256  M0_UT_ASSERT(modules[A].m_dep_nr == 0);
257  /*
258  * m0_module_dep_add() is called implicitly: ->m_enter() callback,
259  * invoked when module A enters level 2, creates a3 -> b2 dependency.
260  */
261  rc = m0_module_init(&modules[A], 3);
262  M0_UT_ASSERT(rc == 0);
263  M0_UT_ASSERT(modules[A].m_dep_nr == 1);
264  M0_UT_ASSERT(cur(A) == 3);
265  M0_UT_ASSERT(cur(B) == 2);
268  M0_UT_ASSERT(m0_streq(g_log, "a0a1a2b0b1b2a3"));
269 
271 }
272 
273 static void _test_module_fini_all(void)
274 {
275  int rc;
276 
277  _reset();
278 
279  rc = m0_module_init(&modules[E], 0) ?: m0_module_init(&modules[F], 3);
280  M0_UT_ASSERT(rc == 0);
281  M0_UT_ASSERT(cur(E) == 0);
282  M0_UT_ASSERT(cur(F) == 3);
283  M0_UT_ASSERT(cur(G) == 2);
284  M0_UT_ASSERT(cur(H) == 0);
285  M0_UT_ASSERT(cur(I) == 0);
286  M0_UT_ASSERT(m0_streq(g_log, "f0f1e0h0g0g1g2f2i0f3"));
287 
288  *g_log = 0;
290  M0_UT_ASSERT(cur(E) == 0);
291  M0_UT_ASSERT(cur(F) == 1);
295  M0_UT_ASSERT(m0_streq(g_log, "f3i0f2g2g1g0h0"));
296 
300  M0_UT_ASSERT(m0_streq(g_log, "f3i0f2g2g1g0h0e0f1f0"));
301 }
302 
303 /* amb
304  * +---------+
305  * | |
306  * | foo | bar
307  * | +-----+ | +-----+
308  * | | 0 |<-----| 0 |
309  * | +-----+ | +-----+
310  * +---------+
311  */
312 
313 /*
314  * This ambient structure is not needed for _test_module_alt_init() to
315  * work, but it resembles the structure of m0 instance and is used for
316  * thinking over the initialisation of struct m0:
317  *
318  * amb ~ m0, amb::a_foo ~ m0::i_net ("~" stands for "resembles").
319  *
320  * XXX DELETEME: Get rid of _test_module_alt_init(), struct amb, and the
321  * accompanying functions, once the initialisation of m0 instance with
322  * m0_module_init() is in place.
323  */
324 struct amb {
326  struct m0_module a_foo;
327 };
328 
329 static void foobar_setup(struct m0_module *self, const char *name,
330  struct m0_module *other, bool source)
331 {
332  static const struct m0_modlev levels[] = {
333  { .ml_enter = modlev_enter }
334  };
335  struct m0_moddep deps[] = { M0_MODDEP_INIT(other, 0, 0) };
336 
337  *self = (struct m0_module){
338  .m_name = name,
339  .m_m0 = m0_get(),
340  .m_cur = M0_MODLEV_NONE,
341  .m_level = levels,
342  .m_level_nr = ARRAY_SIZE(levels)
343  };
344 
345  if (source) {
346  memcpy(self->m_dep, deps, sizeof deps);
347  self->m_dep_nr = ARRAY_SIZE(deps);
348  } else {
349  memcpy(self->m_inv, deps, sizeof deps);
350  self->m_inv_nr = ARRAY_SIZE(deps);
351  }
352 }
353 
354 static void amb_setup(struct amb *amb, struct m0_module *bar)
355 {
356  *amb = (struct amb){
357  .a_self = { .m_name = "amb module" }
358  /*
359  * Static initialiser of amb::a_foo is not available,
360  * because the initialisers of m0_module::m_{level,dep,inv}
361  * arrays are not visible here. This situation is quite
362  * common.
363  */
364  };
365  foobar_setup(&amb->a_foo, "foo module", bar, false);
366 }
367 
368 static void _test_module_alt_init(void)
369 {
370  struct amb amb;
371  struct m0_module bar;
372  int rc;
373 
374  amb_setup(&amb, &bar);
375  foobar_setup(&bar, "bar module", &amb.a_foo, true);
376 
377  *g_log = 0;
378  rc = m0_module_init(&bar, 0);
379  M0_UT_ASSERT(rc == 0);
380  M0_UT_ASSERT(amb.a_foo.m_cur == 0);
381  M0_UT_ASSERT(bar.m_cur == 0);
382  M0_UT_ASSERT(m0_streq(g_log, "f0b0"));
384 }
385 
386 static void test_module(void)
387 {
393 }
394 
395 static void inherit(int _)
396 {
397  struct m0 *orig;
398  struct m0 *inst;
399  struct m0 local;
400 
401  orig = inst = m0_get();
402  M0_UT_ASSERT(inst == g_instance);
403 
404  m0_set(&local);
405  inst = m0_get();
406  /*
407  * We cannot use M0_UT_ASSERT() here, because m0_ut_assertimpl()
408  * obtains the address of m0_ut_module from m0 instance, and since
409  * `local' is zeroed, no valid pointers can be obtained from it.
410  */
411  M0_ASSERT(inst == &local);
412  m0_set(orig);
413 }
414 
415 static void test_instance(void)
416 {
417  struct m0_thread t = {0};
418  struct m0 *inst;
419  int rc;
420 
421  g_instance = m0_get();
422 
423  rc = M0_THREAD_INIT(&t, int, NULL, &inherit, 0, "heir");
424  M0_ASSERT(rc == 0);
425  m0_thread_join(&t);
426 
427  /* Ensure that subthread's m0_set() has no impact on current thread's
428  * TLS. */
429  inst = m0_get();
430  M0_UT_ASSERT(inst == g_instance);
431 }
432 
433 static const char *kv_get(const struct m0_param_source *_, const char *key)
434 {
435  static struct {
436  const char *key;
437  const char *val;
438  } db[] = {
439  { "rose", "red" },
440  { "violet", "blue" }
441  };
442  unsigned i;
443 
444  for (i = 0; i < ARRAY_SIZE(db); ++i) {
445  if (m0_streq(db[i].key, key))
446  return db[i].val;
447  }
448  return NULL;
449 }
450 
451 static void test_param(void)
452 {
453  struct m0_param_source param = {
454  .ps_param_get = (void *(*)(const struct m0_param_source *,
455  const char *))kv_get
456  };
457  const char *s;
458 
460  s = m0_param_get("rose");
461  M0_UT_ASSERT(m0_streq(s, "red"));
462  s = m0_param_get("daisy");
463  M0_UT_ASSERT(s == NULL);
465 }
466 
468  .ts_name = "module-ut",
469  .ts_tests = {
470  { "module", test_module },
471  { "instance", test_instance },
472  { "param", test_param },
473  { NULL, NULL }
474  }
475 };
476 
477 /*
478  * Local variables:
479  * c-indentation-style: "K&R"
480  * c-basic-offset: 8
481  * tab-width: 8
482  * fill-column: 80
483  * scroll-step: 1
484  * End:
485  */
486 /*
487  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
488  */
uint64_t id
Definition: cob.h:2380
static struct m0_dtm_local_remote local
Definition: transmit.c:71
static char g_log[32]
Definition: module.c:29
#define M0_PRE(cond)
static const char * kv_get(const struct m0_param_source *_, const char *key)
Definition: module.c:433
static struct m0_moddep inv_h[]
Definition: module.c:136
static struct m0_moddep dep_c[]
Definition: module.c:102
module_id
Definition: module.c:67
static struct m0_moddep dep_b[]
Definition: module.c:96
#define NULL
Definition: misc.h:38
Definition: idx_mock.c:52
Definition: module.c:324
int m0_thread_join(struct m0_thread *q)
Definition: kthread.c:169
static FILE * f
Definition: adieu.c:79
M0_INTERNAL void m0_set(struct m0 *instance)
Definition: instance.c:48
#define M0_CASSERT(cond)
unsigned m_dep_nr
Definition: module.h:177
static struct m0_module modules[]
Definition: module.c:56
static int modlev_a2_enter(struct m0_module *module)
Definition: module.c:236
static struct m0_moddep inv_f[]
Definition: module.c:127
static void amb_setup(struct amb *amb, struct m0_module *bar)
Definition: module.c:354
static struct m0 * g_instance
Definition: module.c:30
#define M0_THREAD_INIT(thread, TYPE, init, func, arg, namefmt,...)
Definition: thread.h:139
const char * name
Definition: module.c:60
M0_INTERNAL struct m0 * m0_get(void)
Definition: instance.c:41
static void _reset(void)
Definition: module.c:147
static int cur(enum module_id id)
Definition: module.c:191
Definition: ut.h:77
static int modlev_enter(struct m0_module *module)
Definition: module.c:43
struct m0 * m_m0
Definition: module.h:153
M0_INTERNAL void m0_param_source_del(struct m0_param_source *src)
Definition: param.c:62
static void _test_module_alt_init(void)
Definition: module.c:368
Definition: module.c:67
const char * m_name
Definition: module.h:152
static struct m0_moddep inv_a[]
Definition: module.c:94
static const struct m0_modlev levels[]
Definition: module.c:86
Definition: hash.c:34
int i
Definition: dir.c:1033
M0_INTERNAL void * m0_param_get(const char *key)
Definition: param.c:44
static void inherit(int _)
Definition: module.c:395
static void test_param(void)
Definition: module.c:451
unsigned m_inv_nr
Definition: module.h:180
struct m0_ut_suite module_ut
Definition: module.c:467
static void modlev_leave(struct m0_module *module)
Definition: module.c:50
static struct m0_moddep dep_a[]
Definition: module.c:93
static struct m0_moddep inv_i[]
Definition: module.c:145
static int key
Definition: locality.c:283
Definition: module.c:67
static void test_instance(void)
Definition: module.c:415
static void _test_module_dep_add(void)
Definition: module.c:244
#define M0_ASSERT(cond)
static struct m0_moddep dep_f[]
Definition: module.c:123
static struct m0_moddep inv_b[]
Definition: module.c:100
static struct m0_addb2_callback c
Definition: consumer.c:41
static struct m0_thread t[8]
Definition: service_ut.c:1230
#define m0_streq(a, b)
Definition: string.h:34
int(* ml_enter)(struct m0_module *module)
Definition: module.h:119
Definition: instance.h:80
static void _test_module_fini_all(void)
Definition: module.c:273
#define MOD_REC(name, nr_levels)
struct m0_module a_self
Definition: module.c:325
int m_level_nr
Definition: module.h:168
#define m0_forall(var, nr,...)
Definition: misc.h:112
Definition: module.c:67
const char * ts_name
Definition: ut.h:99
static void _test_module_init(void)
Definition: module.c:197
M0_INTERNAL void m0_module_dep_add(struct m0_module *m0, int l0, struct m0_module *m1, int l1)
Definition: module.c:168
#define M0_MODDEP_INIT(other, src, dst)
Definition: module.h:137
static void _test_module_fini(void)
Definition: module.c:222
static struct m0_moddep dep_e[]
Definition: module.c:120
static struct m0_moddep inv_c[]
Definition: module.c:103
Definition: module.c:67
M0_INTERNAL void m0_param_source_add(struct m0_param_source *src)
Definition: param.c:56
Definition: module.c:67
struct m0_module a_foo
Definition: module.c:326
static struct m0_moddep dep_i[]
Definition: module.c:141
int m_cur
Definition: module.h:160
static struct m0_moddep inv_d[]
Definition: module.c:106
Definition: module.c:67
#define IS_IN_ARRAY(idx, array)
Definition: misc.h:311
static struct m0_moddep inv_e[0]
Definition: module.c:121
static struct m0_moddep inv_g[]
Definition: module.c:130
static void test_module(void)
Definition: module.c:386
static struct m0_moddep dep_d[]
Definition: module.c:105
static struct m0_moddep dep_g[]
Definition: module.c:129
Definition: module.c:67
Definition: module.c:67
Definition: net.c:93
static struct gen g[MAX_GEN]
Definition: beck.c:521
static struct m0_moddep dep_h[0]
Definition: module.c:135
static struct m0_addb2_source * s
Definition: consumer.c:39
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
#define M0_UT_ASSERT(a)
Definition: ut.h:46
M0_INTERNAL void m0_module_fini(struct m0_module *module, int level)
Definition: module.c:142
const struct m0_modlev * m_level
Definition: module.h:167
static void _log(char c1, char c2)
Definition: module.c:32
Definition: module.c:67
Definition: idx_mock.c:47
M0_INTERNAL int m0_module_init(struct m0_module *module, int level)
Definition: module.c:131
static void foobar_setup(struct m0_module *self, const char *name, struct m0_module *other, bool source)
Definition: module.c:329