Motr  M0
kthread.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2011-2021 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 <linux/version.h> /* LINUX_VERSION_CODE */
24 
25 #include "lib/thread.h"
26 #include "lib/misc.h" /* M0_IS0 */
27 #include "lib/arith.h" /* min64u */
28 #include "lib/bitmap.h" /* m0_bitmap_get */
29 #include "module/instance.h" /* m0_set */
30 #include "addb2/global.h"
31 
32 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_LIB
33 #include "lib/trace.h"
34 
65 static struct m0 *__instance;
66 
67 M0_INTERNAL struct m0_thread_tls *m0_thread_tls(void)
68 {
69  if (current->journal_info == NULL) {
70  M0_LOG(M0_FATAL, "No tls.");
71  dump_stack();
72  }
73  M0_ASSERT(current->journal_info != NULL);
74  return current->journal_info;
75 }
76 
77 M0_INTERNAL int m0_threads_init(struct m0 *instance)
78 {
82  return 0;
83 }
84 
85 M0_INTERNAL void m0_threads_fini(void)
86 {
87 }
88 
89 M0_INTERNAL int m0_threads_once_init(void)
90 {
91  return 0;
92 }
93 
94 M0_INTERNAL void m0_threads_once_fini(void)
95 {
96 }
97 
98 M0_INTERNAL void m0_thread_enter(struct m0_thread *thread, bool full)
99 {
101 }
102 M0_EXPORTED(m0_thread_enter);
103 
104 static void tls_fini(struct m0_thread_tls *tls)
105 {
106 }
107 
108 M0_INTERNAL void m0_thread_leave(void)
109 {
111 }
112 M0_EXPORTED(m0_thread_leave);
113 
114 M0_INTERNAL void m0_thread__cleanup(struct m0_thread *bye)
115 {
116  m0_thread_leave();
117 }
118 M0_EXPORTED(m0_thread__cleanup);
119 
120 static int kthread_trampoline(void *arg)
121 {
122  struct m0_thread *t = arg;
123 
124  current->journal_info = &t->t_tls;
125  /* Required for correct m0_thread_join() behavior in kernel:
126  kthread_stop() will not stop if the thread has been created but has
127  not yet started executing. So, m0_thread_join() blocks on the
128  semaphore to ensure the thread can be stopped iff t_init != NULL
129  (when t_init == NULL, blocking occurs in m0_thread_init).
130  kthread_stop(), in turn, requires that the thread not exit until
131  kthread_stop() is called, so we must loop on kthread_should_stop()
132  to satisfy that API requirement. The semaphore is signalled before
133  calling the thread function so that other kernel code can still
134  depend on kthread_should_stop().
135  */
136  if (t->t_init == NULL)
139  current->journal_info = NULL;
140  set_current_state(TASK_INTERRUPTIBLE);
141  while (!kthread_should_stop()) {
142  schedule();
143  set_current_state(TASK_INTERRUPTIBLE);
144  }
145  set_current_state(TASK_RUNNING);
146 
147  return 0;
148 }
149 
150 M0_INTERNAL int m0_thread_init_impl(struct m0_thread *q, const char *name)
151 {
152  int result;
153  struct task_struct *task;
154 
155  M0_PRE(q->t_state == TS_RUNNING);
156 
157  task = kthread_create(kthread_trampoline, q, "%s", name);
158  if (IS_ERR(task)) {
159  result = PTR_ERR(q->t_h.h_tsk);
160  } else {
161  result = 0;
162  q->t_h.h_tsk = task;
163  q->t_h.h_pid = task->pid;
164  wake_up_process(task);
165  }
166  return result;
167 }
168 
170 {
171  int result;
172 
173  M0_PRE(q->t_state == TS_RUNNING);
174  M0_PRE(q->t_h.h_tsk != current);
175 
176  /* see comment in kthread_trampoline */
177  if (q->t_init == NULL)
178  m0_semaphore_down(&q->t_wait);
179  /*
180  m0_thread provides no wrappers for do_exit(), so this will block
181  until the thread exits by returning from kthread_trampoline.
182  kthread_trampoline() always returns 0, but kthread_stop() can return
183  -errno on failure.
184  */
185  result = kthread_stop(q->t_h.h_tsk);
186  if (result == 0)
187  q->t_state = TS_PARKED;
188  return result;
189 }
190 M0_EXPORTED(m0_thread_join);
191 
192 M0_INTERNAL int m0_thread_signal(struct m0_thread *q, int sig)
193 {
194  return M0_ERR(-ENOSYS);
195 }
196 
197 M0_INTERNAL int m0_thread_confine(struct m0_thread *q,
198  const struct m0_bitmap *processors)
199 {
200  int result = 0;
201  size_t idx;
202  size_t nr_bits = min64u(processors->b_nr, nr_cpu_ids);
203  cpumask_var_t cpuset;
204  struct task_struct *p = q->t_h.h_tsk;
205  int nr_allowed;
206 
207  if (!zalloc_cpumask_var(&cpuset, GFP_KERNEL))
208  return M0_ERR(-ENOMEM);
209 
210  for (idx = 0; idx < nr_bits; ++idx)
211  if (m0_bitmap_get(processors, idx))
212  cpumask_set_cpu(idx, cpuset);
213  nr_allowed = cpumask_weight(cpuset);
214 
215  if (nr_allowed == 0) {
216  result = M0_ERR(-EINVAL);
217  } else {
218  /*
219  The following code would safely access the task_struct and
220  ensure it would not disappear, however put_task_struct is an
221  inline that references __put_task_struct, and the latter is
222  not exported. See the notes at the top of this file.
223 
224  get_task_struct(p);
225 
226  ...
227 
228  put_task_struct(p);
229  */
230 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0) || defined (CONFIG_AARCH64)
231  cpumask_copy(&p->cpus_allowed, cpuset);
232 #else
233  cpumask_copy(&p->cpus_mask, cpuset);
234 #endif
235 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
236  p->rt.nr_cpus_allowed = nr_allowed;
237 #else
238  p->nr_cpus_allowed = nr_allowed;
239 #endif
240 
241  /* cause current task to migrate immediately by blocking */
242  if (p == current && !cpumask_test_cpu(task_cpu(p), cpuset))
243  schedule_timeout_uninterruptible(1);
244  }
245  free_cpumask_var(cpuset);
246  return result;
247 }
248 
249 M0_INTERNAL void m0_enter_awkward(void)
250 {
251  /*
252  * To avoid kernel warnings from del_timer_sync() when
253  * canceling m0_sm_timer at m0_sm_state_set() -> clink_signal()
254  * we disable the effect of this function in kernel mode.
255  * Luckily, m0_is_awkward() is used in kernel in its UT only
256  * at the moment, so we disabled it there also.
257  *
258  * add_preempt_count(HARDIRQ_OFFSET);
259  */
260 }
261 
262 M0_INTERNAL void m0_exit_awkward(void)
263 {
264  /*
265  * sub_preempt_count(HARDIRQ_OFFSET);
266  */
267 }
268 
269 M0_INTERNAL bool m0_is_awkward(void)
270 {
271  return in_irq();
272 }
273 
274 M0_INTERNAL struct m0_thread_tls *m0_thread_tls_pop(void)
275 {
276  struct m0_thread_tls *tls = current->journal_info;
277 
278  current->journal_info = tls->tls_arch.tat_prev;
279  return tls;
280 }
281 
282 M0_INTERNAL void m0_thread_tls_back(struct m0_thread_tls *tls)
283 {
284  M0_PRE(__instance != NULL);
285  M0_PRE(tls->tls_arch.tat_prev == current->journal_info);
286 
287  current->journal_info = tls;
288 }
289 
290 M0_INTERNAL uint64_t m0_pid(void)
291 {
292  return current->pid;
293 }
294 
295 M0_INTERNAL uint64_t m0_process(void)
296 {
297  return 0;
298 }
299 
300 M0_INTERNAL int m0_thread_arch_adopt(struct m0_thread *thread,
301  struct m0 *instance, bool full)
302 {
303  M0_PRE(M0_IS0(thread));
305 
306  thread->t_tls.tls_arch.tat_prev = current->journal_info;
308  thread->t_h.h_tsk = current;
309  thread->t_h.h_pid = current->pid;
310  current->journal_info = &thread->t_tls;
311  if (__instance != NULL) {
313  if (full)
315  }
316  return 0;
317 }
318 M0_EXPORTED(m0_thread_arch_adopt);
319 
320 M0_INTERNAL void m0_thread_arch_shun(void)
321 {
322  struct m0_thread_tls *tls = current->journal_info;
323  void *prev = tls->tls_arch.tat_prev;
324 
325  tls_fini(tls);
327  current->journal_info = prev;
328 }
329 M0_EXPORTED(m0_thread_arch_shun);
330 
331 #undef M0_TRACE_SUBSYSTEM
332 
335 /*
336  * Local variables:
337  * c-indentation-style: "K&R"
338  * c-basic-offset: 8
339  * tab-width: 8
340  * fill-column: 80
341  * scroll-step: 1
342  * End:
343  */
M0_INTERNAL void m0_enter_awkward(void)
Definition: kthread.c:249
M0_INTERNAL uint64_t m0_process(void)
Definition: kthread.c:295
static struct m0_addb2_philter p
Definition: consumer.c:40
M0_INTERNAL void m0_thread_tls_back(struct m0_thread_tls *tls)
Definition: kthread.c:282
#define M0_PRE(cond)
M0_INTERNAL int m0_thread_init_impl(struct m0_thread *q, const char *name)
Definition: kthread.c:150
void * tat_prev
Definition: thread.h:52
static struct m0_semaphore q
Definition: rwlock.c:55
#define NULL
Definition: misc.h:38
M0_INTERNAL int m0_thread_confine(struct m0_thread *q, const struct m0_bitmap *processors)
Definition: kthread.c:197
int m0_thread_join(struct m0_thread *q)
Definition: kthread.c:169
M0_INTERNAL void m0_threads_fini(void)
Definition: kthread.c:85
#define M0_LOG(level,...)
Definition: trace.h:167
M0_INTERNAL void m0_set(struct m0 *instance)
Definition: instance.c:48
struct task_struct * h_tsk
Definition: thread.h:46
static void full(void)
Definition: base.c:334
struct m0_thread_tls t_tls
Definition: thread.h:118
struct m0_semaphore t_wait
Definition: thread.h:116
M0_INTERNAL void m0_thread_leave(void)
Definition: kthread.c:108
M0_INTERNAL struct m0_thread_tls * m0_thread_tls(void)
Definition: kthread.c:67
struct m0_thread_arch_tls tls_arch
Definition: thread.h:67
static int kthread_trampoline(void *arg)
Definition: kthread.c:120
return M0_ERR(-EOPNOTSUPP)
const char * name
Definition: trace.c:110
M0_INTERNAL void m0_addb2_global_thread_leave(void)
Definition: global.c:58
static struct m0 * __instance
Definition: kthread.c:65
M0_INTERNAL int m0_thread_signal(struct m0_thread *q, int sig)
Definition: kthread.c:192
#define M0_ASSERT(cond)
M0_INTERNAL void * m0_thread_trampoline(void *arg)
Definition: thread.c:101
struct m0_thread thread
Definition: note.c:104
static struct m0_thread t[8]
Definition: service_ut.c:1230
M0_INTERNAL void m0_thread_enter(struct m0_thread *thread, bool full)
Definition: kthread.c:98
M0_INTERNAL void m0_addb2_global_thread_enter(void)
Definition: global.c:43
M0_INTERNAL struct m0_thread_tls * m0_thread_tls_pop(void)
Definition: kthread.c:274
Definition: instance.h:80
M0_INTERNAL void m0_threads_once_fini(void)
Definition: kthread.c:94
M0_INTERNAL bool m0_is_awkward(void)
Definition: kthread.c:269
static __thread struct m0_thread_tls * tls
Definition: uthread.c:66
static uint64_t min64u(uint64_t a, uint64_t b)
Definition: arith.h:66
int(* t_init)(void *)
Definition: thread.h:113
#define M0_IS0(obj)
Definition: misc.h:70
M0_INTERNAL bool m0_bitmap_get(const struct m0_bitmap *map, size_t idx)
Definition: bitmap.c:105
M0_INTERNAL int m0_threads_once_init(void)
Definition: kthread.c:89
static struct m0 instance
Definition: main.c:78
struct m0_thread * tls_self
Definition: thread.h:69
struct m0_thread_handle t_h
Definition: thread.h:112
M0_INTERNAL void m0_exit_awkward(void)
Definition: kthread.c:262
M0_INTERNAL void m0_semaphore_down(struct m0_semaphore *semaphore)
Definition: semaphore.c:49
M0_INTERNAL uint64_t m0_pid(void)
Definition: kthread.c:290
size_t b_nr
Definition: bitmap.h:44
M0_INTERNAL void m0_semaphore_up(struct m0_semaphore *semaphore)
Definition: semaphore.c:65
M0_INTERNAL int m0_threads_init(struct m0 *instance)
Definition: kthread.c:77
M0_INTERNAL int m0_thread_arch_adopt(struct m0_thread *thread, struct m0 *instance, bool full)
Definition: kthread.c:300
M0_INTERNAL void m0_thread__cleanup(struct m0_thread *bye)
Definition: kthread.c:114
static void tls_fini(struct m0_thread_tls *tls)
Definition: kthread.c:104
M0_INTERNAL void m0_thread_arch_shun(void)
Definition: kthread.c:320
unsigned long h_pid
Definition: thread.h:47