/*
 * RTLinux mutex implementation
 *
 * Written by Michael Barabanov
 * Copyright (C) Finite State Machine Labs Inc., 1999
 * Released under the terms of the GPL Version 2
 *
 */

#ifndef __RTL_MUTEX_H__
#define __RTL_MUTEX_H__

#ifdef __KERNEL__

#include <rtl_conf.h>
#include <errno.h>
#include <rtl_spinlock.h>
#include <rtl_wait.h>

enum { PTHREAD_MUTEX_NORMAL, PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK,
	PTHREAD_MUTEX_SPINLOCK_NP, PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL };

typedef struct {
	int type;
	int pshared;
	int protocol;
	int prioceiling;
} pthread_mutexattr_t;

#define PTHREAD_PROCESS_PRIVATE 0
#define PTHREAD_PROCESS_SHARED 1

typedef struct {
	rtl_irqstate_t flags;
	int busy;
	int valid;
	spinlock_t lock;
	int type;
	rtl_wait_t wait;
	int protocol;
	int prioceiling;
	int oldprio;
} pthread_mutex_t;


#define PTHREAD_MUTEX_INITIALIZER { 0,0,1, SPIN_LOCK_UNLOCKED, PTHREAD_MUTEX_DEFAULT, RTL_WAIT_INITIALIZER, PTHREAD_PRIO_NONE }

enum {PTHREAD_PRIO_NONE, PTHREAD_PRIO_PROTECT};


static inline int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
{
	if (type != PTHREAD_MUTEX_NORMAL
			&& attr->type != PTHREAD_MUTEX_SPINLOCK_NP) {
		return EINVAL;
	}
	attr->type = type;
	return 0;
}



static inline int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr,
		    int *pshared)
{
	*pshared = attr->pshared;
	return 0;
}

/*TODO something sensible with this. We don't worry about
  shared and not shared yet.
  */
extern inline int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,
		    int pshared)
{
	if (pshared != PTHREAD_PROCESS_SHARED
			&& pshared != PTHREAD_PROCESS_PRIVATE) {
		return EINVAL;
	}
	attr->pshared = pshared;
	return 0;
}


extern int pthread_mutexattr_init(pthread_mutexattr_t *attr);

extern inline int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
{
	return 0;
}

extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);

extern inline int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
{
	*type = attr->type;
	return 0;
}


extern int pthread_mutex_init(pthread_mutex_t *mutex,
		    const pthread_mutexattr_t *attr);
extern inline int pthread_mutex_destroy(pthread_mutex_t *mutex);

extern int pthread_mutex_lock(pthread_mutex_t *mutex);
extern int pthread_mutex_trylock(pthread_mutex_t *mutex);
extern int pthread_mutex_unlock(pthread_mutex_t *mutex);

/* not supported for spinlock mutexes */
extern int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime);

static inline int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol)
{
#ifndef _RTL_POSIX_THREAD_PRIO_PROTECT
		return ENOTSUP;
#endif
	if (protocol != PTHREAD_PRIO_PROTECT && protocol != PTHREAD_PRIO_NONE) {
		return ENOTSUP;
	}
	attr->protocol = protocol;
	return 0;
}

static inline int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol)
{
	*protocol = attr->protocol;
	return 0;
}

static inline int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
{
	attr->prioceiling = prioceiling;
	return 0;
}

static inline int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *prioceiling)
{
	*prioceiling = attr->prioceiling;
	return 0;
}


extern int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling, int *old_ceiling);

static inline int pthread_mutex_getprioceiling(const pthread_mutex_t *mutex, int *prioceiling)
{
	*prioceiling = mutex->prioceiling;
	return 0;
}




#endif

#endif // __RTL_MUTEX_H__
