2013-06-26 23:18:30 +08:00
|
|
|
/*
|
|
|
|
* File : pthread_mutex.c
|
|
|
|
* This file is part of RT-Thread RTOS
|
|
|
|
* COPYRIGHT (C) 2006 - 2010, RT-Thread Development Team
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*
|
|
|
|
* Change Logs:
|
|
|
|
* Date Author Notes
|
|
|
|
* 2010-10-26 Bernard the first version
|
|
|
|
*/
|
|
|
|
|
2013-01-08 22:40:58 +08:00
|
|
|
#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)
|
|
|
|
{
|
2013-06-26 23:18:30 +08:00
|
|
|
if (attr)
|
|
|
|
{
|
|
|
|
*attr = pthread_default_mutexattr;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINVAL;
|
2013-01-08 22:40:58 +08:00
|
|
|
}
|
|
|
|
RTM_EXPORT(pthread_mutexattr_init);
|
|
|
|
|
|
|
|
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
|
|
|
|
{
|
2013-06-26 23:18:30 +08:00
|
|
|
if (attr)
|
|
|
|
{
|
|
|
|
*attr = -1;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINVAL;
|
2013-01-08 22:40:58 +08:00
|
|
|
}
|
|
|
|
RTM_EXPORT(pthread_mutexattr_destroy);
|
|
|
|
|
|
|
|
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
|
|
|
|
{
|
2013-06-26 23:18:30 +08:00
|
|
|
if (attr && type)
|
|
|
|
{
|
2013-01-08 22:40:58 +08:00
|
|
|
int atype = (*attr & MUTEXATTR_TYPE_MASK);
|
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
if (atype >= PTHREAD_MUTEX_NORMAL && atype <= PTHREAD_MUTEX_ERRORCHECK)
|
|
|
|
{
|
|
|
|
*type = atype;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINVAL;
|
2013-01-08 22:40:58 +08:00
|
|
|
}
|
|
|
|
RTM_EXPORT(pthread_mutexattr_gettype);
|
|
|
|
|
|
|
|
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
|
|
|
|
{
|
2013-06-26 23:18:30 +08:00
|
|
|
if (attr && type >= PTHREAD_MUTEX_NORMAL && type <= PTHREAD_MUTEX_ERRORCHECK)
|
|
|
|
{
|
2013-01-08 22:40:58 +08:00
|
|
|
*attr = (*attr & ~MUTEXATTR_TYPE_MASK) | type;
|
2013-06-26 23:18:30 +08:00
|
|
|
|
2013-01-08 22:40:58 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
RTM_EXPORT(pthread_mutexattr_settype);
|
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
|
2013-01-08 22:40:58 +08:00
|
|
|
{
|
2013-06-26 23:18:30 +08:00
|
|
|
if (!attr)
|
|
|
|
return EINVAL;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
|
|
|
switch (pshared)
|
2013-06-26 23:18:30 +08:00
|
|
|
{
|
2013-01-08 22:40:58 +08:00
|
|
|
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)
|
|
|
|
{
|
2013-06-26 23:18:30 +08:00
|
|
|
if (!attr || !pshared)
|
|
|
|
return EINVAL;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
|
|
|
*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)
|
|
|
|
{
|
2013-06-26 23:18:30 +08:00
|
|
|
rt_err_t result;
|
|
|
|
char name[RT_NAME_MAX];
|
|
|
|
static rt_uint16_t pthread_mutex_number = 0;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
if (!mutex)
|
|
|
|
return EINVAL;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
/* 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;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
/* init mutex lock */
|
|
|
|
result = rt_mutex_init(&(mutex->lock), name, RT_IPC_FLAG_FIFO);
|
|
|
|
if (result != RT_EOK)
|
|
|
|
return EINVAL;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
/* detach the object from system object container */
|
|
|
|
rt_object_detach(&(mutex->lock.parent.parent));
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
return 0;
|
2013-01-08 22:40:58 +08:00
|
|
|
}
|
|
|
|
RTM_EXPORT(pthread_mutex_init);
|
|
|
|
|
|
|
|
int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
|
|
|
{
|
2013-06-26 23:18:30 +08:00
|
|
|
if (!mutex || mutex->attr == -1)
|
|
|
|
return EINVAL;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
/* it's busy */
|
|
|
|
if (mutex->lock.owner != RT_NULL)
|
|
|
|
return EBUSY;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
rt_memset(mutex, 0, sizeof(pthread_mutex_t));
|
|
|
|
mutex->attr = -1;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
return 0;
|
2013-01-08 22:40:58 +08:00
|
|
|
}
|
|
|
|
RTM_EXPORT(pthread_mutex_destroy);
|
|
|
|
|
|
|
|
int pthread_mutex_lock(pthread_mutex_t *mutex)
|
|
|
|
{
|
2013-06-26 23:18:30 +08:00
|
|
|
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;
|
2013-01-08 22:40:58 +08:00
|
|
|
}
|
|
|
|
RTM_EXPORT(pthread_mutex_lock);
|
|
|
|
|
|
|
|
int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
|
|
|
{
|
2013-06-26 23:18:30 +08:00
|
|
|
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;
|
2013-01-08 22:40:58 +08:00
|
|
|
}
|
|
|
|
RTM_EXPORT(pthread_mutex_unlock);
|
|
|
|
|
|
|
|
int pthread_mutex_trylock(pthread_mutex_t *mutex)
|
|
|
|
{
|
2013-06-26 23:18:30 +08:00
|
|
|
rt_err_t result;
|
2016-11-03 15:38:51 +08:00
|
|
|
int mtype;
|
2013-06-26 23:18:30 +08:00
|
|
|
|
|
|
|
if (!mutex)
|
|
|
|
return EINVAL;
|
|
|
|
if (mutex->attr == -1)
|
|
|
|
{
|
|
|
|
/* init mutex */
|
|
|
|
pthread_mutex_init(mutex, RT_NULL);
|
|
|
|
}
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2016-11-03 15:38:51 +08:00
|
|
|
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();
|
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
result = rt_mutex_take(&(mutex->lock), 0);
|
2016-11-03 15:38:51 +08:00
|
|
|
if (result == RT_EOK) return 0;
|
2013-01-08 22:40:58 +08:00
|
|
|
|
2013-06-26 23:18:30 +08:00
|
|
|
return EBUSY;
|
2013-01-08 22:40:58 +08:00
|
|
|
}
|
|
|
|
RTM_EXPORT(pthread_mutex_trylock);
|