Motr  M0
fom_timedwait_ut.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2017-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 "lib/errno.h"
24 #include "lib/memory.h"
25 #include "lib/semaphore.h"
26 #include "lib/finject.h"
27 #include "rpc/rpc_opcodes.h"
28 #include "fop/fom.h"
29 #include "reqh/reqh.h"
30 #include "reqh/reqh_service.h"
31 #include "ut/ut.h"
32 
33 enum tw_test {
40 };
41 
42 struct tw_fom {
43  struct m0_fom tw_fom;
50 };
51 
57 };
58 
59 static struct m0_sm_state_descr tw_fom_phases[] = {
60  [INIT] = {
62  .sd_name = "init",
63  .sd_allowed = M0_BITS(PHASE1, PHASE2)
64  },
65  [PHASE1] = {
66  .sd_name = "phase1",
67  .sd_allowed = M0_BITS(PHASE2)
68  },
69  [PHASE2] = {
70  .sd_name = "phase2",
71  .sd_allowed = M0_BITS(FINISH)
72  },
73  [FINISH] = {
74  .sd_name = "finish",
75  .sd_flags = M0_SDF_TERMINAL,
76  }
77 };
78 
79 static struct m0_sm_conf tw_sm_conf = {
80  .scf_name = "tw_fom",
81  .scf_nr_states = ARRAY_SIZE(tw_fom_phases),
82  .scf_state = tw_fom_phases,
83 };
84 
85 static struct m0_fom_type tw_fomt;
86 
87 static struct m0_reqh twreqh;
88 static struct m0_reqh_service *twsvc;
89 
90 static void tw_fom_fini(struct m0_fom *fom);
91 static int tw_fom_tick(struct m0_fom *fom);
92 static size_t tw_fom_home_locality(const struct m0_fom *fom);
93 
94 static const struct m0_fom_ops tw_fom_ops = {
96  .fo_tick = tw_fom_tick,
97  .fo_home_locality = tw_fom_home_locality
98 };
99 
101  .fto_create = NULL
102 };
103 
104 /*************************************************/
105 /* UT service */
106 /*************************************************/
107 
108 static int twsvc_start(struct m0_reqh_service *svc);
109 static void twsvc_stop (struct m0_reqh_service *svc);
110 static void twsvc_fini (struct m0_reqh_service *svc);
111 
112 static const struct m0_reqh_service_ops twsvc_ops = {
114  .rso_start = &twsvc_start,
115  .rso_stop = &twsvc_stop,
116  .rso_fini = &twsvc_fini
117 };
118 
119 static int twsvc_start(struct m0_reqh_service *svc)
120 {
121  return 0;
122 }
123 
124 static void twsvc_stop(struct m0_reqh_service *svc)
125 {
126 }
127 
128 static void twsvc_fini(struct m0_reqh_service *svc)
129 {
130  m0_free(svc);
131 }
132 
134  const struct m0_reqh_service_type *stype)
135 {
136  M0_ALLOC_PTR(*svc);
137  M0_UT_ASSERT(*svc != NULL);
138  (*svc)->rs_type = stype;
139  (*svc)->rs_ops = &twsvc_ops;
140  return 0;
141 }
142 
145 };
146 
148  .rst_name = "tw_ut",
149  .rst_ops = &twsvc_type_ops,
150  .rst_level = M0_RS_LEVEL_NORMAL,
151  .rst_typecode = M0_CST_DS1
152 };
153 
154 /*************************************************/
155 /* FOM routines */
156 /*************************************************/
157 
158 static size_t tw_fom_home_locality(const struct m0_fom *fom)
159 {
160  return 1;
161 }
162 
163 static void wakeup(struct m0_sm_group *grp, struct m0_sm_ast *ast)
164 {
165  struct tw_fom *fom = M0_AMB(fom, ast, tw_wakeup);
166  m0_fom_wakeup(&fom->tw_fom);
167 }
168 
169 static void fom_reschedule(struct tw_fom *fom)
170 {
171  struct m0_sm_group *grp;
172 
173  grp = &fom->tw_fom.fo_loc->fl_group;
174  fom->tw_wakeup.sa_cb = wakeup;
175  m0_sm_ast_post(grp, &fom->tw_wakeup);
176 }
177 
178 static int tw_fom_tick(struct m0_fom *fom0)
179 {
180  struct tw_fom *fom = M0_AMB(fom, fom0, tw_fom);
181  int phase = m0_fom_phase(fom0);
182  int result = M0_FSO_AGAIN;
183  enum tw_test test = fom->tw_test;
184 
185  switch (phase) {
186  case INIT:
187  m0_semaphore_up(&fom->tw_sem_init);
188  switch(test) {
191  if (!m0_chan_has_waiters(&fom0->fo_sm_phase.sm_chan)) {
192  /*
193  * Wait until fom waiter used internally in
194  * m0_fom_timedwait() adds clink to the channel.
195  */
197  result = M0_FSO_WAIT;
198  } else {
199  m0_fom_phase_set(fom0,
201  PHASE1 : PHASE2);
202  result = M0_FSO_AGAIN;
203  }
204  break;
208  m0_fom_phase_set(fom0, PHASE1);
209  result = M0_FSO_AGAIN;
210  break;
212  m0_fom_phase_set(fom0, PHASE1);
213  /* Main thread should wake up FOM. */
214  result = M0_FSO_WAIT;
215  break;
216  default:
217  M0_IMPOSSIBLE("Unknown test!");
218  }
219  break;
220  case PHASE1:
221  if (M0_IN(test, (TW_TEST_DELAYED_TIMEOUT,
223  !m0_semaphore_trydown(&fom->tw_sem_timeout)) {
225  result = M0_FSO_WAIT;
226  } else {
227  m0_fom_phase_set(fom0, PHASE2);
228  result = M0_FSO_AGAIN;
229  }
230  break;
231  case PHASE2:
232  m0_fom_phase_set(fom0, FINISH);
233  result = M0_FSO_WAIT;
234  break;
235  default:
236  M0_IMPOSSIBLE("Invalid phase");
237  }
238  return result;
239 }
240 
241 static void tw_fom_create(struct m0_fom **out, struct m0_reqh *reqh,
242  enum tw_test test)
243 {
244  struct m0_fom *fom0;
245  struct tw_fom *fom_obj;
246 
247  M0_PRE(out != NULL);
248 
249  M0_ALLOC_PTR(fom_obj);
250  M0_UT_ASSERT(fom_obj != NULL);
251 
252  fom_obj->tw_test = test;
253  m0_semaphore_init(&fom_obj->tw_sem_init, 0);
254  m0_semaphore_init(&fom_obj->tw_sem_fini, 0);
255  m0_semaphore_init(&fom_obj->tw_sem_timeout, 0);
256  fom0 = &fom_obj->tw_fom;
258  *out = fom0;
259 }
260 
261 static void tw_fom_destroy(struct tw_fom *fom)
262 {
263 
264  m0_semaphore_fini(&fom->tw_sem_init);
265  m0_semaphore_fini(&fom->tw_sem_fini);
266  m0_semaphore_fini(&fom->tw_sem_timeout);
267  m0_free(fom);
268 }
269 
270 static void tw_fom_fini(struct m0_fom *fom)
271 {
272  struct tw_fom *tw_fom = M0_AMB(tw_fom, fom, tw_fom);
273 
274  m0_fom_fini(fom);
276  /* Memory will be deallocated in test itself, see tw_fom_destroy(). */
277 }
278 
279 static void tw_fom_start(struct m0_fom *fom)
280 {
281  struct tw_fom *tw_fom = M0_AMB(tw_fom, fom, tw_fom);
282 
283  m0_fom_queue(fom);
284  /* Wait until the fom is really executed. */
286 }
287 
288 static void tw_fom_timeout_signal(struct m0_fom *fom)
289 {
290  struct tw_fom *tw_fom = M0_AMB(tw_fom, fom, tw_fom);
291 
293 }
294 
295 /*************************************************/
296 /* REQH routines */
297 /*************************************************/
298 
299 static void reqh_init(void)
300 {
301  int rc;
302 
304  .rhia_dtm = (void *)1,
305  .rhia_mdstore = (void *)1,
306  .rhia_fid = &g_process_fid);
307  M0_UT_ASSERT(rc == 0);
308 }
309 
310 static void reqh_start(void)
311 {
312  int rc;
313 
315  M0_UT_ASSERT(rc == 0);
319 }
320 
321 static void reqh_stop(void)
322 {
327 }
328 
329 static void reqh_fini(void)
330 {
333 }
334 
335 /*************************************************/
336 /* UT init/fini */
337 /*************************************************/
338 
339 static struct m0_fom *tw_init(enum tw_test test)
340 {
341  struct m0_fom *tw_fom;
342 
343  reqh_init();
344  reqh_start();
347  return tw_fom;
348 }
349 
350 static void tw_fini(struct m0_fom *fom0)
351 {
352  struct tw_fom *fom = M0_AMB(fom, fom0, tw_fom);
353 
354  reqh_stop();
355  /* Assure that FOM is finalised. */
356  m0_semaphore_down(&fom->tw_sem_fini);
357  reqh_fini();
359 }
360 
361 /*************************************************/
362 /* Test cases */
363 /*************************************************/
364 
365 static void immediate_success(void)
366 {
367  struct m0_fom *tw_fom;
368  int rc;
369 
372  M0_UT_ASSERT(rc == 0);
373  /* FOM should wait after moving to PHASE1, wakeup it. */
375  tw_fini(tw_fom);
376 }
377 
378 static void delayed_success(void)
379 {
380  struct m0_fom *tw_fom;
381  int rc;
382 
385  M0_UT_ASSERT(rc == 0);
386  tw_fini(tw_fom);
387 }
388 
389 static void immediate_timeout(void)
390 {
391  struct m0_fom *tw_fom;
392  int rc;
393 
396  M0_UT_ASSERT(rc == -ETIMEDOUT);
398  tw_fini(tw_fom);
399 }
400 
401 static void delayed_timeout(void)
402 {
403  struct m0_fom *tw_fom;
404  int rc;
405 
408  m0_time_now() + 100 * M0_TIME_ONE_MSEC);
409  M0_UT_ASSERT(rc == -ETIMEDOUT);
411  tw_fini(tw_fom);
412 }
413 
414 static void immediate_unreachable(void)
415 {
416  struct m0_fom *tw_fom;
417  int rc;
418 
421  M0_UT_ASSERT(rc == -ESRCH);
422  tw_fini(tw_fom);
423 }
424 
425 static void delayed_unreachable(void)
426 {
427  struct m0_fom *tw_fom;
428  int rc;
429 
432  M0_UT_ASSERT(rc == -ESRCH);
433  tw_fini(tw_fom);
434 }
435 
437 {
440  &tw_sm_conf);
441  return 0;
442 }
443 
445  .ts_name = "fom-timedwait-ut",
446  .ts_init = tw_test_suite_init,
447  .ts_fini = NULL,
448  .ts_tests = {
449  { "immediate-success", immediate_success },
450  { "delayed-success", delayed_success },
451  { "immediate-timeout", immediate_timeout },
452  { "delayed-timeout", delayed_timeout },
453  { "immediate-unreachable", immediate_unreachable },
454  { "delayed-unreachable", delayed_unreachable },
455  { NULL, NULL }
456  }
457 };
458 
459 M0_EXPORTED(fom_timedwait_ut);
460 
461 /*
462  * Local variables:
463  * c-indentation-style: "K&R"
464  * c-basic-offset: 8
465  * tab-width: 8
466  * fill-column: 80
467  * scroll-step: 1
468  * End:
469  */
470 /*
471  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
472  */
static void delayed_unreachable(void)
static struct m0_reqh twreqh
M0_INTERNAL void m0_fom_wakeup(struct m0_fom *fom)
Definition: fom.c:532
#define M0_PRE(cond)
M0_INTERNAL int m0_reqh_service_start(struct m0_reqh_service *service)
Definition: reqh_service.c:343
M0_INTERNAL void m0_reqh_services_terminate(struct m0_reqh *reqh)
Definition: reqh.c:675
M0_INTERNAL void m0_reqh_service_stop(struct m0_reqh_service *service)
Definition: reqh_service.c:402
#define NULL
Definition: misc.h:38
M0_INTERNAL bool m0_semaphore_trydown(struct m0_semaphore *semaphore)
Definition: semaphore.c:60
static void reqh_start(void)
#define M0_REQH_INIT(reqh,...)
Definition: reqh.h:262
Definition: sm.h:350
const m0_time_t M0_TIME_NEVER
Definition: time.c:108
static void wakeup(struct m0_sm_group *grp, struct m0_sm_ast *ast)
M0_INTERNAL bool m0_chan_has_waiters(struct m0_chan *chan)
Definition: chan.c:185
static struct m0_sm_group * grp
Definition: bytecount.c:38
M0_INTERNAL void m0_reqh_service_prepare_to_stop(struct m0_reqh_service *service)
Definition: reqh_service.c:375
M0_INTERNAL void m0_sm_ast_post(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: sm.c:135
tw_fom_phase
struct m0_ut_suite fom_timedwait_ut
int(* fto_create)(struct m0_fop *fop, struct m0_fom **out, struct m0_reqh *reqh)
Definition: fom.h:650
static void delayed_success(void)
struct m0_fom tw_fom
#define M0_BITS(...)
Definition: misc.h:236
static int tw_fom_tick(struct m0_fom *fom)
Definition: sm.h:504
Definition: ut.h:77
static void immediate_success(void)
M0_INTERNAL void m0_reqh_fini(struct m0_reqh *reqh)
Definition: reqh.c:320
static void delayed_timeout(void)
struct tpool_test test[]
Definition: thread_pool.c:45
m0_fom_phase
Definition: fom.h:372
static struct m0_reqh_service_type ut_tw_service_type
struct m0_semaphore tw_sem_init
static const struct m0_reqh_service_type_ops twsvc_type_ops
static struct m0_sm_ast ast[NR]
Definition: locality.c:44
void m0_fom_init(struct m0_fom *fom, const struct m0_fom_type *fom_type, const struct m0_fom_ops *ops, struct m0_fop *fop, struct m0_fop *reply, struct m0_reqh *reqh)
Definition: fom.c:1372
enum tw_test tw_test
static size_t tw_fom_home_locality(const struct m0_fom *fom)
tw_test
static void tw_fom_fini(struct m0_fom *fom)
#define M0_AMB(obj, ptr, field)
Definition: misc.h:320
static const struct socktype stype[]
Definition: sock.c:1156
static const struct m0_reqh_service_ops twsvc_ops
void m0_fom_fini(struct m0_fom *fom)
Definition: fom.c:1324
const char * scf_name
Definition: sm.h:352
struct m0_semaphore tw_sem_timeout
m0_time_t m0_time_now(void)
Definition: time.c:134
const char * rst_name
Definition: reqh_service.h:447
M0_INTERNAL void m0_reqh_service_fini(struct m0_reqh_service *service)
Definition: reqh_service.c:457
int tw_test_suite_init(void)
M0_INTERNAL void m0_fom_type_init(struct m0_fom_type *type, uint64_t id, const struct m0_fom_type_ops *ops, const struct m0_reqh_service_type *svc_type, const struct m0_sm_conf *sm)
Definition: fom.c:1596
static void reqh_stop(void)
M0_INTERNAL int m0_semaphore_init(struct m0_semaphore *semaphore, unsigned value)
Definition: semaphore.c:38
static void tw_fom_start(struct m0_fom *fom)
static void twsvc_fini(struct m0_reqh_service *svc)
M0_INTERNAL int m0_reqh_service_allocate(struct m0_reqh_service **out, const struct m0_reqh_service_type *stype, struct m0_reqh_context *rctx)
Definition: reqh_service.c:185
static struct m0_reqh_service * twsvc
Definition: reqh.h:94
Definition: dump.c:103
static void immediate_timeout(void)
M0_INTERNAL void m0_reqh_service_init(struct m0_reqh_service *service, struct m0_reqh *reqh, const struct m0_fid *fid)
Definition: reqh_service.c:428
static struct m0_fom_type tw_fomt
struct m0_sm_ast tw_wakeup
int m0_reqh_service_async_start_simple(struct m0_reqh_service_start_async_ctx *asc)
Definition: reqh_service.c:601
static int twsvc_type_allocate(struct m0_reqh_service **svc, const struct m0_reqh_service_type *stype)
M0_INTERNAL int m0_fom_timedwait(struct m0_fom *fom, uint64_t phases, m0_time_t deadline)
Definition: fom.c:724
uint32_t sd_flags
Definition: sm.h:378
Definition: fom.h:481
const char * ts_name
Definition: ut.h:99
static void fom_reschedule(struct tw_fom *fom)
static struct m0_sm_conf tw_sm_conf
M0_INTERNAL void m0_reqh_start(struct m0_reqh *reqh)
Definition: reqh.c:711
struct m0_reqh reqh
Definition: rm_foms.c:48
int(* rsto_service_allocate)(struct m0_reqh_service **service, const struct m0_reqh_service_type *stype)
Definition: reqh_service.h:435
static int twsvc_start(struct m0_reqh_service *svc)
static struct m0_sm_state_descr tw_fom_phases[]
static void reqh_fini(void)
static void twsvc_stop(struct m0_reqh_service *svc)
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
struct m0_chan sm_chan
Definition: sm.h:331
M0_INTERNAL void m0_semaphore_fini(struct m0_semaphore *semaphore)
Definition: semaphore.c:45
Definition: list.c:42
static void tw_fini(struct m0_fom *fom0)
struct m0_semaphore tw_sem_fini
static struct m0_net_test_service svc
Definition: service.c:34
static void reqh_init(void)
struct m0_fom_timeout tw_timeout
M0_INTERNAL void m0_reqh_idle_wait_for(struct m0_reqh *reqh, struct m0_reqh_service *service)
Definition: reqh.c:591
M0_INTERNAL void m0_fom_queue(struct m0_fom *fom)
Definition: fom.c:624
struct m0_sm fo_sm_phase
Definition: fom.h:522
void(* fo_fini)(struct m0_fom *fom)
Definition: fom.h:657
static const struct m0_fom_ops tw_fom_ops
static void tw_fom_create(struct m0_fom **out, struct m0_reqh *reqh, enum tw_test test)
M0_INTERNAL void m0_semaphore_down(struct m0_semaphore *semaphore)
Definition: semaphore.c:49
const struct m0_fom_type_ops tw_fom_type_ops
#define out(...)
Definition: gen.c:41
void m0_fom_phase_set(struct m0_fom *fom, int phase)
Definition: fom.c:1688
M0_INTERNAL void m0_semaphore_up(struct m0_semaphore *semaphore)
Definition: semaphore.c:65
static void tw_fom_destroy(struct tw_fom *fom)
void m0_free(void *data)
Definition: memory.c:146
static void immediate_unreachable(void)
static struct m0_fom * tw_init(enum tw_test test)
static void tw_fom_timeout_signal(struct m0_fom *fom)
int32_t rc
Definition: trigger_fop.h:47
int(* rso_start_async)(struct m0_reqh_service_start_async_ctx *asc)
Definition: reqh_service.h:341
#define ARRAY_SIZE(a)
Definition: misc.h:45
struct m0_fid g_process_fid
Definition: ut.c:689
#define M0_UT_ASSERT(a)
Definition: ut.h:46
#define M0_IMPOSSIBLE(fmt,...)