zephyr/lib/posix/pthread_mutex.c
Andy Ross f4b6daff4b lib/posix: Port wait_q usage to new API
The pthread mutex changes went in with an adaptation to build with the
new wait queue API, but they did it by using the old dlist hooks
directly through typecasting and union assignment.  That... is sort of
the opposite of the intent to having the new API be abstracted.  The
pthread code worked, but failed once wait queues (on x86) stopped
being dlists.

Simple fix once I saw the problem, anyway.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2018-05-19 07:00:55 +03:00

205 lines
3.3 KiB
C

/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <ksched.h>
#include <wait_q.h>
#include <posix/pthread.h>
#define MUTEX_MAX_REC_LOCK 32767
/*
* Default mutex attrs.
*/
static const pthread_mutexattr_t def_attr = {
.type = PTHREAD_MUTEX_DEFAULT,
};
static int acquire_mutex(pthread_mutex_t *m, int timeout)
{
int rc = 0, key = irq_lock();
if (m->lock_count == 0 && m->owner == NULL) {
m->lock_count++;
m->owner = pthread_self();
irq_unlock(key);
return 0;
} else if (m->owner == pthread_self()) {
if (m->type == PTHREAD_MUTEX_RECURSIVE &&
m->lock_count < MUTEX_MAX_REC_LOCK) {
m->lock_count++;
rc = 0;
} else if (m->type == PTHREAD_MUTEX_ERRORCHECK) {
rc = EDEADLK;
} else {
rc = EINVAL;
}
irq_unlock(key);
return rc;
}
if (timeout == K_NO_WAIT) {
irq_unlock(key);
return EINVAL;
}
rc = _pend_current_thread(key, &m->wait_q, timeout);
if (rc != 0) {
rc = ETIMEDOUT;
}
return rc;
}
/**
* @brief Lock POSIX mutex with non-blocking call.
*
* See IEEE 1003.1
*/
int pthread_mutex_trylock(pthread_mutex_t *m)
{
return acquire_mutex(m, K_NO_WAIT);
}
/**
* @brief Lock POSIX mutex with timeout.
*
*
* See IEEE 1003.1
*/
int pthread_mutex_timedlock(pthread_mutex_t *m,
const struct timespec *to)
{
return acquire_mutex(m, _ts_to_ms(to));
}
/**
* @brief Intialize POSIX mutex.
*
* See IEEE 1003.1
*/
int pthread_mutex_init(pthread_mutex_t *m,
const pthread_mutexattr_t *attr)
{
const pthread_mutexattr_t *mattr;
m->owner = NULL;
m->lock_count = 0;
mattr = (attr == NULL) ? &def_attr : attr;
m->type = mattr->type;
_waitq_init(&m->wait_q);
return 0;
}
/**
* @brief Lock POSIX mutex with blocking call.
*
* See IEEE 1003.1
*/
int pthread_mutex_lock(pthread_mutex_t *m)
{
return acquire_mutex(m, K_FOREVER);
}
/**
* @brief Unlock POSIX mutex.
*
* See IEEE 1003.1
*/
int pthread_mutex_unlock(pthread_mutex_t *m)
{
unsigned int key = irq_lock();
k_tid_t thread;
if (m->owner != pthread_self()) {
irq_unlock(key);
return EPERM;
}
if (m->lock_count == 0) {
irq_unlock(key);
return EINVAL;
}
m->lock_count--;
if (m->lock_count == 0) {
thread = _unpend_first_thread(&m->wait_q);
if (thread) {
m->owner = (pthread_t)thread;
m->lock_count++;
_ready_thread(thread);
_set_thread_return_value(thread, 0);
return _reschedule(key);
}
m->owner = NULL;
}
irq_unlock(key);
return 0;
}
/**
* @brief Destroy POSIX mutex.
*
* See IEEE 1003.1
*/
int pthread_mutex_destroy(pthread_mutex_t *m)
{
ARG_UNUSED(m);
return 0;
}
/**
* @brief Read protocol attribute for mutex.
*
* See IEEE 1003.1
*/
int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr,
int *protocol)
{
*protocol = PTHREAD_PRIO_NONE;
return 0;
}
/**
* @brief Read type attribute for mutex.
*
* See IEEE 1003.1
*/
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
{
*type = attr->type;
return 0;
}
/**
* @brief Set type attribute for mutex.
*
* See IEEE 1003.1
*/
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
{
int retc = EINVAL;
if ((type == PTHREAD_MUTEX_NORMAL) ||
(type == PTHREAD_MUTEX_RECURSIVE) ||
(type == PTHREAD_MUTEX_ERRORCHECK)) {
attr->type = type;
retc = 0;
}
return retc;
}