From: Lawrence S. <ljs...@us...> - 2014-11-05 17:46:17
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 47829c785b649b987a4f6eadedfd9e2500a50fb3 (commit) via e457937b8111cdc6a33cf1d6780d76601b0add59 (commit) via 6cdc70924ff0b9e5dd74611bf92595351ad521ab (commit) from 41725dd391b0625b72b19e57a4edef3e33457b62 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 47829c785b649b987a4f6eadedfd9e2500a50fb3 Author: Lawrence Sebald <ljs...@us...> Date: Wed Nov 5 12:44:35 2014 -0500 Add in C11 threading support. commit e457937b8111cdc6a33cf1d6780d76601b0add59 Author: Lawrence Sebald <ljs...@us...> Date: Wed Nov 5 12:42:49 2014 -0500 Fix a small typo in a doxygen comment. commit 6cdc70924ff0b9e5dd74611bf92595351ad521ab Author: Lawrence Sebald <ljs...@us...> Date: Mon Nov 3 16:02:17 2014 -0500 Fix stupid spacing in tls.c. ----------------------------------------------------------------------- Summary of changes: doc/CHANGELOG | 1 + include/sys/dirent.h | 2 +- include/threads.h | 504 ++++++++++++++++++++ kernel/libc/Makefile | 5 +- kernel/libc/c11/Makefile | 15 + kernel/libc/c11/call_once.c | 11 + kernel/libc/c11/cnd_broadcast.c | 11 + kernel/libc/c11/cnd_destroy.c | 11 + kernel/libc/c11/cnd_init.c | 11 + kernel/libc/c11/cnd_signal.c | 11 + kernel/libc/c11/cnd_timedwait.c | 31 ++ kernel/libc/c11/cnd_wait.c | 11 + kernel/libc/c11/mtx_destroy.c | 11 + kernel/libc/c11/mtx_init.c | 14 + kernel/libc/c11/mtx_lock.c | 11 + kernel/libc/c11/mtx_timedlock.c | 30 ++ kernel/libc/c11/mtx_trylock.c | 19 + kernel/libc/c11/mtx_unlock.c | 11 + kernel/libc/c11/thrd_create.c | 19 + kernel/libc/c11/thrd_current.c | 11 + kernel/libc/c11/thrd_detach.c | 14 + kernel/libc/c11/thrd_equal.c | 11 + kernel/libc/c11/thrd_exit.c | 11 + kernel/libc/c11/thrd_join.c | 17 + .../libc/{koslib/nanosleep.c => c11/thrd_sleep.c} | 27 +- kernel/libc/c11/thrd_yield.c | 11 + kernel/libc/c11/tss_create.c | 11 + kernel/libc/c11/tss_delete.c | 11 + kernel/libc/c11/tss_get.c | 11 + kernel/libc/c11/tss_set.c | 11 + kernel/thread/tls.c | 20 +- 31 files changed, 876 insertions(+), 29 deletions(-) create mode 100644 include/threads.h create mode 100644 kernel/libc/c11/Makefile create mode 100644 kernel/libc/c11/call_once.c create mode 100644 kernel/libc/c11/cnd_broadcast.c create mode 100644 kernel/libc/c11/cnd_destroy.c create mode 100644 kernel/libc/c11/cnd_init.c create mode 100644 kernel/libc/c11/cnd_signal.c create mode 100644 kernel/libc/c11/cnd_timedwait.c create mode 100644 kernel/libc/c11/cnd_wait.c create mode 100644 kernel/libc/c11/mtx_destroy.c create mode 100644 kernel/libc/c11/mtx_init.c create mode 100644 kernel/libc/c11/mtx_lock.c create mode 100644 kernel/libc/c11/mtx_timedlock.c create mode 100644 kernel/libc/c11/mtx_trylock.c create mode 100644 kernel/libc/c11/mtx_unlock.c create mode 100644 kernel/libc/c11/thrd_create.c create mode 100644 kernel/libc/c11/thrd_current.c create mode 100644 kernel/libc/c11/thrd_detach.c create mode 100644 kernel/libc/c11/thrd_equal.c create mode 100644 kernel/libc/c11/thrd_exit.c create mode 100644 kernel/libc/c11/thrd_join.c copy kernel/libc/{koslib/nanosleep.c => c11/thrd_sleep.c} (64%) create mode 100644 kernel/libc/c11/thrd_yield.c create mode 100644 kernel/libc/c11/tss_create.c create mode 100644 kernel/libc/c11/tss_delete.c create mode 100644 kernel/libc/c11/tss_get.c create mode 100644 kernel/libc/c11/tss_set.c diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 176f26f..6ac3262 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -52,6 +52,7 @@ KallistiOS version 2.0.1 ----------------------------------------------- - DC Added an example of the PVR's cheap shadow functionality [LS] - DC Added a tool for generation of bumpmaps that was sent to the mailing list all the way back in 2005 [Fredrik Ehnbom = FE] +- *** Added in C11 threading support [LS] KallistiOS version 2.0.0 ----------------------------------------------- - DC Broadband Adapter driver fixes [Dan Potter == DP] diff --git a/include/sys/dirent.h b/include/sys/dirent.h index eb30e79..8733dd1 100644 --- a/include/sys/dirent.h +++ b/include/sys/dirent.h @@ -101,7 +101,7 @@ struct dirent *readdir(DIR *dir); This function retrieves the file descriptor of a directory stream that was previously opened with opendir(). - \param dir The directory stream to retrieve the descriptor of. + \param dirp The directory stream to retrieve the descriptor of. \return The file descriptor from the directory stream on success or -1 on failure (sets errno as appropriate). diff --git a/include/threads.h b/include/threads.h new file mode 100644 index 0000000..d9669c7 --- /dev/null +++ b/include/threads.h @@ -0,0 +1,504 @@ +/* KallistiOS ##version## + + threads.h + Copyright (C) 2014 Lawrence Sebald +*/ + +/** \file threads.h + \brief C11 threading functionality. + + This file contains the definitions needed for using C11 threads. The C11 + standard defines a number of threading-related primitives, which we wrap + neatly around KOS' built-in threading support here. + + If you compile your code with a strict standard set (you use a -std= flag + with GCC that doesn't start with gnu), you must use -std=c11 to use this + functionality. If you don't pass a -std= flag to GCC, then you're probably + fine. + + \author Lawrence Sebald +*/ + +#ifndef __THREADS_H +#define __THREADS_H + +#if !defined(__STRICT_ANSI__) || (__STDC_VERSION__ >= 201112L) + +#include <sys/cdefs.h> +#include <time.h> + +/* Bring in all the threading-related stuff we'll need. */ +#include <kos/thread.h> +#include <kos/once.h> +#include <kos/mutex.h> +#include <kos/cond.h> +#include <kos/tls.h> + +__BEGIN_DECLS + +/** \defgroup c11_thd_rvs C11 Thread function return values + + Most of the C11 thread-related functions that return a result code return + one of these. + + @{ +*/ +#define thrd_success 0 /**< \brief Success */ +#define thrd_error -1 /**< \brief Uncategorized error */ +#define thrd_timedout -2 /**< \brief Time out error */ +#define thrd_busy -3 /**< \brief Resource busy */ +#define thrd_nomem -4 /**< \brief Out of memory */ +/** @} */ + +/** \brief Object type backing call_once. + + This object type holds a flag that is used by the call_once function to call + a function one time. It should always be initialized with the ONCE_FLAG_INIT + macro. + + \headerfile threads.h +*/ +typedef kthread_once_t once_flag; + +/** \brief Macro to initiallize a once_flag object. */ +#define ONCE_FLAG_INIT KTHREAD_ONCE_INIT + +/** \brief Call a function one time, no matter how many threads try. + + This function uses the once_flag object passed in to ensure that a given + function is called exactly once, regardless of how many threads attempt to + call through the once_flag. + + \param flag The once_flag to run against. + \param func The function to call. +*/ +extern void call_once(once_flag *flag, void (*func)(void)); + +/** \brief C11 mutual exclusion lock type. + + This type holds an identifier for a mutual exclusion (mutex) lock to be used + with C11 threading support. + + \headerfile threads.h +*/ +typedef mutex_t mtx_t; + +/** \defgroup c11_mutex_types C11 mutual exclusion lock types + + These are the possible types of mutex locks that C11 allows for. Note that + mtx_plain or mtx_recursive can be ORed with mtx_timed as well. + + @{ +*/ +#define mtx_plain (1 << 0) /**< \brief Plain mutex */ +#define mtx_recursive (1 << 1) /**< \brief Recursive mutex */ +#define mtx_timed (1 << 2) /**< \brief Mutex supporting the + mtx_timedlock function. */ +/** @} */ + +/** \brief Deinitialize a mutex lock. + + This function deinitializes a mutex lock that was previously created with + mtx_init(). + + \param mtx The mutex to deinitialize. +*/ +extern void mtx_destroy(mtx_t *mtx); + +/** \brief Initialize a mutex lock. + + This function initializes a mutex lock of the given type for later use to + protect critical sections of code. + + \param mtx The mutex to initialize. + \param type The type of mutex desired (see + \ref c11_mutex_types). + \retval thrd_success On success. + \retval thrd_error If the request could not be honored. +*/ +extern int mtx_init(mtx_t *mtx, int type); + +/** \brief Lock a mutex lock. + + This function locks the specified mutex, preventing any other threads from + obtaining the same lock. + + This function will block until the lock can be obtained. + + \param mtx The mutex to lock. + \retval thrd_success On success. + \retval thrd_error If the request could not be honored. + + \note Calling this function in an interrupt will result in an error being + returned. +*/ +extern int mtx_lock(mtx_t *mtx); + +/** \brief Lock a mutex lock with a timeout. + + This function locks the specified mutex, assuming that the lock can be + obtained in the time period specified. + + This function will block until the lock can be obtained or the timeout + expires. + + \param mtx The mutex to lock. + \param ts The amount of time to wait before timing out. + \retval thrd_success On success. + \retval thrd_error If the request could not be honored for some other + reason than a timeout. + \retval thrd_timedout If the timeout specified passes without obtaining + the lock. + + \note Calling this function in an interrupt will result in an error being + returned. + \note Although timeouts are specified in seconds and nanoseconds, the + timeout will be rounded up to the nearest millisecond. +*/ +extern int mtx_timedlock(mtx_t *restrict mtx, + const struct timespec *restrict ts); + +/** \brief Attempt to acquire a mutex lock. + + This function attempts to acquire the specififed mutex and will not block if + it cannot be obtained. + + \param mtx The mutex to lock. + \retval thrd_success On success. + \retval thrd_busy If the lock is already locked by a thread. + \retval thrd_error If the request could not be honored for some other + reason. + + \note This function is safe to call in an interrupt. + \note Always check the return value to ensure that the lock was obtained. +*// +extern int mtx_trylock(mtx_t *mtx); + +/** \brief Unlock a previously acquired lock. + + This function releases the specified mutex lock, allowing other threads to + acquire it. + + \param mtx The mutex to unlock. + \retval thrd_success On success. + \retval thrd_error If the request cannot be honored. + + \note Unlocking a mutex that was not previously locked by the calling + thread results in undefined behavior. +*/ +extern int mtx_unlock(mtx_t *mtx); + +/** \brief C11 condition variable type. + + This type holds an identifier for a condition variable object that is to be + used with C11 threading support. + + \headerfile threads.h +*/ +typedef condvar_t cnd_t; + +/** \brief Broadcast to all threads locked on a condition variable. + + This function wakes all threads that are blocked on the condition variable + cond at the time of the call. If no threads are currently blocked on cond, + this call does nothing. + + \param cond The condition variable to signal. + \retval thrd_success On success. + \retval thrd_error If the request cannot be honored. +*/ +extern int cnd_broadcast(cnd_t *cond); + +/** \brief Deinitialize a condition variable. + + This function cleans up all resources associated with the given condition + variable. You must ensure that no threads are currently blocked on the + condition variable before calling this function. + + \param cond The condition variable to deinitialize. + + \note Deinitializing a condition variable that is currently being waited + on by threads results in undefined behavior. +*/ +extern void cnd_destroy(cnd_t *cond); + +/** \brief Initialize a condition variable. + + This function initializes the specified condition variable for use. + + \param cond The condition variable to signal. + \retval thrd_success On success. + \retval thrd_nomem If memory cannot be allocated for the new condition + variable. + \retval thrd_error If the request cannot be honored for some other + reason. +*/ +extern int cnd_init(cnd_t *cond); + +/** \brief Signal one thread locked on a condition variable. + + This function wakes one thread that is blocked on the condition variable + cond at the time of the call. If no threads are currently blocked on cond, + this call does nothing. + + \param cond The condition variable to signal. + \retval thrd_success On success. + \retval thrd_error If the request cannot be honored. +*/ +extern int cnd_signal(cnd_t *cond); + +/** \brief Wait on a condition variable (with a timeout). + + This function puts the calling thread to sleep until either the condition + variable is signaled or the timeout specified expires, whichever happens + first. The specified mutex must be held by the calling thread when calling + this function and will be held by the thread again when it is unblocked. + + \param cond The condition variable to wait on. + \param mtx The mutex associated with the condition variable. + \param ts The time to wait before timing out. + \retval thrd_success On success. + \retval thrd_timedout If the timeout was reached before the condition + variable was signaled. + \retval thrd_error If the request cannot be honored for some other + reason. + + \note Calling this function in an interrupt will result in an error being + returned. + \note Although timeouts are specified in seconds and nanoseconds, the + timeout will be rounded up to the nearest millisecond. +*/ +extern int cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx, + const struct timespec *restrict ts); + +/** \brief Wait on a condition variable. + + This function puts the calling thread to sleep until the condition variable + is signaled. The specified mutex must be held by the calling thread when + calling this function and will be held by the thread again when it is + unblocked. + + \param cond The condition variable to wait on. + \param mtx The mutex associated with the condition variable. + \retval thrd_success On success. + \retval thrd_error If the request cannot be honored. + + \note Calling this function in an interrupt will result in an error being + returned. +*/ +extern int cnd_wait(cnd_t *cond, mtx_t *mtx); + +/** \brief C11 thread identifier type. + + This type holds an identifier for a C11 thread. + + \headerfile threads.h +*/ +typedef kthread_t *thrd_t; + +/** \brief C11 thread start function type. + + This is a function pointer type representing a function used to begin a + thread. The thread exits when the function returns or calls thrd_exit(). + + \headerfile threads.h +*/ +typedef int (*thrd_start_t)(void *); + +/** \brief Create and start a new thread. + + This function creates a new thread, calling the function specified. The + thread is immediately added to the runnable queue of the scheduler and can + start at any moment after that. The thread ends when either the function + specified returns or when the thread calls thrd_exit(). + + \param thr Storage for the thread identifier. + \param func The function to call in the new thread. + \param arg Argument to pass to the function called. + \retval thrd_success On success. + \retval thrd_nomem If memory cannot be allocated to satisfy the + request. + \retval thrd_error If the request cannot be honored for some other + reason. + + \note All threads created are joinable threads by default. That means that + in order to free all resources at thread termination, the thread + must be joined with the thrd_join() function or detached at some + point with thrd_detach(). +*/ +extern int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); + +/** \brief Return the identifier of the currently running thread. + + \return The current thread's ID. +*/ +extern thrd_t thrd_current(void); + +/** \brief Detach a running thread. + + This function detaches a thread, which informs the kernel that any resources + associated with the thread should be freed immediately when it terminates. + + \param thr The thread to detach. + \retval thrd_success On success. + \retval thrd_error If the request cannot be honored. + + \note Detaching an already detached thread has no effect. + \note Detaching a thread that has been joined with another thread results + in undefined behavior. +*/ +extern int thrd_detach(thrd_t thr); + +/** \brief Compare two threads for equality. + + This function checks the two two thread identifiers passed in to see if they + refer to the same thread. + + \param thr0 The first thread to compare. + \param thr1 The second thread to compare. + \return 0 if the threads are not equal, nonzero if the + threads are equal. +*/ +extern int thrd_equal(thrd_t thr0, thrd_t thr1); + +/** \brief Terminate the current thread immediately. + + This function terminates the calling thread immediately, setting the return + value of the thread to the value specified. + + \param res The return value of the thread. + \note This function will not return. +*/ +extern _Noreturn void thrd_exit(int res); + +/** \brief Join a running thread. + + This function joins the current thread with the specified thread, blocking + until that thread has terminated. + + \param thr The thread to join with. + \param res Pointer to storage for the result code of the other + thread. Set to NULL if you don't care about the + result value. + \retval thrd_success On success. + \retval thrd_error If the request cannot be honored. + + \note Joining with a previously detached thread results in undefined + behavior. + \note Joining with a thread that has already been joined to another thread + results in undefined behavior. + \note Calling this function in an interrupt will result in an error being + returned. +*/ +extern int thrd_join(thrd_t thr, int *res); + +/** \brief Put the currently running thread to sleep. + + This function puts the currently running thread to sleep for the specified + duration of time, returning any left over time (if interrupted by a signal, + for instance) in the second parameter. + + \param duration The amount of time to sleep. + \param remaining Any remaining time from the duration that the thread + did not sleep for. + \return 0 if the requested time elapsed, a negative value + otherwise. + + \note Although the duration is expressed in seconds and nanoseconds, all + sleeping is done in millisecond increments. The value specified will + be rounded up if it is not an even number of milliseconds. + \note KOS does not support signals, so remaining will only ever have a + value after the function if there is some sort of error. + \note Calling this function in an interrupt will result in an error being + returned. +*/ +extern int thrd_sleep(const struct timespec *duration, + struct timespec *remaining); + +/** \brief Yield the current thread's timeslice. + + This function immediately pauses the current thread's execution and switches + to another thread in the ready queue (if there are any threads ready to ...<truncated>... hooks/post-receive -- A pseudo Operating System for the Dreamcast. |