/* Copyright (c) 2000 Sinby.com
   All Rights Reserved

   This project is covered by the GNU General Public License. */

/* $Id: lock-impl.h,v 1.1.1.1 2000/12/22 07:22:06 ryos Exp $ */

#ifndef __ecos_native_lock_impl_h
#define __ecos_native_lock_impl_h

#define THREAD_SYSTEM_HAS_KSEM

typedef struct Ksem {
	cyg_mutex_t	mux;
	cyg_cond_t	cv;
	int			count;
} Ksem;

static inline void
ksemInit(Ksem* sem)
{
	assert(sem);
	
	cyg_mutex_init(&(sem->mux));
	cyg_cond_init(&(sem->cv),&(sem->mux));
	sem->count = 0;
}

static inline jboolean
ksemGet(Ksem* sem, jlong timeout)
{
	jboolean r;

	assert(sem);
	
	r = true;

	cyg_mutex_lock(&sem->mux);
	/* If no stored wakeups, then sleep. */
	if (sem->count == 0) {
#define ___NOTIMEOUT		0
		if ( timeout == ___NOTIMEOUT ) {
			cyg_cond_wait(&(sem->cv));
		} else {
			cyg_uint64 timelimit;
			timelimit = cyg_current_time() + (timeout/10);
			cyg_cond_timed_wait(&(sem->cv),timelimit);
		}
	}

	/* Use a stored wakeup if available. */
	if (sem->count == 1) {
		sem->count = 0;
		r = true;
	}
	else {
		/* Still no stored wakeup means we waited and timedout. */
		r = false;
	}
	assert(sem->count == 0);
	cyg_mutex_unlock(&sem->mux);
	return (r);
}

/*
 * Store a wakeup in the semaphore.  Wakeup one thread blocked
 * on the cv (if any).
 */
static inline void
ksemPut(Ksem* sem)
{
	cyg_mutex_lock(&sem->mux);
	/*assert((sem->count == 0) || (sem->count == 1));*/
	assert(sem->count == 0);
        sem->count = 1;
	cyg_cond_signal(&sem->cv);
	cyg_mutex_unlock(&sem->mux);
}

static inline void
ksemDestroy(Ksem* sem)
{
	assert(sem);
	cyg_mutex_destroy(&(sem->mux));
	cyg_cond_destroy(&(sem->cv));
}

#endif /* __ecos_native_lock_impl_h */
