/*
* Copyright (c) 2012 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/** @file
* Defines the API in the
* Pthread library
*
* @addtogroup Pthread
* @{
*/
#ifndef _PTHREAD_H
#define _PTHREAD_H 1
#include
#include
#include
#include
#include
#include
/*
* Signed 32-bit integer supporting CompareAndSwap and AtomicIncrement
* (see implementations), as well as atomic loads and stores.
* Instances must be naturally aligned.
*/
typedef int AtomicInt32;
#ifdef __cplusplus
extern "C" {
#endif
struct timespec;
struct __nc_basic_thread_data;
/** Mutex type attributes */
enum {
/** Fast mutex type; for use with pthread_mutexattr_settype() */
PTHREAD_MUTEX_FAST_NP,
/** Recursive mutex type; for use with pthread_mutexattr_settype() */
PTHREAD_MUTEX_RECURSIVE_NP,
/** Error-checking mutex type; for use with pthread_mutexattr_settype() */
PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP,
PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
};
/*
* The layout of pthread_mutex_t and the static initializers are redefined
* in newlib's sys/lock.h file (including this file from sys/lock.h will
* cause include conflicts). When changing one of the definitions, make sure to
* change the second one.
*/
/**
* A structure representing a thread mutex. It should be considered an
* opaque record; the names of the fields can change anytime.
*/
typedef struct {
/*
* mutex_state is either UNLOCKED (0), LOCKED_WITHOUT_WAITERS (1) or
* LOCKED_WITH_WAITERS (2). See "enum MutexState".
*/
volatile int mutex_state;
/**
* The kind of mutex:
* PTHREAD_MUTEX_FAST_NP, PTHREAD_MUTEX_RECURSIVE_NP,
* or PTHREAD_MUTEX_ERRORCHECK_NP
*/
int mutex_type;
/** ID of the thread that owns the mutex */
struct __nc_basic_thread_data *owner_thread_id;
/** Recursion depth counter for recursive mutexes */
uint32_t recursion_counter;
/*
* Padding is for compatibility with libraries (newlib etc.) that
* were built before libpthread switched to using futexes, and to
* match _LOCK_T in newlib's newlib/libc/include/sys/lock.h.
*/
int unused_padding;
} pthread_mutex_t;
/**
* A structure representing mutex attributes. It should be considered an
* opaque record and accessed only using pthread_mutexattr_settype().
*/
typedef struct {
/**
* The kind of mutex:
* PTHREAD_MUTEX_FAST_NP, PTHREAD_MUTEX_RECURSIVE_NP,
* or PTHREAD_MUTEX_ERRORCHECK_NP
*/
int kind;
} pthread_mutexattr_t;
/**
* A structure representing a condition variable. It should be considered an
* opaque record; the names of the fields can change anytime.
*/
typedef struct {
/* This is incremented on each pthread_cond_signal/broadcast() call. */
int sequence_number;
/*
* Padding is for compatibility with libraries (newlib etc.) that
* were built before libpthread switched to using futexes.
*/
int unused_padding;
} pthread_cond_t;
/**
* A structure representing condition variable attributes. Currently
* Native Client condition variables have no attributes.
*/
typedef struct {
int dummy; /**< Reserved; condition variables don't have attributes */
} pthread_condattr_t;
/** A value that represents an uninitialized handle. */
#define NC_INVALID_HANDLE -1
/** Maximum valid thread ID value. */
#define MAX_THREAD_ID (0xfffffffe)
/** Illegal thread ID value. */
#define NACL_PTHREAD_ILLEGAL_THREAD_ID ((pthread_t) 0)
/** Statically initializes a pthread_mutex_t representing a recursive mutex. */
#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
{0, 1, NACL_PTHREAD_ILLEGAL_THREAD_ID, 0, NC_INVALID_HANDLE}
/** Statically initializes a pthread_mutex_t representing a fast mutex. */
#define PTHREAD_MUTEX_INITIALIZER \
{0, 0, NACL_PTHREAD_ILLEGAL_THREAD_ID, 0, NC_INVALID_HANDLE}
/**
* Statically initializes a pthread_mutex_t representing an
* error-checking mutex.
*/
#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
{0, 2, NACL_PTHREAD_ILLEGAL_THREAD_ID, 0, NC_INVALID_HANDLE}
/** Statically initializes a condition variable (pthread_cond_t). */
#define PTHREAD_COND_INITIALIZER {0, NC_INVALID_HANDLE}
/* Functions for mutex handling. */
/** @nqPosix
* Initializes a mutex using attributes in mutex_attr, or using the
* default values if the latter is NULL.
*
* @linkPthread
*
* @param mutex The address of the mutex structure to be initialized.
* @param mutex_attr The address of the attributes structure.
*
* @return 0 upon success, 1 otherwise
*/
extern int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutex_attr);
/** @nqPosix
* Destroys a mutex.
*
* @linkPthread
*
* @param mutex The address of the mutex structure to be destroyed.
*
* @return 0 upon success, non-zero error code otherwise
*/
extern int pthread_mutex_destroy(pthread_mutex_t *mutex);
/** @nqPosix
* Tries to lock a mutex.
*
* @linkPthread
*
* @param mutex The address of the mutex structure to be locked.
*
* @return 0 upon success, EBUSY if the mutex is locked by another thread,
* non-zero error code otherwise.
*/
extern int pthread_mutex_trylock(pthread_mutex_t *mutex);
/** @nqPosix
* Locks a mutex.
*
* @linkPthread
*
* @param mutex The address of the mutex structure to be locked.
*
* @return 0 upon success, non-zero error code otherwise.
*/
extern int pthread_mutex_lock(pthread_mutex_t *mutex);
/* Wait until lock becomes available, or specified time passes. */
extern int pthread_mutex_timedlock(pthread_mutex_t *mutex,
struct timespec *abstime);
/** @nqPosix
* Unlocks a mutex.
*
* @linkPthread
*
* @param mutex The address of the mutex structure to be unlocked.
*
* @return 0 upon success, non-zero error code otherwise.
*/
extern int pthread_mutex_unlock(pthread_mutex_t *mutex);
/* Mutex attributes manipulation */
/** @nqPosix
* Initializes mutex attributes.
*
* @linkPthread
*
* @param attr The address of the attributes structure to be initialized.
*
* @return 0.
*/
extern int pthread_mutexattr_init(pthread_mutexattr_t *attr);
/** @nqPosix
* Destroys mutex attributes structure.
*
* @linkPthread
*
* @param attr The address of the attributes structure to be destroyed.
*
* @return 0.
*/
extern int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
/** @nqPosix
* Sets the mutex type: fast, recursive or error-checking.
*
* @linkPthread
*
* @param attr The address of the attributes structure.
* @param kind PTHREAD_MUTEX_FAST_NP, PTHREAD_MUTEX_RECURSIVE_NP or
* PTHREAD_MUTEX_ERRORCHECK_NP.
*
* @return 0 on success, -1 for illegal values of kind.
*/
extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr,
int kind);
/** @nqPosix
* Gets the mutex type: fast, recursive or error-checking.
*
* @linkPthread
*
* @param attr The address of the attributes structure.
* @param kind Pointer to the location where the mutex kind value is copied.
*
* @return 0.
*/
extern int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr,
int *kind);
/* Functions for handling conditional variables. */
/** @nqPosix
* Initializes a condition variable.
*
* @linkPthread
*
* @param cond Pointer to the condition variable structure.
* @param cond_attr Pointer to the attributes structure, should be NULL as
* Native Client does not support any attributes for a condition variable at
* this stage.
*
* @return 0 for success, 1 otherwise.
*/
extern int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *cond_attr);
/** @nqPosix
* Destroys a condition variable.
*
* @linkPthread
*
* @param cond Pointer to the condition variable structure.
*
* @return 0 for success, non-zero error code otherwise.
*/
extern int pthread_cond_destroy(pthread_cond_t *cond);
/** @nqPosix
* Signals a condition variable, waking up one of the threads waiting on it.
*
* @linkPthread
*
* @param cond Pointer to the condition variable structure.
*
* @return 0 for success, non-zero error code otherwise.
*/
extern int pthread_cond_signal(pthread_cond_t *cond);
/** @nqPosix
* Wakes up all threads waiting on a condition variable.
*
* @linkPthread
*
* @param cond Pointer to the condition variable structure.
*
* @return 0 for success, non-zero error code otherwise.
*/
extern int pthread_cond_broadcast(pthread_cond_t *cond);
/** @nqPosix
* Waits for a condition variable to be signaled or broadcast.
*
* @linkPthread
*
* @param cond Pointer to the condition variable structure.
* @param mutex Pointer to the mutex structure. The mutex is assumed to be locked
* when this function is called.
*
* @return 0 for success, non-zero error code otherwise.
*/
extern int pthread_cond_wait(pthread_cond_t *cond,
pthread_mutex_t *mutex);
/** @nqPosix
* Waits for condition variable cond to be signaled or broadcast until
* abstime.
*
* @linkPthread
*
* @param cond Pointer to the condition variable structure.
* @param mutex Pointer to the mutex structure. The mutex is assumed to be locked
* when this function is called.
* @param abstime Absolute time specification; zero is the beginning of the epoch
* (00:00:00 GMT, January 1, 1970).
*
* @return 0 for success, non-zero error code otherwise.
*/
int pthread_cond_timedwait_abs(pthread_cond_t *cond,
pthread_mutex_t *mutex,
const struct timespec *abstime);
/** @nqPosix
* Waits for condition variable cond to be signaled or broadcast; wait time is
* limited by reltime.
*
* @linkPthread
*
* @param cond Pointer to the condition variable structure.
* @param mutex Pointer to the mutex structure. The mutex is assumed to be locked
* when this function is called.
* @param reltime Time specification, relative to the current time.
*
* @return 0 for success, non-zero error code otherwise.
*/
int pthread_cond_timedwait_rel(pthread_cond_t *cond,
pthread_mutex_t *mutex,
const struct timespec *reltime);
/**
* Defined for POSIX compatibility; pthread_cond_timedwait() is actually
* a macro calling pthread_cond_timedwait_abs().
*/
#define pthread_cond_timedwait pthread_cond_timedwait_abs
/* Threads */
/** Thread entry function type. */
typedef void *(*nc_thread_function)(void *p);
/** Thread identifier type. */
typedef struct __nc_basic_thread_data *pthread_t;
/** A structure representing thread attributes. */
typedef struct {
int joinable; /**< 1 if the thread is joinable, 0 otherwise */
size_t stacksize; /**< The requested thread stack size in bytes. */
} pthread_attr_t;
/** Joinable thread type; for use with pthread_attr_setdetachstate(). */
#define PTHREAD_CREATE_JOINABLE 1
/** Detached thread type; for use with pthread_attr_setdetachstate(). */
#define PTHREAD_CREATE_DETACHED 0
/** Minimum stack size; for use with pthread_attr_setstacksize(). */
#define PTHREAD_STACK_MIN (1024)
/* default stack size */
#define PTHREAD_STACK_DEFAULT (512 * 1024)
/* Thread functions */
/** @nqPosix
* Creates a thread.
*
* @linkPthread
*
* @param[out] thread_id A pointer to the location where the identifier of the
* newly created thread is stored on success.
* @param attr Thread attributes structure.
* @param start_routine Thread function.
* @param arg A single argument that is passed to the thread function.
*
* @return 0 for success, non-zero error code otherwise.
*/
extern int pthread_create(pthread_t *thread_id,
const pthread_attr_t *attr,
void *(*start_routine)(void *p),
void *arg);
/** @nqPosix
* Obtains the identifier of the current thread.
*
* @linkPthread
*
* @return Thread ID of the current thread.
*/
extern pthread_t pthread_self(void);
/** @nqPosix
* Compares two thread identifiers.
*
* @linkPthread
*
* @param thread1 Thread ID of thread A.
* @param thread2 Thread ID of thread B.
*
* @return 1 if both identifiers belong to the same thread, 0 otherwise.
*/
extern int pthread_equal(pthread_t thread1, pthread_t thread2);
/** @nqPosix
* Terminates the calling thread.
*
* @linkPthread
*
* @param retval Return value of the thread.
*
* @return The function never returns.
*/
extern void pthread_exit(void *retval);
/** @nqPosix
* Makes the calling thread wait for termination of another thread.
*
* @linkPthread
*
* @param th The identifier of the thread to wait for.
* @param thread_return If not NULL, points to the location where the return
* value of the terminated thread is stored upon completion.
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_join(pthread_t th, void **thread_return);
/** @nqPosix
* Indicates that the specified thread is never to be joined with pthread_join().
* The resources of that thread will therefore be freed immediately when it
* terminates, instead of waiting for another thread to perform pthread_join()
* on it.
*
* @linkPthread
*
* @param th Thread identifier.
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_detach(pthread_t th);
/** @nqPosix
* Sends a signal to a thread. (Currently only a stub implementation.)
*
* @linkPthread
*
* @param thread_id The identifier of the thread to receive the signal.
* @param sig The signal value to send.
*
* @return 0 for success, non-zero error code otherwise.
*/
extern int pthread_kill(pthread_t thread_id,
int sig);
/* Functions for handling thread attributes. */
/** @nqPosix
* Initializes thread attributes structure attr with default attributes
* (detachstate is PTHREAD_CREATE_JOINABLE).
*
* @linkPthread
*
* @param attr Pointer to thread attributes structure.
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_attr_init(pthread_attr_t *attr);
/** @nqPosix
* Destroys a thread attributes structure.
*
* @linkPthread
*
* @param attr Pointer to thread attributes structure.
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_attr_destroy(pthread_attr_t *attr);
/** @nqPosix
* Sets the detachstate attribute in thread attributes.
*
* @linkPthread
*
* @param attr Pointer to thread attributes structure.
* @param detachstate Value to be set, determines whether the thread is joinable.
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_attr_setdetachstate(pthread_attr_t *attr,
int detachstate);
/** @nqPosix
* Gets the detachstate attribute from thread attributes.
*
* @linkPthread
*
* @param attr Pointer to thread attributes structure.
* @param detachstate Location where the value of `detachstate` is stored upon
* successful completion.
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_attr_getdetachstate(pthread_attr_t *attr,
int *detachstate);
/** @nqPosix
* Sets the stacksize attribute in thread attributes. Has no effect if the
* size is less than PTHREAD_STACK_MIN.
*
* @linkPthread
*
* @param attr Pointer to thread attributes structure.
* @param stacksize Value to be set, determines the minimum stack size.
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_attr_setstacksize(pthread_attr_t *attr,
size_t stacksize);
/** @nqPosix
* Gets the stacksize attribute in thread attributes.
*
* @linkPthread
*
* @param attr Pointer to thread attributes structure.
* @param stacksize Value to be set, determines the minimum stack size.
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_attr_getstacksize(pthread_attr_t *attr,
size_t *stacksize);
/** @nqPosix
* Gets the maximum address of the stack (assuming stacks grow
* downwards) of the given thread.
*
* If the given thread exits concurrently with the call to this
* function, the behaviour is undefined.
*
* Note that in the future this may be removed and replaced with an
* implementation of pthread_getattr_np(), for consistency with Linux
* glibc. pthread_getattr_np() + pthread_attr_getstack() return the
* stack base (minimum) address and stack size. However, that is
* currently unimplementable under NaCl, because NaCl does not provide
* a way to determine the initial thread's stack size. See:
* https://code.google.com/p/nativeclient/issues/detail?id=3431
*/
extern int pthread_get_stack_end_np(pthread_t tid, void **stack_end);
/* Functions for handling thread-specific data. */
/** Thread-specific key identifier type */
typedef int pthread_key_t;
/** Number of available keys for thread-specific data. */
#define PTHREAD_KEYS_MAX 512
/** @nqPosix
* Creates a key value identifying a location in the thread-specific
* data area.
*
* @linkPthread
*
* @param key Pointer to the location where the value of the key is stored upon
* successful completion.
* @param destr_function Pointer to a cleanup function that is called if the
* thread terminates while the key is still allocated.
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_key_create(pthread_key_t *key,
void (*destr_function)(void *p));
/** @nqPosix
* Destroys a thread-specific data key.
*
* @linkPthread
*
* @param key Key value, previously obtained using pthread_key_create().
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_key_delete(pthread_key_t key);
/** @nqPosix
* Stores a value in the thread-specific data slot identified by a key value.
*
* @linkPthread
*
* @param key Key value, previously obtained using pthread_key_create().
* @param pointer The value to be stored.
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_setspecific(pthread_key_t key,
const void *pointer);
/** @nqPosix
* Gets the value currently stored at the thread-specific data slot
* identified by the key.
*
* @linkPthread
*
* @param key Key value, previously obtained using pthread_key_create().
*
* @return The value that was previously stored using pthread_setspecific is
* returned on success, otherwise NULL.
*/
extern void *pthread_getspecific(pthread_key_t key);
/**
* A structure describing a control block
* used with the pthread_once() function.
* It should be considered an opaque record;
* the names of the fields can change anytime.
*/
typedef struct {
/** A flag: 1 if the function was already called, 0 if it wasn't */
AtomicInt32 done;
/** Synchronization lock for the flag */
pthread_mutex_t lock;
} pthread_once_t;
/** Static initializer for pthread_once_t. */
#define PTHREAD_ONCE_INIT {0, PTHREAD_MUTEX_INITIALIZER}
/** @nqPosix
* Ensures that a piece of initialization code is executed at most once.
*
* @linkPthread
*
* @param __once_control Points to a static or extern variable statically
* initialized to PTHREAD_ONCE_INIT.
* @param __init_routine A pointer to the initialization function.
*
* @return 0.
*/
extern int pthread_once(pthread_once_t *__once_control,
void (*__init_routine)(void));
/** @nqPosix
* Sets the scheduling priority of a thread.
*
* @linkPthread
*
* @param thread_id Identifies the thread to operate on.
* @param prio Scheduling priority to apply to that thread.
*
* @return 0 on success, non-zero error code otherwise.
*/
extern int pthread_setschedprio(pthread_t thread_id, int prio);
/*
* NOTE: this is only declared here to shut up
* some warning in the c++ system header files.
* We do not define this function anywhere.
*/
extern int pthread_cancel(pthread_t th);
/*
* NOTE: There are only stub implementations of these functions.
*/
void pthread_cleanup_push(void (*func)(void *cleanup_arg), void *arg);
void pthread_cleanup_pop(int execute);
/**
* @} End of PTHREAD group
*/
#ifdef __cplusplus
}
#endif
#endif /* pthread.h */