Threads and syncronization primitives

Provides cross-platform interface for threads handling and synchronization primitives.

Example of thread's function:

thread_result_t worker_thread(thread_arg_t arg) {
   THREAD_ENTRY(arg, workload_t, wl);

   ...
   if(cond)
     THREAD_EXIT(1);
   ...

THREAD_END:
      smth_destroy(...);
      THREAD_FINISH(arg);
}

You may pass an context variable into thread in t_init(), like workload_t
in this example. THREAD_ENTRY macro declares it and special variable 'thread':

   thread_t* thread;
      workload_t* wl;

NOTES
On Solaris mutex_ and cv_ function names are reserved by libc, so threads library prefixes it's names with ts.

Constants

THREAD_KEY_INITIALIZER, THREAD_EVENT_INITIALIZER, THREAD_MUTEX_INITIALIZER


Default object initializers

#define THREAD_EVENT_INITIALIZER    { SM_INIT(.te_impl, PLAT_THREAD_EVENT_INITIALIZER),        SM_INIT(.te_name, "\0") }
#define THREAD_MUTEX_INITIALIZER    { SM_INIT(.tm_impl, PLAT_THREAD_MUTEX_INITIALIZER),        SM_INIT(.tm_name, "\0"),                              SM_INIT(.tm_is_recursive, B_FALSE) }
#define THREAD_KEY_INITIALIZER  { SM_INIT(.tk_impl, PLAT_THREAD_KEY_INITIALIZER),        SM_INIT(.tk_name, "\0") }

TSTACKSIZE


Default stack size of thread

#define TSTACKSIZE  (64 * SZ_KB)

Functions

THREAD_ENTRY


THREAD_ENTRY macro should be inserted into beginning of thread function
declares thread_t* thread and argtype_t* arg_name (private argument passed to t_init)

#define THREAD_ENTRY(arg, arg_type, arg_name)

THREAD_FINISH, THREAD_END


THREAD_END and THREAD_FINISH are used as thread's epilogue:

THREAD_END:
De-initialization code goes here
THREAD_FINISH(arg);
}

#define THREAD_END  _l_thread_exit
#define THREAD_FINISH(arg)

THREAD_EXIT


THREAD_EXIT - prematurely exit from thread (works only in main function of thread)

#define THREAD_EXIT(code)

thread_start_func


Prototype of thread's function

typedef thread_result_t (*thread_start_func)(thread_arg_t arg);

mutex_init, mutex_unlock, mutex_lock, mutex_try_lock, rmutex_init, mutex_destroy

public


Mutexes

NOTES
rmutex_init() is deprecated

LIBEXPORT void mutex_init(thread_mutex_t* mutex, const char* namefmt, ...)
LIBEXPORT void rmutex_init(thread_mutex_t* mutex, const char* namefmt, ...)
LIBEXPORT boolean_t mutex_try_lock(thread_mutex_t* mutex)
LIBEXPORT void mutex_lock(thread_mutex_t* mutex)
LIBEXPORT void mutex_unlock(thread_mutex_t* mutex)
LIBEXPORT void mutex_destroy(thread_mutex_t* mutex)

rwlock_unlock, rwlock_lock_write, rwlock_lock_read, rwlock_init, rwlock_destroy

public


Read-write locks

LIBEXPORT void rwlock_init(thread_rwlock_t* rwlock, const char* namefmt, ...)
LIBEXPORT void rwlock_lock_read(thread_rwlock_t* rwlock)
LIBEXPORT void rwlock_lock_write(thread_rwlock_t* rwlock)
LIBEXPORT void rwlock_unlock(thread_rwlock_t* rwlock)
LIBEXPORT void rwlock_destroy(thread_rwlock_t* rwlock)

cv_destroy, cv_wait_timed, cv_wait, cv_init, cv_notify_one, cv_notify_all

public


Condition variables

LIBEXPORT void cv_init(thread_cv_t* cv, const char* namefmt, ...)
LIBEXPORT void cv_wait(thread_cv_t* cv, thread_mutex_t* mutex)
LIBEXPORT void cv_wait_timed(thread_cv_t* cv, thread_mutex_t* mutex, ts_time_t timeout)
LIBEXPORT void cv_notify_one(thread_cv_t* cv)
LIBEXPORT void cv_notify_all(thread_cv_t* cv)
LIBEXPORT void cv_destroy(thread_cv_t* cv)

tkey_get, tkey_init, tkey_set, tkey_destroy

public


Thread-local storage

