rt-thread/components/pthreads/pthread_mutex.c

196 lines
4.0 KiB
C

#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;
}
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
{
if (attr)
{
*attr = -1;
return 0;
}
return EINVAL;
}
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;
}
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;
}
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;
}
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;
}
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_FIFO);
if (result != RT_EOK) return EINVAL;
/* detach the object from system object container */
rt_object_detach(&(mutex->lock.parent.parent));
return 0;
}
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;
}
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;
}
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;
}
int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
rt_err_t result;
if (!mutex) return EINVAL;
if (mutex->attr == -1)
{
/* init mutex */
pthread_mutex_init(mutex, RT_NULL);
}
result = rt_mutex_take(&(mutex->lock), 0);
if (result == RT_EOK) return 0;
return EBUSY;
}