291 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			291 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /*
 | |
|  * Copyright (c) 2006-2021, 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;
 | |
| 
 | |
| int pthread_mutexattr_init(pthread_mutexattr_t *attr)
 | |
| {
 | |
|     if (attr)
 | |
|     {
 | |
|         *attr = pthread_default_mutexattr;
 | |
| 
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     return EINVAL;
 | |
| }
 | |
| RTM_EXPORT(pthread_mutexattr_init);
 | |
| 
 | |
| int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
 | |
| {
 | |
|     if (attr)
 | |
|     {
 | |
|         *attr = -1;
 | |
| 
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     return EINVAL;
 | |
| }
 | |
| RTM_EXPORT(pthread_mutexattr_destroy);
 | |
| 
 | |
| 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);
 | |
| 
 | |
| 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);
 | |
| 
 | |
| 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);
 | |
| 
 | |
| 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);
 | |
| 
 | |
| 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);
 | |
| 
 | |
| 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);
 | |
| 
 | |
| 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);
 | |
| 
 | |
| 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);
 | |
| 
 | |
| 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);
 |