Motr  M0
timer.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2015-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/timer.h"
24 
25 #include <time.h> /* timer_create */
26 #include <signal.h> /* timer_create */
27 #include <unistd.h> /* syscall */
28 #include <sys/syscall.h> /* syscall */
29 
30 #include "lib/errno.h" /* errno */
31 #include "lib/thread.h" /* m0_thread */
32 #include "lib/memory.h" /* M0_ALLOC_PTR */
33 #include "lib/mutex.h" /* m0_mutex */
34 #include "lib/semaphore.h" /* m0_semaphore */
35 
36 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_LIB
37 #include "lib/trace.h"
38 
49 #define TIMER_SIGNO SIGRTMIN
50 
51 static const m0_time_t zero_time = M0_MKTIME(0, 0);
53 static int clock_source_timer = -1;
54 
58 M0_TL_DESCR_DEFINE(tid, "thread IDs", static, struct m0_timer_tid,
59  tt_linkage, tt_magic,
60  0x696c444954726d74,
62  0x686c444954726d74);
64 M0_TL_DEFINE(tid, static, struct m0_timer_tid);
65 
70 static pid_t _gettid()
71 {
72  return syscall(SYS_gettid);
73 }
74 
75 M0_INTERNAL void m0_timer_locality_init(struct m0_timer_locality *loc)
76 {
77  M0_PRE(loc != NULL);
78 
79  m0_mutex_init(&loc->tlo_lock);
80  tid_tlist_init(&loc->tlo_tids);
81  loc->tlo_rrtid = NULL;
82 }
83 
84 M0_INTERNAL void m0_timer_locality_fini(struct m0_timer_locality *loc)
85 {
86  M0_PRE(loc != NULL);
87 
88  m0_mutex_fini(&loc->tlo_lock);
89  tid_tlist_fini(&loc->tlo_tids);
90 }
91 
93  pid_t tid)
94 {
95  struct m0_timer_tid *tt;
96 
97  M0_PRE(loc != NULL);
98 
99  m0_mutex_lock(&loc->tlo_lock);
100  m0_tl_for(tid, &loc->tlo_tids, tt) {
101  if (tt->tt_tid == tid)
102  break;
103  } m0_tl_endfor;
104  m0_mutex_unlock(&loc->tlo_lock);
105 
106  return tt;
107 }
108 
110 {
111  pid_t tid = 0;
112 
113  if (loc != NULL) {
114  m0_mutex_lock(&loc->tlo_lock);
115  if (!tid_tlist_is_empty(&loc->tlo_tids)) {
116  if (loc->tlo_rrtid == NULL)
117  loc->tlo_rrtid = tid_tlist_head(&loc->tlo_tids);
118  tid = loc->tlo_rrtid->tt_tid;
119  loc->tlo_rrtid = tid_tlist_next(&loc->tlo_tids,
120  loc->tlo_rrtid);
121  }
122  m0_mutex_unlock(&loc->tlo_lock);
123  }
124  return tid;
125 }
126 
127 M0_INTERNAL int m0_timer_thread_attach(struct m0_timer_locality *loc)
128 {
129  struct m0_timer_tid *tt;
130  pid_t tid;
131  int rc;
132 
133  M0_PRE(loc != NULL);
134 
135  tid = _gettid();
136  M0_ASSERT(locality_tid_find(loc, tid) == NULL);
137 
138  M0_ALLOC_PTR(tt);
139  if (tt == NULL) {
140  rc = -ENOMEM;
141  } else {
142  tt->tt_tid = tid;
143 
144  m0_mutex_lock(&loc->tlo_lock);
145  tid_tlink_init_at_tail(tt, &loc->tlo_tids);
146  m0_mutex_unlock(&loc->tlo_lock);
147 
148  rc = 0;
149  }
150  return M0_RC(rc);
151 }
152 
153 M0_INTERNAL void m0_timer_thread_detach(struct m0_timer_locality *loc)
154 {
155  pid_t tid;
156  struct m0_timer_tid *tt;
157 
158  M0_PRE(loc != NULL);
159 
160  tid = _gettid();
161  tt = locality_tid_find(loc, tid);
162  M0_ASSERT(tt != NULL);
163 
164  m0_mutex_lock(&loc->tlo_lock);
165  if (loc->tlo_rrtid == tt)
166  loc->tlo_rrtid = NULL;
167  tid_tlink_del_fini(tt);
168  m0_mutex_unlock(&loc->tlo_lock);
169 
170  m0_free(tt);
171 }
172 
179 static int timer_posix_init(struct m0_timer *timer)
180 {
181  struct sigevent se;
182  timer_t ptimer;
183  int rc;
184 
185  M0_SET0(&se);
186  se.sigev_signo = TIMER_SIGNO;
187  se.sigev_value.sival_ptr = timer;
188  if (timer->t_tid == 0) {
189  se.sigev_notify = SIGEV_SIGNAL;
190  } else {
191  se.sigev_notify = SIGEV_THREAD_ID;
192  se._sigev_un._tid = timer->t_tid;
193  }
194  rc = timer_create(clock_source_timer, &se, &ptimer);
195  /* preserve timer->t_ptimer if timer_create() isn't succeeded */
196  if (rc == 0)
197  timer->t_ptimer = ptimer;
198  return M0_RC(rc);
199 }
200 
204 static void timer_posix_fini(timer_t posix_timer)
205 {
206  int rc;
207 
208  rc = timer_delete(posix_timer);
209  /*
210  * timer_delete() can fail iff timer->t_ptimer isn't valid timer ID.
211  */
212  M0_ASSERT_INFO(rc == 0, "rc = %d", rc);
213 }
214 
216 {
218  !M0_IN(expire, (M0_TIME_NEVER, 0, 1)))
219  expire -= m0_time_monotonic_offset;
220  return expire;
221 }
222 
227 static void
228 timer_posix_set(struct m0_timer *timer, m0_time_t expire, m0_time_t *old_expire)
229 {
230  int rc;
231  struct itimerspec ts;
232  struct itimerspec ots;
233 
234  M0_PRE(timer != NULL);
235 
236  expire = timer_time_to_realtime(expire);
237 
238  ts.it_interval.tv_sec = 0;
239  ts.it_interval.tv_nsec = 0;
240  ts.it_value.tv_sec = m0_time_seconds(expire);
241  ts.it_value.tv_nsec = m0_time_nanoseconds(expire);
242 
243  rc = timer_settime(timer->t_ptimer, TIMER_ABSTIME, &ts, &ots);
244  /* timer_settime() can only fail if timer->t_ptimer isn't valid
245  * timer ID or ts has invalid fields. */
246  M0_ASSERT_INFO(rc == 0, "rc = %d", rc);
247 
248  if (old_expire != NULL)
249  *old_expire = m0_time(ots.it_value.tv_sec,
250  ots.it_value.tv_nsec);
251 }
252 
254 static int timer_sigaction(int signo,
255  void (*sighandler)(int, siginfo_t*, void*))
256 {
257  struct sigaction sa;
258 
259  M0_SET0(&sa);
260  sigemptyset(&sa.sa_mask);
261  if (sighandler == NULL) {
262  sa.sa_handler = SIG_DFL;
263  } else {
264  sa.sa_sigaction = sighandler;
265  sa.sa_flags = SA_SIGINFO;
266  }
267 
268  return sigaction(signo, &sa, NULL) == 0 ? 0 : errno;
269 }
270 
275 static void timer_sighandler(int signo, siginfo_t *si, void *u_ctx)
276 {
277  struct m0_timer *timer;
278 
279  M0_PRE(si != NULL && si->si_value.sival_ptr != 0);
280  M0_PRE(si->si_code == SI_TIMER);
281  M0_PRE(signo == TIMER_SIGNO);
282 
283  timer = si->si_value.sival_ptr;
284  M0_ASSERT_EX(ergo(timer->t_tid != 0, timer->t_tid == _gettid()));
287 }
288 
292 static int timer_hard_init(struct m0_timer *timer,
293  struct m0_timer_locality *loc)
294 {
295  int rc;
296 
297  timer->t_tid = timer_locality_tid_next(loc);
298  rc = timer_posix_init(timer);
299  if (rc == 0) {
300  rc = m0_semaphore_init(&timer->t_cb_sync_sem, 0);
301  if (rc != 0)
302  timer_posix_fini(timer->t_ptimer);
303  }
304  return M0_RC(rc);
305 }
306 
310 static void timer_hard_fini(struct m0_timer *timer)
311 {
313  timer_posix_fini(timer->t_ptimer);
314 }
315 
319 static void timer_hard_start(struct m0_timer *timer)
320 {
321  /* expire = 0 will not arm the timer, so use 1ns in this case */
322  timer_posix_set(timer,
323  timer->t_expire == 0 ? 1 : timer->t_expire, NULL);
324 }
325 
330 static void timer_hard_stop(struct m0_timer *timer)
331 {
332  m0_time_t expire;
333  timer_posix_set(timer, zero_time, &expire);
334  /* if timer was expired then wait until callback is finished */
335  if (expire == zero_time)
337 }
338 
342 static void timer_working_thread(struct m0_timer *timer)
343 {
344  while (1) {
345  /*
346  * This semaphore is incremented
347  * in timer_soft_start() or in timer_soft_fini().
348  */
350  /* Check if it is incremented in timer_soft_fini() */
351  if (timer->t_thread_stop)
352  break;
353 
354  /*
355  * Wait until either:
356  * - semaphore isn't decremented => timer->t_expire passed
357  * - semaphore is decremented => timer_soft_stop() cancels
358  * the timer.
359  */
360  if (!m0_semaphore_timeddown(&timer->t_sleep_sem,
361  timer->t_expire)) {
363  /*
364  * Wait until timer_soft_stop()
365  * increments this semaphore.
366  */
368  }
369  /* Synchronise timer callback with m0_timer_stop() */
371  }
372 }
373 
374 static int timer_soft_initfini(struct m0_timer *timer, bool init)
375 {
376  int rc;
377 
378  if (!init)
379  goto fini;
380  rc = m0_semaphore_init(&timer->t_sleep_sem, 0);
381  if (rc != 0)
382  goto err;
383  rc = m0_semaphore_init(&timer->t_cb_sync_sem, 0);
384  if (rc != 0)
385  goto fini_sleep_sem;
386  rc = M0_THREAD_INIT(&timer->t_thread, struct m0_timer*, NULL,
387  &timer_working_thread, timer, "timer_thread");
388  if (rc != 0)
389  goto fini_stop_sem;
390  return 0;
391 
392 fini:
393  rc = m0_thread_join(&timer->t_thread);
394  /*
395  * There is something wrong with timers logic
396  * if thread can't be joined.
397  */
398  M0_ASSERT_INFO(rc == 0, "rc = %d", rc);
399  m0_thread_fini(&timer->t_thread);
400 fini_stop_sem:
402 fini_sleep_sem:
404 err:
405  return M0_RC(rc);
406 }
407 
408 static int timer_soft_init(struct m0_timer *timer,
409  struct m0_timer_locality *loc)
410 {
411  timer->t_thread_stop = false;
412  return timer_soft_initfini(timer, true);
413 }
414 
415 static void timer_soft_fini(struct m0_timer *timer)
416 {
417  int rc;
418 
419  timer->t_thread_stop = true;
420  m0_semaphore_up(&timer->t_sleep_sem);
421  rc = timer_soft_initfini(timer, false);
422  M0_ASSERT_INFO(rc == 0, "rc = %d", rc);
423 }
424 
425 static void timer_soft_start(struct m0_timer *timer)
426 {
427  m0_semaphore_up(&timer->t_sleep_sem);
428 }
429 
433 static void timer_soft_stop(struct m0_timer *timer)
434 {
435  m0_semaphore_up(&timer->t_sleep_sem);
437 }
438 
439 M0_INTERNAL const struct m0_timer_operations m0_timer_ops[] = {
440  [M0_TIMER_SOFT] = {
442  .tmr_fini = timer_soft_fini,
443  .tmr_start = timer_soft_start,
444  .tmr_stop = timer_soft_stop,
445  },
446  [M0_TIMER_HARD] = {
447  .tmr_init = timer_hard_init,
448  .tmr_fini = timer_hard_fini,
449  .tmr_start = timer_hard_start,
450  .tmr_stop = timer_hard_stop,
451  },
452 };
453 
457 M0_INTERNAL int m0_timers_init(void)
458 {
460 
461  switch (M0_CLOCK_SOURCE) {
463  clock_source_timer = CLOCK_REALTIME;
464  break;
466  clock_source_timer = CLOCK_MONOTONIC;
467  break;
472  break;
473  default:
474  M0_IMPOSSIBLE("Invalid clock source for timer");
475  }
476  return 0;
477 }
478 
479 M0_INTERNAL void m0_timers_fini(void)
480 {
481  clock_source_timer = -1;
483 }
484 
485 #undef M0_TRACE_SUBSYSTEM
486 
489 /*
490  * Local variables:
491  * c-indentation-style: "K&R"
492  * c-basic-offset: 8
493  * tab-width: 8
494  * fill-column: 80
495  * scroll-step: 1
496  * End:
497  */
498 /*
499  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
500  */
M0_INTERNAL void m0_timer_locality_fini(struct m0_timer_locality *loc)
Definition: timer.c:84
static struct m0_timer_tid * locality_tid_find(struct m0_timer_locality *loc, pid_t tid)
Definition: timer.c:92
M0_INTERNAL int m0_timer_thread_attach(struct m0_timer_locality *loc)
Definition: timer.c:127
static int timer_hard_init(struct m0_timer *timer, struct m0_timer_locality *loc)
Definition: timer.c:292
int(* tmr_init)(struct m0_timer *timer, struct m0_timer_locality *loc)
Definition: timer.h:127
static void timer_working_thread(struct m0_timer *timer)
Definition: timer.c:342
#define M0_PRE(cond)
m0_time_t m0_time_monotonic_offset
Definition: time.c:113
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
m0_time_t t_expire
Definition: timer.h:47
#define NULL
Definition: misc.h:38
#define ergo(a, b)
Definition: misc.h:293
int m0_thread_join(struct m0_thread *q)
Definition: kthread.c:169
M0_TL_DEFINE(tid, static, struct m0_timer_tid)
const m0_time_t M0_TIME_NEVER
Definition: time.c:108
static pid_t _gettid()
Definition: timer.c:70
uint64_t m0_time_t
Definition: time.h:37
M0_INTERNAL bool m0_semaphore_timeddown(struct m0_semaphore *semaphore, const m0_time_t abs_timeout)
Definition: semaphore.c:75
uint64_t m0_time_nanoseconds(const m0_time_t time)
Definition: time.c:89
#define TIMER_SIGNO
Definition: timer.c:49
M0_INTERNAL int m0_timers_init(void)
Definition: timer.c:457
enum CLOCK_SOURCES M0_CLOCK_SOURCE
Definition: time.c:112
static int timer_sigaction(int signo, void(*sighandler)(int, siginfo_t *, void *))
Definition: timer.c:254
M0_INTERNAL void m0_timer_thread_detach(struct m0_timer_locality *loc)
Definition: timer.c:153
#define M0_THREAD_INIT(thread, TYPE, init, func, arg, namefmt,...)
Definition: thread.h:139
struct m0_semaphore t_sleep_sem
Definition: timer.h:57
static void timer_hard_fini(struct m0_timer *timer)
Definition: timer.c:310
#define M0_SET0(obj)
Definition: misc.h:64
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
Definition: timer.h:39
m0_time_t m0_time(uint64_t secs, long ns)
Definition: time.c:41
#define m0_tl_endfor
Definition: tlist.h:700
M0_INTERNAL void m0_timers_fini(void)
Definition: timer.c:479
return M0_RC(rc)
#define M0_ASSERT_EX(cond)
static void timer_posix_fini(timer_t posix_timer)
Definition: timer.c:204
struct m0_tl tlo_tids
Definition: timer.h:92
static void timer_sighandler(int signo, siginfo_t *si, void *u_ctx)
Definition: timer.c:275
#define M0_ASSERT(cond)
static void timer_soft_start(struct m0_timer *timer)
Definition: timer.c:425
void m0_thread_fini(struct m0_thread *q)
Definition: thread.c:92
timer_t t_ptimer
Definition: timer.h:62
pid_t t_tid
Definition: timer.h:68
M0_INTERNAL int m0_semaphore_init(struct m0_semaphore *semaphore, unsigned value)
Definition: semaphore.c:38
M0_TL_DESCR_DEFINE(tid, "thread IDs", static, struct m0_timer_tid, tt_linkage, tt_magic, 0x696c444954726d74, 0x686c444954726d74)
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
struct m0_timer_tid * tlo_rrtid
Definition: timer.h:94
uint64_t m0_time_seconds(const m0_time_t time)
Definition: time.c:83
static int timer_soft_initfini(struct m0_timer *timer, bool init)
Definition: timer.c:374
int init(struct workload *w)
static int timer_soft_init(struct m0_timer *timer, struct m0_timer_locality *loc)
Definition: timer.c:408
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
M0_INTERNAL void m0_semaphore_fini(struct m0_semaphore *semaphore)
Definition: semaphore.c:45
bool t_thread_stop
Definition: timer.h:59
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
struct m0_mutex tlo_lock
Definition: timer.h:90
static void timer_hard_start(struct m0_timer *timer)
Definition: timer.c:319
int fini(struct workload *w)
static void timer_soft_fini(struct m0_timer *timer)
Definition: timer.c:415
#define M0_MKTIME(secs, ns)
Definition: time.h:86
#define M0_ASSERT_INFO(cond, fmt,...)
static void timer_soft_stop(struct m0_timer *timer)
Definition: timer.c:433
M0_INTERNAL void m0_timer_locality_init(struct m0_timer_locality *loc)
Definition: timer.c:75
M0_INTERNAL void m0_semaphore_down(struct m0_semaphore *semaphore)
Definition: semaphore.c:49
static int clock_source_timer
Definition: timer.c:53
struct m0_thread t_thread
Definition: timer.h:55
M0_INTERNAL const struct m0_timer_operations m0_timer_ops[]
Definition: timer.c:93
static int timer_posix_init(struct m0_timer *timer)
Definition: timer.c:179
M0_INTERNAL void m0_semaphore_up(struct m0_semaphore *semaphore)
Definition: semaphore.c:65
pid_t tt_tid
Definition: timer.h:77
static void timer_hard_stop(struct m0_timer *timer)
Definition: timer.c:330
static m0_time_t timer_time_to_realtime(m0_time_t expire)
Definition: timer.c:215
static void timer_posix_set(struct m0_timer *timer, m0_time_t expire, m0_time_t *old_expire)
Definition: timer.c:228
#define m0_tl_for(name, head, obj)
Definition: tlist.h:695
void m0_free(void *data)
Definition: memory.c:146
static const m0_time_t zero_time
Definition: timer.c:51
int32_t rc
Definition: trigger_fop.h:47
static struct sync_interactions si
Definition: sync.c:121
M0_INTERNAL void m0_timer_callback_execute(struct m0_timer *timer)
Definition: timer.c:99
struct m0_semaphore t_cb_sync_sem
Definition: timer.h:52
static pid_t timer_locality_tid_next(struct m0_timer_locality *loc)
Definition: timer.c:109
#define M0_IMPOSSIBLE(fmt,...)