/*
 * Copyright (C) 2000 TimeSys Corporation
 * Some code in this file is derived from LinuxThreads,
 *	which is Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)
 *
 * This is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 */

#define __RK__
#define TIMESYS
#include <rk/rk.h>

#include <pthread.h>
#include <bits/pthreadtypes.h>
#include <errno.h>

extern int errno;

void *thread_self();

int pthread_mutex_init(pthread_mutex_t *mutex, 
	const pthread_mutexattr_t *mutex_attr)
{
	int ret=__pthread_mutex_init(mutex, mutex_attr);
	if (ret)
		return ret;

	if (mutex_attr)
		mutex->__m_reserved=rt_mutex_create(mutex_attr->proto, mutex_attr->gid);
	else
		mutex->__m_reserved=rt_mutex_create(PTHREAD_PRIO_NONE, -1);

	if (mutex->__m_reserved==-1)
		mutex->__m_reserved=0;
	
	return 0;
}

int pthread_mutex_destroy(pthread_mutex_t *mutex)
{
  int ret = 0;

	if (mutex->__m_reserved)
	  {
	    do 
	      {
		errno = 0;
		ret = rt_mutex_destroy(mutex->__m_reserved);
	      }
	    while (errno == EINTR);
	  }
  
	__pthread_mutex_destroy(mutex);

	return ret;
}

int pthread_mutex_trylock(pthread_mutex_t *mutex)
{
	int retcode;

	if (!mutex->__m_reserved)
		return __pthread_mutex_trylock(mutex);

	switch(mutex->__m_kind) {
	case PTHREAD_MUTEX_FAST_NP:
	  do
	    {
	      errno = 0;
	      retcode=rt_mutex_trylock(mutex->__m_reserved);
	    } 
	  while (errno == EINTR);
		if (retcode != 0)
			return errno;
		return 0;

	case PTHREAD_MUTEX_RECURSIVE_NP:
		if ((pid_t)mutex->__m_owner == getpid()) {
			mutex->__m_count++;
			return 0;
		}
		do
		  {
		    errno = 0;
		    retcode=rt_mutex_trylock(mutex->__m_reserved);
		  }
		while (errno == EINTR);

		if (retcode!= 0)
			retcode=errno;
		else {
			mutex->__m_owner = (void*)getpid();
			mutex->__m_count = 0;
		}
		return retcode;

	case PTHREAD_MUTEX_ERRORCHECK_NP:
	       do
		 {
		   errno = 0;
		   retcode=rt_mutex_trylock(mutex->__m_reserved);
		 }
	       while(errno == EINTR);

		if (retcode!=0)
			retcode=errno;
		else 
			mutex->__m_owner = (void*)getpid();

		return retcode;

	default:
		return EINVAL;
	}
}

int pthread_mutex_lock(pthread_mutex_t *mutex)
{
  int retcode;
	if (!mutex->__m_reserved)
		return __pthread_mutex_lock(mutex);

	switch(mutex->__m_kind) {
	case PTHREAD_MUTEX_FAST_NP:
	  do
	    {
	      errno = 0;
	      retcode = rt_mutex_lock(mutex->__m_reserved);
	    }
	  while (errno == EINTR);
		return 0;

	case PTHREAD_MUTEX_RECURSIVE_NP:
		if ((pid_t)mutex->__m_owner == getpid()) {
			mutex->__m_count++;
			return 0;
		}

		do
		  {
		    errno  = 0;
		    retcode = rt_mutex_lock(mutex->__m_reserved);
		  }
		while (errno == EINTR);

		mutex->__m_owner = (void*)getpid();
		mutex->__m_count = 0;
		return 0;

	case PTHREAD_MUTEX_ERRORCHECK_NP:
		if ((pid_t)mutex->__m_owner == getpid()) 
			return EDEADLK;

		do
		  {
		    errno = 0;
		    retcode = rt_mutex_lock(mutex->__m_reserved);
		  }
		while (errno == EINTR);

		mutex->__m_owner = (void*)getpid();
		return 0;

	default:
		return EINVAL;
	}
}

int pthread_mutex_unlock(pthread_mutex_t *mutex)
{
  int retcode;
	if (!mutex->__m_reserved)
		return __pthread_mutex_unlock(mutex);

	switch (mutex->__m_kind) {
	case PTHREAD_MUTEX_FAST_NP:
	  do
	    {
	      errno = 0;
	      retcode = rt_mutex_unlock(mutex->__m_reserved);
	    }
	  while (errno == EINTR);

	  return retcode;

	case PTHREAD_MUTEX_RECURSIVE_NP:
		if (mutex->__m_count > 0) {
			mutex->__m_count--;
			return 0;
		}
		mutex->__m_owner = NULL;

		do 
		  {
		    errno = 0;
		    retcode = rt_mutex_unlock(mutex->__m_reserved);
		  }
		while (errno == EINTR);

		return retcode;
	case PTHREAD_MUTEX_ERRORCHECK_NP:
		mutex->__m_owner = NULL;

		do 
		  {
		    errno = 0;
		    retcode = rt_mutex_unlock(mutex->__m_reserved);
		  }
		while (errno == EINTR);

		return retcode;

	default:
		return EINVAL;
	}
}

int pthread_mutexattr_init(pthread_mutexattr_t *attr)
{
	int ret=__pthread_mutexattr_init(attr);
	if (ret)
		return ret;
		
	attr->proto = PTHREAD_PRIO_NONE;
	attr->gid = PTHREAD_PROCESS_PRIVATE;
	attr->ceiling = 0; /* Not currently used */
	return 0;
}

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

int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol)
{
	if (protocol != PTHREAD_PRIO_NONE && protocol != PTHREAD_PRIO_INHERIT)
		return EINVAL;
	attr->proto = protocol;
	return 0;
}

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

int pthread_mutexattr_setgid(pthread_mutexattr_t *attr, int gid)
{
	if (attr->gid>=-2)
		attr->gid = gid;
	else
		return EINVAL;
}

int pthread_mutexattr_getgid(pthread_mutexattr_t *attr, int *gid)
{
	*gid = attr->gid;
}

int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
{
	if (pshared==PTHREAD_PROCESS_PRIVATE || pshared==PTHREAD_PROCESS_SHARED)
		attr->gid = pshared;
	else
		return EINVAL;
}

int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared)
{
	if (attr->gid<0)
		*pshared = attr->gid;
	else
		*pshared = PTHREAD_PROCESS_PRIVATE;
}

