Motr
M0
|
![]() |
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_tls * | m0_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_thread * | m0_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_tls * | m0_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_tls * | tls = NULL |
static struct m0_thread | main_thread |
M0_INTERNAL char | m0_argv0 [PATH_MAX] = {} |
M0_INTERNAL char * | m0_debugger_args [4] |
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).
Linux kernel m0_thread implementation
Kernel space implementation is based <linux/kthread.h>
Common m0_thread implementation.
User space m0_thread implementation
User space implementation is straight-forwardly based on POSIX thread interface.
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.
Helper macro creating an anonymous function with a given body.
For example:
LAMBDA is useful to create an "ad-hoc" function that can be passed as a call-back function pointer.
The long story. Consider an arrangement like
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
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).
#define M0_THREAD_ENTER |
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:
M0_THREAD_INIT() checks that type of the argument matches function prototype.
enum m0_thread_state |
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 void m0_thread__cleanup | ( | struct m0_thread * | bye | ) |
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.
M0_INTERNAL void m0_thread_arch_shun | ( | void | ) |
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.
q | thread whose affinity is to be set (confined) |
processors | bitmap of processors, true values are those on which the thread can run |
0 | success |
!0 | failed to set affinity, -errno |
Definition at line 129 of file uthread.c.
M0_INTERNAL void m0_thread_enter | ( | struct m0_thread * | thread, |
bool | full | ||
) |
int void m0_thread_fini | ( | struct m0_thread * | q | ) |
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).
Definition at line 41 of file thread.c.
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.
0 | thread created |
-errno | failed |
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.
0 | thread joined (thread is terminated) |
-errno | failed to join, not exit status of thread |
M0_INTERNAL void m0_thread_leave | ( | void | ) |
M0_INTERNAL struct m0_thread * m0_thread_self | ( | void | ) |
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.
M0_INTERNAL int m0_thread_signal | ( | struct m0_thread * | q, |
int | sig | ||
) |
M0_INTERNAL struct m0_thread_tls* m0_thread_tls | ( | void | ) |
M0_INTERNAL void m0_thread_tls_back | ( | struct m0_thread_tls * | tls | ) |
M0_INTERNAL struct m0_thread_tls* m0_thread_tls_pop | ( | void | ) |
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.
t | a m0_thread*, passed as void* to be compatible with pthread_create function argument. |
NULL |
Definition at line 101 of file thread.c.
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().
instance | Initial m0 instance. |
Definition at line 155 of file uthread.c.
|
static |
M0_INTERNAL char* m0_debugger_args[4] |
struct m0_thread_tls M0_XCA_DOMAIN |
|
static |
|
static |
|
static |