Motr  M0
Thread
Collaboration diagram for Thread:

Modules

 Kernel Thread Implementation
 

Data Structures

struct  m0_thread_handle
 
struct  m0_thread_arch_tls
 
struct  m0_thread_tls
 
struct  m0_thread
 

Macros

#define M0_THREAD_ENTER
 
#define M0_THREAD_INIT(thread, TYPE, init, func, arg, namefmt, ...)
 
#define LAMBDA(T, ...)   ({ T __lambda __VA_ARGS__; &__lambda; })
 

Enumerations

enum  { M0_THREAD_NAME_LEN = TASK_COMM_LEN }
 
enum  m0_thread_state { TS_PARKED = 0, TS_RUNNING }
 
enum  { M0_THREAD_NAME_LEN = 16 }
 

Functions

M0_INTERNAL void m0_thread_enter (struct m0_thread *thread, bool full)
 
M0_INTERNAL void m0_thread_leave (void)
 
M0_INTERNAL void m0_thread__cleanup (struct m0_thread *bye)
 
M0_INTERNAL struct m0_thread_tlsm0_thread_tls_pop (void)
 
M0_INTERNAL void m0_thread_tls_back (struct m0_thread_tls *tls)
 
int m0_thread_init (struct m0_thread *q, int(*init)(void *), void(*func)(void *), void *arg, const char *namefmt,...)
 
void m0_thread_fini (struct m0_thread *q)
 
M0_INTERNAL void * m0_thread_trampoline (void *arg)
 
M0_INTERNAL struct m0_threadm0_thread_self (void)
 
M0_INTERNAL int m0_thread_adopt (struct m0_thread *thread, struct m0 *instance)
 
M0_INTERNAL void m0_thread_shun (void)
 
M0_INTERNAL int m0_thread_init_impl (struct m0_thread *q, const char *name)
 
int m0_thread_join (struct m0_thread *q)
 
M0_INTERNAL int m0_thread_signal (struct m0_thread *q, int sig)
 
M0_INTERNAL int m0_thread_confine (struct m0_thread *q, const struct m0_bitmap *processors)
 
M0_INTERNAL struct m0_thread_tlsm0_thread_tls (void)
 
M0_INTERNAL int m0_threads_init (struct m0 *instance)
 
M0_INTERNAL void m0_threads_fini (void)
 
M0_INTERNAL int m0_threads_once_init (void)
 
M0_INTERNAL void m0_threads_once_fini (void)
 
M0_INTERNAL void m0_enter_awkward (void)
 
M0_INTERNAL void m0_exit_awkward (void)
 
M0_INTERNAL bool m0_is_awkward (void)
 
M0_INTERNAL uint64_t m0_pid (void)
 
M0_INTERNAL uint64_t m0_process (void)
 
M0_INTERNAL int m0_thread_arch_adopt (struct m0_thread *thread, struct m0 *instance, bool full)
 
M0_INTERNAL void m0_thread_arch_shun (void)
 
static void * uthread_trampoline (void *arg)
 

Variables

struct m0_thread_tls M0_XCA_DOMAIN
 
static pthread_attr_t pthread_attr_default
 
static __thread struct m0_thread thread = {}
 
static __thread struct m0_thread_tlstls = NULL
 
static struct m0_thread main_thread
 
M0_INTERNAL char m0_argv0 [PATH_MAX] = {}
 
M0_INTERNAL char * m0_debugger_args [4]
 

Detailed Description

Thread creation and manipulation interface (rather spartan at the moment).

Threads can be created that will start execution by running a specified function invoked with a specified argument. Thread functions return void, a user must arrange a method of transferring results back from the thread if necessary.

The only operation on a started thread is waiting for its completion ("joining" the thread).

See also
m0_thread

Linux kernel m0_thread implementation

Kernel space implementation is based <linux/kthread.h>

See also
m0_thread

Common m0_thread implementation.

User space m0_thread implementation

User space implementation is straight-forwardly based on POSIX thread interface.

See also
m0_thread

Implementation of m0_thread on top of pthread_t.

Implementation notes

Instead of creating a new POSIX thread executing user-supplied function, all threads start executing the same trampoline function m0_thread_trampoline() that performs some generic book-keeping.

Threads are created with a PTHREAD_CREATE_JOINABLE attribute.

Macro Definition Documentation

◆ LAMBDA

#define LAMBDA (   T,
  ... 
)    ({ T __lambda __VA_ARGS__; &__lambda; })

Helper macro creating an anonymous function with a given body.

For example:

int x;
result = M0_THREAD_INIT(&tcb, int, NULL,
LAMBDA(void, (int y) { printf("%i", x + y); } ), 1,
"add_%d", 1);

