/* * 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 */