LIBEXPORT void tkey_init(thread_key_t* key, const char* namefmt, ...)
LIBEXPORT void tkey_destroy(thread_key_t* key)
LIBEXPORT void tkey_set(thread_key_t* key, void* value)
LIBEXPORT void* tkey_get(thread_key_t* key)

t_self

public


returns pointer to current thread
Used to monitor mutex/event deadlock and starvation (see tutil.c)

LIBEXPORT thread_t* t_self()

t_init

public


Initialize and run thread

ARGUMENTS

LIBEXPORT void t_init(thread_t* thread, void* arg,thread_start_func start,const char* namefmt, ...)

t_post_init

public


Post-initialize thread. Called from context of thread by THREAD_ENTRY
Inserts it to hash-map and sets platform thread id if possible

ARGUMENTS

RETURN VALUES
t (for THREAD_ENTRY)

NOTES
Do not call this function directly, use THREAD_ENTRY macro

LIBEXPORT thread_t* t_post_init(thread_t* t)

t_exit

public


Exit from thread. Called from context of thread: notifies thread which is joined to t
and remove thread from hash_map.

NOTES
Do not call this function directly, use THREAD_EXIT macro

LIBEXPORT void t_exit(thread_t* t)

t_wait_start

public


Wait until thread starts

LIBEXPORT void t_wait_start(thread_t* t)

t_join

public


Wait until thread finishes

LIBEXPORT void t_join(thread_t* thread)

t_destroy

public


Destroy thread. If thread is still alive - join to it.

NOTES
blocks until thread exits from itself!

LIBEXPORT void t_destroy(thread_t* thread)

t_notify_state

public

LIBEXPORT void t_notify_state(thread_t* t, thread_state_t state)

threads_init, threads_fini

public

LIBEXPORT int threads_init(void)
LIBEXPORT void threads_fini(void)

t_eternal_wait

publicplat

LIBEXPORT PLATAPI void t_eternal_wait(void)

t_get_pid

publicplat

LIBEXPORT PLATAPI long t_get_pid(void)

t_dump_threads


Logs how many time each thread spent on event/mutex

void t_dump_threads() 

Types

thread_state_t


Thread states:

      |
    t_init              +----------------------------------------------+
      |                 |                                              |
TS_INITIALIZED --> TS_RUNNABLE --+--event_wait--> TS_WAITING ----------+
                        |        \                                     |
                      t_exit      \--mutex_lock--> TS_LOCKED ----------+
                        |
                        v
                     TS_DEAD

typedef enum {
    TS_INITIALIZED,
    TS_RUNNABLE,
    TS_WAITING,
    TS_LOCKED,
    TS_DEAD
} thread_state_t;

thread_cv_t

typedef struct {
    plat_thread_cv_t tcv_impl;

    char            tcv_name[TEVENTNAMELEN];
} thread_cv_t;

thread_mutex_t

typedef struct {
    plat_thread_mutex_t tm_impl;

    char             tm_name[TMUTEXNAMELEN];
    boolean_t        tm_is_recursive;
} thread_mutex_t;

thread_rwlock_t

typedef struct {
    plat_thread_rwlock_t tl_impl;

    char             tl_name[TRWLOCKNAMELEN];
} thread_rwlock_t;

thread_key_t

typedef struct {
    plat_thread_key_t tk_impl;

    char            tk_name[TKEYNAMELEN];
} thread_key_t;

thread_event_t

typedef struct {
    thread_mutex_t    te_mutex;
    thread_cv_t     te_cv;

    char            te_name[TEVENTNAMELEN];
} thread_event_t;

typedef unsigned    thread_id_t;

typedef struct thread


Thread structure

MEMBERS

typedef struct thread {
    plat_thread_t    t_impl;
    plat_sched_t    t_sched_impl;

    thread_state_t    t_state;

    thread_id_t      t_id;
    int                t_local_id;

    unsigned long   t_system_id;

    char             t_name[TNAMELEN];
    
    /* We cannot use tutil primitives directly because
       it may break TS_LOCK_DEBUG and introduce a deadlock
       Fallback directly to platform versions */
    plat_thread_mutex_t        t_mutex;
    plat_thread_cv_t        t_condvar;
    
    void*            t_arg;
    unsigned        t_ret_code;

#ifdef TS_LOCK_DEBUG
    ts_time_t        t_block_time;
    thread_cv_t*    t_block_cv;
    thread_mutex_t* t_block_mutex;
    thread_rwlock_t* t_block_rwlock;
#endif

    struct thread*    t_next;            /*< Next thread in global thread list*/
    struct thread*    t_pool_next;    /*< Next thread in pool*/
} thread_t;