LAMBDA is useful to create an "ad-hoc" function that can be passed as a call-back function pointer.

Note
resulting anonymous function can be called only while the block where LAMBDA macro was called is active. For example, in the code fragment above, the tcb thread must finish before the block where M0_THREAD_INIT() was called is left.
Be careful if using LAMBDA in kernel code, as the code could be generated on the stack and would fault in the kernel as it is execution protected in the kernel.

The long story. Consider an arrangement like

int foo(int x)
{
int y = x + 1;
bar(LAMBDA(int, (int z) { return z + y; }));
...
}

Let's call the lambda function defined above L. 'y' is called a "free variable" of L, because it is neither declared in L's body nor passed as a parameter. When bar() or some of the functions (transitively) called by bar() calls L, L needs access to its parameters (z), supplied by its caller, and also to its free variables (y). y is stored in foo's stack frame and y's location on the stack, relative to L's frame is, in general, impossible to determine statically. For example, bar() can call baz(), which can store L in some data-structure, call quux() that will extract L from the data-structure and call it.

This means that to call L, in addition, to the address of L's executable code, one also has to supply references to all its free variables. A structure, containing address of a function, together with references to the function's free variables is called a "closure" (http://en.wikipedia.org/wiki/Closure_(computer_science)). A closure is sufficient to call a function, but it is incompatible with the format of other function pointers. For example, given a value of type int (*func)(int), it is impossible to tell whether func is a pointer to a closure or a "normal" function pointer to a function without free variable. To work around this, gcc dynamically creates for each closure a small "trampoline function" that effectively builds closure and calls it. For example, the trampoline for L would look like

int __L_trampoline(int z)
{
int *y = (int *)LITERAL_ADDRESS_OF_y;
return L(z, *y);
}

The trampoline is built when foo() is called and y's address is known. Once it is built, __L_trampoline()'s address can be passed to other functions safely. Note that __L_trampoline code is generated dynamically at run-time. Moreover gcc stores trampoline's code at the stack. And in kernel stack pages has no execution bit, to prevent exploits.

Summary:

- if your LAMBDA() has no free variables, you are safe;

- if your LAMBDA() has only free variables with statically known
  addresses (e.g., global variables) you are safe, because gcc doesn't
  generate trampoline in this case;

- otherwise

    - you are unsafe in kernel;

    - you are safe in user space, provided a lambda function is never
      called after the function in which the lambda function is defined
      returns (because when foo() returns, __L_trampoline() is
      destroyed).
See also
http://en.wikipedia.org/wiki/Lambda_calculus

Definition at line 153 of file thread.h.

◆ M0_THREAD_ENTER

#define M0_THREAD_ENTER
Value:
struct m0_thread __th \
__attribute__((cleanup(m0_thread__cleanup))) = { 0, }; \
m0_thread_enter(&__th, true)
enum m0_md_lustre_logrec_type __attribute__
Definition: balloc.c:2745
M0_INTERNAL void m0_thread__cleanup(struct m0_thread *bye)
Definition: kthread.c:114

Definition at line 60 of file thread.h.

◆ M0_THREAD_INIT

#define M0_THREAD_INIT (   thread,
  TYPE,
  init,
  func,
  arg,
  namefmt,
  ... 
)
Value:
({ \
typeof(func) __func = (func); \
typeof(arg) __arg = (arg); \
TYPE __dummy; \
(void)(__func == (void (*)(TYPE))NULL); \
(void)(&__arg == &__dummy); \
m0_thread_init(thread, \
(int (*)(void *))init, \
(void (*)(void *))__func, \
(void *)(unsigned long)__arg, \
namefmt , ## __VA_ARGS__); \
})
#define NULL
Definition: misc.h:38
struct m0_thread thread
Definition: note.c:104
int init(struct workload *w)

Type-safe wrapper around m0_thread_init().

With this macro one can initialise a thread with a function taking an argument of a particular type:

static void worker(struct foo *arg) { ... }
static struct m0_thread tcb;
result = M0_THREAD_INIT(&tcb, struct foo *, NULL, &worker, arg, "worker");

M0_THREAD_INIT() checks that type of the argument matches function prototype.

Note
TYPE cannot be void.

Definition at line 139 of file thread.h.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
M0_THREAD_NAME_LEN 

Definition at line 43 of file thread.h.

◆ anonymous enum

anonymous enum
Enumerator
M0_THREAD_NAME_LEN 

Definition at line 46 of file thread.h.

◆ m0_thread_state

Thread states used to validate thread interface usage.

See also
m0_thread
Enumerator
TS_PARKED 
TS_RUNNING 

Definition at line 78 of file thread.h.

Function Documentation

◆ m0_enter_awkward()

M0_INTERNAL void m0_enter_awkward ( void  )

Sets the thread in awkward context.

Definition at line 194 of file uthread.c.

Here is the call graph for this function:

◆ m0_exit_awkward()

M0_INTERNAL void m0_exit_awkward ( void  )

Resets thread from awkward context.

Definition at line 208 of file uthread.c.

Here is the call graph for this function:

◆ m0_is_awkward()

M0_INTERNAL bool m0_is_awkward ( void  )

Tells if executing thread is in awkward context.

Definition at line 216 of file uthread.c.

Here is the call graph for this function:

◆ m0_pid()

M0_INTERNAL uint64_t m0_pid ( void  )

Returns "process identifier", depending on the architecture.

Definition at line 221 of file uthread.c.

◆ m0_process()

M0_INTERNAL uint64_t m0_process ( void  )

Returns "process identifier" for userspace process and 0 in the kernel.

See also
m0_pid().

Definition at line 226 of file uthread.c.

Here is the call graph for this function:

◆ m0_thread__cleanup()

M0_INTERNAL void m0_thread__cleanup ( struct m0_thread bye)

Definition at line 114 of file kthread.c.

Here is the call graph for this function:

◆ m0_thread_adopt()

M0_INTERNAL int m0_thread_adopt ( struct m0_thread thread,
struct m0 instance 
)

Accepts a thread as a Motr thread.

Motr maintains a per-thread context needed for any Motr operation. A thread with such a context is "Motr thread". A thread that calls m0_init() is a Motr thread. A thread created by a call to m0_thread_init() (necessarily made by a Motr thread) is a Motr thread.

To turn any other thread into a Motr thread call m0_thread_adopt() before any Motr call is made in the thread. m0_thread_shun() must be called before the thread exits.

"thread" object must be owned by the calling thread (not accessed concurrently by multiple threads). It must exist at least until the matching m0_thread_shun() call returns.

"instance" is m0 instance to which the thread belongs.

Definition at line 127 of file thread.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_thread_arch_adopt()

M0_INTERNAL int m0_thread_arch_adopt ( struct m0_thread thread,
struct m0 instance,
bool  full 
)

Definition at line 231 of file uthread.c.

Here is the call graph for this function:

◆ m0_thread_arch_shun()

M0_INTERNAL void m0_thread_arch_shun ( void  )

Definition at line 244 of file uthread.c.

Here is the call graph for this function:

◆ m0_thread_confine()

M0_INTERNAL int m0_thread_confine ( struct m0_thread q,
const struct m0_bitmap processors 
)

Sets thread affinity to a given processor bitmap.

The user space implementation calls pthread_setaffinity_np and the kernel implementation modifies fields of the task_struct directly.

See also
http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_setaffinity_np.3.html
lib/processor.h
Kernel Thread Implementation
Parameters
qthread whose affinity is to be set (confined)
processorsbitmap of processors, true values are those on which the thread can run
Return values
0success
!0failed to set affinity, -errno

Definition at line 129 of file uthread.c.

Here is the call graph for this function:

◆ m0_thread_enter()

M0_INTERNAL void m0_thread_enter ( struct m0_thread thread,
bool  full 
)

Definition at line 98 of file kthread.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_thread_fini()

int void m0_thread_fini ( struct m0_thread q)

Releases resources associated with the thread.

Precondition
q->t_state == TS_PARKED

Definition at line 92 of file thread.c.

Here is the call graph for this function:

◆ m0_thread_init()

int m0_thread_init ( struct m0_thread q,
int(*)(void *)  init,
void(*)(void *)  func,
void *  arg,
const char *  namefmt,
  ... 
)

Creates a new thread.

If "init" is not NULL, the created thread starts execution by calling (*init)(arg). If this call returns non-zero, thread exits and m0_thread_init() returns the value returned by "init".

Otherwise (or in the case where "init" is NULL), m0_thread_init() returns 0 and the thread calls (*func)(arg) and exits when this call completes.

The namefmt and its arguments are used to name the thread. The formatted name is truncated to M0_THREAD_NAME_LEN characters (based on TASK_COMM_LEN).

Note
it is possible that after successful return from m0_thread_init() the thread hasn't yet entered "func" code, it is also possible that the thread has finished its execution.
Precondition
q->t_state == TS_PARKED
Postcondition
(result != 0) == (q->t_state == TS_PARKED)
(result == 0) == (q->t_state == TS_RUNNING)

Definition at line 41 of file thread.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_thread_init_impl()

M0_INTERNAL int m0_thread_init_impl ( struct m0_thread q,
const char *  name 
)

Internal helper for m0_thread_init() that creates the user or kernel thread after the m0_thread q has been initialised.

Precondition
q->t_state == TS_RUNNING
Return values
0thread created
-errnofailed

Definition at line 103 of file uthread.c.

◆ m0_thread_join()

int m0_thread_join ( struct m0_thread q)

Waits until the thread exits.

After this calls returns successfully it is guaranteed that no code would be ever executed by the "q", including instructions that touch stack or code pages. Note that the same effect can not be reliably achieved by the explicit synchronization (e.g., by signalling a condition variable at the end of a thread function), because the thread might be still executing instructions after it returns from m0_thread::t_func.

Precondition
q->t_state == TS_RUNNING
q is different from the calling thread
Postcondition
(result == 0) == (q->t_state == TS_PARKED)
Return values
0thread joined (thread is terminated)
-errnofailed to join, not exit status of thread

Definition at line 111 of file uthread.c.

◆ m0_thread_leave()

M0_INTERNAL void m0_thread_leave ( void  )

Definition at line 108 of file kthread.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_thread_self()

M0_INTERNAL struct m0_thread * m0_thread_self ( void  )

Returns the current thread.

Definition at line 122 of file thread.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_thread_shun()

M0_INTERNAL void m0_thread_shun ( void  )

Discards Motr per-thread context. This is dual to m0_thread_adopt().

Definition at line 134 of file thread.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_thread_signal()

M0_INTERNAL int m0_thread_signal ( struct m0_thread q,
int  sig 
)

Send specified signal to this thread.

Definition at line 124 of file uthread.c.

◆ m0_thread_tls()

M0_INTERNAL struct m0_thread_tls* m0_thread_tls ( void  )

Returns thread-local storage.

Note
The returned value is never NULL.

Definition at line 76 of file uthread.c.

◆ m0_thread_tls_back()

M0_INTERNAL void m0_thread_tls_back ( struct m0_thread_tls tls)

Definition at line 282 of file kthread.c.

Here is the caller graph for this function:

◆ m0_thread_tls_pop()

M0_INTERNAL struct m0_thread_tls* m0_thread_tls_pop ( void  )

Definition at line 274 of file kthread.c.

Here is the caller graph for this function:

◆ m0_thread_trampoline()

M0_INTERNAL void * m0_thread_trampoline ( void *  t)

Threads created by m0_thread_init_impl execute this function to perform common bookkeeping, executing t->t_init if appropriate, and then executing t->t_func.

Precondition
t->t_state == TS_RUNNING && t->t_initrc == 0
Parameters
ta m0_thread*, passed as void* to be compatible with pthread_create function argument.
Return values
NULL

Definition at line 101 of file thread.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_threads_fini()

M0_INTERNAL void m0_threads_fini ( void  )

Definition at line 163 of file uthread.c.

◆ m0_threads_init()

M0_INTERNAL int m0_threads_init ( struct m0 instance)

Initialises thread system.

m0_threads_init() is usually called at the early stages of Motr initialisation, i.e., early in m0_init().

Parameters
instanceInitial m0 instance.

Definition at line 155 of file uthread.c.

Here is the call graph for this function:

◆ m0_threads_once_fini()

M0_INTERNAL void m0_threads_once_fini ( void  )

Definition at line 189 of file uthread.c.

◆ m0_threads_once_init()

M0_INTERNAL int m0_threads_once_init ( void  )

Definition at line 168 of file uthread.c.

◆ uthread_trampoline()

static void* uthread_trampoline ( void *  arg)
static

Definition at line 93 of file uthread.c.

Here is the call graph for this function:

Variable Documentation

◆ m0_argv0

M0_INTERNAL char m0_argv0[PATH_MAX] = {}

Definition at line 146 of file uthread.c.

◆ m0_debugger_args

M0_INTERNAL char* m0_debugger_args[4]
Initial value:
= {
NULL,
NULL,
NULL,
}
#define NULL
Definition: misc.h:38

Definition at line 148 of file uthread.c.

◆ M0_XCA_DOMAIN

struct m0_thread_tls M0_XCA_DOMAIN

◆ main_thread

struct m0_thread main_thread
static
Initial value:
= {
.t_state = TS_RUNNING,
.t_tls = {
.tls_self = &main_thread
},
.t_namebuf = "main()"
}
static struct m0_thread main_thread
Definition: uthread.c:68
char t_namebuf[M0_THREAD_NAME_LEN]
Definition: thread.h:119

Definition at line 68 of file uthread.c.

◆ pthread_attr_default

pthread_attr_t pthread_attr_default
static

Default pthread creation attribute.

Todo:
move this in m0 instance.

Definition at line 63 of file uthread.c.

◆ thread

__thread struct m0_thread thread = {}
static

Definition at line 65 of file uthread.c.

◆ tls

__thread struct m0_thread_tls* tls = NULL
static

Definition at line 66 of file uthread.c.