/* * 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 */ #include #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_FIFO); 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);