123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- /*
- * Copyright (c) 2006-2024 RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2010-10-26 Bernard the first version
- */
- #include <rtthread.h>
- #include "pthread.h"
- #define MUTEXATTR_SHARED_MASK 0x0010
- #define MUTEXATTR_TYPE_MASK 0x000f
- const pthread_mutexattr_t pthread_default_mutexattr = PTHREAD_PROCESS_PRIVATE;
- /**
- * @brief Initializes a mutex attributes object.
- *
- * This function initializes a mutex attributes object pointed to by `attr` with
- * default attribute values. Once initialized, the attributes object can be used
- * to customize the behavior of mutexes created using it.
- *
- * @param[out] attr Pointer to the mutex attributes object to be initialized.
- *
- * @return
- * - 0 on success.
- * - Non-zero error code on failure.
- *
- * @note
- * After initialization, the mutex attributes object must be destroyed with
- * `pthread_mutexattr_destroy()` when it is no longer needed.
- *
- * @warning
- * Using an uninitialized mutex attributes object may result in undefined behavior.
- *
- * @see pthread_mutexattr_destroy, pthread_mutex_init
- */
- int pthread_mutexattr_init(pthread_mutexattr_t *attr)
- {
- if (attr)
- {
- *attr = pthread_default_mutexattr;
- return 0;
- }
- return EINVAL;
- }
- RTM_EXPORT(pthread_mutexattr_init);
- /**
- * @brief Destroys a mutex attributes object.
- *
- * This function releases any resources associated with the mutex attributes object
- * pointed to by `attr`. After the attributes object is destroyed, it should not
- * be used unless it is re-initialized with `pthread_mutexattr_init()`.
- *
- * @param[in,out] attr Pointer to the mutex attributes object to be destroyed.
- *
- * @return
- * - 0 on success.
- * - Non-zero error code on failure, including:
- * - `EINVAL`: The attributes object is invalid or uninitialized.
- *
- * @note
- * Destroying an uninitialized or already destroyed attributes object results in undefined behavior.
- *
- * @warning
- * Ensure that no mutexes are being initialized or created using this attributes object
- * at the time of its destruction.
- *
- * @see pthread_mutexattr_init, pthread_mutex_init
- */
- int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
- {
- if (attr)
- {
- *attr = -1;
- return 0;
- }
- return EINVAL;
- }
- RTM_EXPORT(pthread_mutexattr_destroy);
- /**
- * @brief Retrieves the type attribute of a mutex attributes object.
- *
- * This function retrieves the mutex type attribute from the attributes object
- * pointed to by `attr` and stores it in the integer pointed to by `type`.
- *
- * @param[in] attr Pointer to the mutex attributes object.
- * @param[out] type Pointer to an integer where the mutex type will be stored.
- * Possible values include:
- * - `PTHREAD_MUTEX_NORMAL`: Default mutex type.
- * - `PTHREAD_MUTEX_ERRORCHECK`: Mutex with error-checking.
- * - `PTHREAD_MUTEX_RECURSIVE`: Recursive mutex.
- *
- * @return
- * - 0 on success.
- * - Non-zero error code on failure, including:
- * - `EINVAL`: The attributes object or the `type` pointer is invalid.
- *
- * @note
- * Use this function to check the type of a mutex attributes object that has
- * already been initialized or configured.
- *
- * @see pthread_mutexattr_settype, pthread_mutexattr_init
- */
- int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
- {
- if (attr && type)
- {
- int atype = (*attr & MUTEXATTR_TYPE_MASK);
- if (atype >= PTHREAD_MUTEX_NORMAL && atype <= PTHREAD_MUTEX_ERRORCHECK)
- {
- *type = atype;
- return 0;
- }
- }
- return EINVAL;
- }
- RTM_EXPORT(pthread_mutexattr_gettype);
- /**
- * @brief Sets the type attribute of a mutex attributes object.
- *
- * This function sets the type of the mutex to be initialized using the
- * attributes object pointed to by `attr`. The `type` can be one of the
- * following values:
- * - `PTHREAD_MUTEX_NORMAL`: Default mutex type. The mutex does not allow
- * a thread to unlock it if it was not locked by that thread (this results
- * in undefined behavior).
- * - `PTHREAD_MUTEX_ERRORCHECK`: Error-checking mutex type. A thread trying to
- * lock a mutex it already holds will return an error.
- * - `PTHREAD_MUTEX_RECURSIVE`: Recursive mutex type. The same thread can lock
- * the mutex multiple times without causing a deadlock, but it must unlock it
- * the same number of times.
- *
- * @param[in,out] attr Pointer to the mutex attributes object.
- * @param[in] type The type to set for the mutex. One of the following:
- * - `PTHREAD_MUTEX_NORMAL`
- * - `PTHREAD_MUTEX_ERRORCHECK`
- * - `PTHREAD_MUTEX_RECURSIVE`
- *
- * @return
- * - 0 on success.
- * - Non-zero error code on failure, including:
- * - `EINVAL`: The specified type is invalid.
- *
- * @note
- * The type must be set before the mutex attributes object is used to
- * initialize a mutex with `pthread_mutex_init()`.
- *
- * @warning
- * Attempting to set an invalid mutex type will result in an error.
- *
- * @see pthread_mutexattr_gettype, pthread_mutexattr_init, pthread_mutex_init
- */
- int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
- {
- if (attr && type >= PTHREAD_MUTEX_NORMAL && type <= PTHREAD_MUTEX_ERRORCHECK)
- {
- *attr = (*attr & ~MUTEXATTR_TYPE_MASK) | type;
- return 0;
- }
- return EINVAL;
- }
- RTM_EXPORT(pthread_mutexattr_settype);
- /**
- * @brief Sets the shared attribute of a mutex attributes object.
- *
- * This function sets the `pshared` attribute of the mutex attributes object
- * pointed to by `attr`. The `pshared` attribute determines whether the mutex
- * is shared between threads of the same process or can be shared between
- * threads of different processes.
- *
- * @param[in,out] attr Pointer to the mutex attributes object.
- * @param[in] pshared The sharing behavior of the mutex. This can be one of the following:
- * - `PTHREAD_PROCESS_PRIVATE`: The mutex is only shared between threads
- * of the same process (this is the default behavior).
- * - `PTHREAD_PROCESS_SHARED`: The mutex can be shared between threads
- * of different processes (requires the mutex to be allocated in
- * shared memory).
- *
- * @return
- * - 0 on success.
- * - Non-zero error code on failure, including:
- * - `EINVAL`: Invalid `pshared` value or invalid attributes object.
- *
- * @note
- * The `pshared` attribute must be set before the mutex attributes object is
- * used to initialize a mutex with `pthread_mutex_init()`. For shared mutexes
- * (`PTHREAD_PROCESS_SHARED`), the mutex object must be allocated in shared memory.
- *
- * @warning
- * Attempting to set an invalid `pshared` value will result in an error.
- *
- * @see pthread_mutexattr_getpshared, pthread_mutexattr_init, pthread_mutex_init
- */
- int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
- {
- if (!attr)
- return EINVAL;
- switch (pshared)
- {
- case PTHREAD_PROCESS_PRIVATE:
- *attr &= ~MUTEXATTR_SHARED_MASK;
- return 0;
- case PTHREAD_PROCESS_SHARED:
- *attr |= MUTEXATTR_SHARED_MASK;
- return 0;
- }
- return EINVAL;
- }
- RTM_EXPORT(pthread_mutexattr_setpshared);
- /**
- * @brief Retrieves the shared attribute of a mutex attributes object.
- *
- * This function retrieves the `pshared` attribute from the mutex attributes
- * object pointed to by `attr` and stores it in the integer pointed to by `pshared`.
- * The `pshared` attribute indicates whether the mutex can be shared between threads
- * of different processes or only within the same process.
- *
- * @param[in] attr Pointer to the mutex attributes object.
- * @param[out] pshared Pointer to an integer where the shared attribute will be stored.
- * Possible values are:
- * - `PTHREAD_PROCESS_PRIVATE`: Mutex is shared only within the same process.
- * - `PTHREAD_PROCESS_SHARED`: Mutex can be shared between threads of different processes.
- *
- * @return
- * - 0 on success.
- * - Non-zero error code on failure, including:
- * - `EINVAL`: Invalid attributes object or the `pshared` pointer is NULL.
- *
- * @note
- * Use this function to check the shared attribute of an already initialized
- * mutex attributes object.
- *
- * @warning
- * Attempting to get the `pshared` attribute of an uninitialized or invalid
- * attributes object will result in an error.
- *
- * @see pthread_mutexattr_setpshared, pthread_mutexattr_init, pthread_mutex_init
- */
- int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared)
- {
- if (!attr || !pshared)
- return EINVAL;
- *pshared = (*attr & MUTEXATTR_SHARED_MASK) ? PTHREAD_PROCESS_SHARED
- : PTHREAD_PROCESS_PRIVATE;
- return 0;
- }
- RTM_EXPORT(pthread_mutexattr_getpshared);
- /**
- * @brief Initializes a mutex with optional attributes.
- *
- * This function initializes a mutex object pointed to by `mutex`. The mutex
- * can optionally be initialized with attributes specified by `attr`. If
- * `attr` is `NULL`, default attributes are used.
- *
- * @param[in,out] mutex Pointer to the mutex to be initialized.
- * @param[in] attr Pointer to the mutex attributes object. Pass `NULL` to use
- * default attributes.
- *
- * @return
- * - 0 on success.
- * - Non-zero error code on failure, including:
- * - `EINVAL`: Invalid parameters or result.
- *
- * @note
- * The mutex object must be destroyed using `pthread_mutex_destroy()` after it
- * is no longer needed to free associated resources.
- *
- * @warning
- * A mutex should not be re-initialized while it is already in use.
- *
- * @see pthread_mutex_destroy, pthread_mutex_lock, pthread_mutex_unlock
- */
- int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
- {
- rt_err_t result;
- char name[RT_NAME_MAX];
- static rt_uint16_t pthread_mutex_number = 0;
- if (!mutex)
- return EINVAL;
- /* build mutex name */
- rt_snprintf(name, sizeof(name), "pmtx%02d", pthread_mutex_number ++);
- if (attr == RT_NULL)
- mutex->attr = pthread_default_mutexattr;
- else
- mutex->attr = *attr;
- /* init mutex lock */
- result = rt_mutex_init(&(mutex->lock), name, RT_IPC_FLAG_PRIO);
- if (result != RT_EOK)
- return EINVAL;
- /* detach the object from system object container */
- rt_object_detach(&(mutex->lock.parent.parent));
- mutex->lock.parent.parent.type = RT_Object_Class_Mutex;
- return 0;
- }
- RTM_EXPORT(pthread_mutex_init);
- /**
- * @brief Destroys a mutex object.
- *
- * This function releases any resources associated with the mutex object
- * pointed to by `mutex`. After the mutex has been destroyed, it cannot
- * be used unless it is re-initialized with `pthread_mutex_init()`.
- *
- * @param[in,out] mutex Pointer to the mutex to be destroyed.
- *
- * @return
- * - 0 on success.
- * - Non-zero error code on failure, including:
- * - `EBUSY`: The mutex is currently locked or being used by another thread.
- * - `EINVAL`: The mutex is invalid or has not been initialized.
- *
- * @note
- * Before calling this function, ensure that the mutex is not locked or in use
- * by any thread. Destroying a locked mutex results in undefined behavior.
- *
- * @warning
- * Attempting to destroy a mutex that is still in use can cause resource leaks
- * or undefined behavior.
- *
- * @see pthread_mutex_init, pthread_mutex_lock, pthread_mutex_unlock
- */
- int pthread_mutex_destroy(pthread_mutex_t *mutex)
- {
- if (!mutex || mutex->attr == -1)
- return EINVAL;
- /* it's busy */
- if (mutex->lock.owner != RT_NULL)
- return EBUSY;
- rt_memset(mutex, 0, sizeof(pthread_mutex_t));
- mutex->attr = -1;
- return 0;
- }
- RTM_EXPORT(pthread_mutex_destroy);
- /**
- * @brief Locks a mutex.
- *
- * This function locks the mutex object pointed to by `mutex`. If the mutex is
- * already locked by another thread, the calling thread will block until the
- * mutex becomes available.
- *
- * @param[in,out] mutex Pointer to the mutex to be locked.
- *
- * @return
- * - 0 on success.
- * - Non-zero error code on failure, including:
- * - `EDEADLK`: A deadlock condition was detected (e.g., the current thread
- * already holds the mutex in a recursive locking scenario).
- * - `EINVAL`: The mutex is invalid or uninitialized.
- *
- * @note
- * If the mutex is initialized with the `PTHREAD_MUTEX_RECURSIVE` attribute,
- * the same thread can lock the mutex multiple times without causing a deadlock.
- * However, the mutex must be unlocked an equal number of times before it
- * becomes available to other threads.
- *
- * @warning
- * Attempting to lock an uninitialized or already destroyed mutex results in
- * undefined behavior.
- *
- * @see pthread_mutex_unlock, pthread_mutex_trylock, pthread_mutex_init
- */
- int pthread_mutex_lock(pthread_mutex_t *mutex)
- {
- int mtype;
- rt_err_t result;
- if (!mutex)
- return EINVAL;
- if (mutex->attr == -1)
- {
- /* init mutex */
- pthread_mutex_init(mutex, RT_NULL);
- }
- mtype = mutex->attr & MUTEXATTR_TYPE_MASK;
- rt_enter_critical();
- if (mutex->lock.owner == rt_thread_self() &&
- mtype != PTHREAD_MUTEX_RECURSIVE)
- {
- rt_exit_critical();
- return EDEADLK;
- }
- rt_exit_critical();
- result = rt_mutex_take(&(mutex->lock), RT_WAITING_FOREVER);
- if (result == RT_EOK)
- return 0;
- return EINVAL;
- }
- RTM_EXPORT(pthread_mutex_lock);
- /**
- * @brief Unlocks a mutex.
- *
- * This function unlocks the mutex object pointed to by `mutex`. If other threads
- * are blocked waiting for the mutex, one of them will acquire the lock once it is
- * released. The calling thread must hold the lock on the mutex before calling
- * this function.
- *
- * @param[in,out] mutex Pointer to the mutex to be unlocked.
- *
- * @return
- * - 0 on success.
- * - Non-zero error code on failure, including:
- * - `EPERM`: The current thread does not hold the lock on the mutex.
- * - `EINVAL`: The mutex is invalid or uninitialized.
- *
- * @note
- * If the mutex was initialized with the `PTHREAD_MUTEX_RECURSIVE` attribute,
- * the mutex will only be unlocked after the calling thread unlocks it as many
- * times as it was locked.
- *
- * @warning
- * Attempting to unlock an uninitialized, destroyed, or unlocked mutex results
- * in undefined behavior.
- *
- * @see pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_init
- */
- int pthread_mutex_unlock(pthread_mutex_t *mutex)
- {
- rt_err_t result;
- if (!mutex)
- return EINVAL;
- if (mutex->attr == -1)
- {
- /* init mutex */
- pthread_mutex_init(mutex, RT_NULL);
- }
- if (mutex->lock.owner != rt_thread_self())
- {
- int mtype;
- mtype = mutex->attr & MUTEXATTR_TYPE_MASK;
- /* error check, return EPERM */
- if (mtype == PTHREAD_MUTEX_ERRORCHECK)
- return EPERM;
- /* no thread waiting on this mutex */
- if (mutex->lock.owner == RT_NULL)
- return 0;
- }
- result = rt_mutex_release(&(mutex->lock));
- if (result == RT_EOK)
- return 0;
- return EINVAL;
- }
- RTM_EXPORT(pthread_mutex_unlock);
- /**
- * @brief Attempts to lock a mutex without blocking.
- *
- * This function attempts to lock the mutex object pointed to by `mutex`. If the mutex
- * is already locked by another thread, the function returns immediately with an error
- * code instead of blocking.
- *
- * @param[in,out] mutex Pointer to the mutex to be locked.
- *
- * @return
- * - 0 on success (the mutex was successfully locked).
- * - Non-zero error code on failure, including:
- * - `EBUSY`: The mutex is already locked by another thread.
- * - `EINVAL`: The mutex is invalid or uninitialized.
- *
- * @note
- * This function is useful for implementing non-blocking mutex acquisition. If the mutex
- * was initialized with the `PTHREAD_MUTEX_RECURSIVE` attribute, the calling thread can
- * lock it multiple times, but must unlock it the same number of times.
- *
- * @warning
- * Attempting to trylock an uninitialized or destroyed mutex results in undefined behavior.
- *
- * @see pthread_mutex_lock, pthread_mutex_unlock, pthread_mutex_init
- */
- int pthread_mutex_trylock(pthread_mutex_t *mutex)
- {
- rt_err_t result;
- int mtype;
- if (!mutex)
- return EINVAL;
- if (mutex->attr == -1)
- {
- /* init mutex */
- pthread_mutex_init(mutex, RT_NULL);
- }
- mtype = mutex->attr & MUTEXATTR_TYPE_MASK;
- rt_enter_critical();
- if (mutex->lock.owner == rt_thread_self() &&
- mtype != PTHREAD_MUTEX_RECURSIVE)
- {
- rt_exit_critical();
- return EDEADLK;
- }
- rt_exit_critical();
- result = rt_mutex_take(&(mutex->lock), 0);
- if (result == RT_EOK) return 0;
- return EBUSY;
- }
- RTM_EXPORT(pthread_mutex_trylock);
- int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *prioceiling)
- {
- return EINVAL;
- }
- RTM_EXPORT(pthread_mutexattr_getprioceiling);
- int pthread_mutexattr_setprioceiling(const pthread_mutexattr_t *attr, int prioceiling)
- {
- return EINVAL;
- }
- RTM_EXPORT(pthread_mutexattr_setprioceiling);
- int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol)
- {
- return EINVAL;
- }
- RTM_EXPORT(pthread_mutexattr_getprotocol);
- int pthread_mutexattr_setprotocol(const pthread_mutexattr_t *attr, int protocol)
- {
- return EINVAL;
- }
- RTM_EXPORT(pthread_mutexattr_setprotocol);
- int pthread_mutex_getprioceiling(const pthread_mutex_t *mutex, int *prioceiling)
- {
- return pthread_mutexattr_getprioceiling(&mutex->attr, prioceiling);
- }
- RTM_EXPORT(pthread_mutex_getprioceiling);
- int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling, int *old_ceiling)
- {
- *old_ceiling = pthread_mutexattr_getprioceiling(&mutex->attr, old_ceiling);
- if(*old_ceiling != 0)
- {
- return EINVAL;
- }
- return pthread_mutexattr_setprioceiling(&mutex->attr, prioceiling);
- }
- RTM_EXPORT(pthread_mutex_setprioceiling);
|