/*******************************************************************************
 *	BSema.cc	BSema Classes
 *			T.Barnaby,	BEAM Ltd,	6/11/02
 *	updated by	D.Korchagin,	CERN AB-BI-SW,	2007-08-31
 *******************************************************************************
 */

#include <BSema.h>
#include <errno.h>
#include <sys/time.h>

BSema::BSema(int value){
	sem_init(&osema, 0, value);
}

BSema::BSema(const BSema& sema){
	sem_init(&osema, 0, sema.getValue());
}

BSema& BSema::operator=(const BSema& sema){
	sem_destroy(&osema);
	sem_init(&osema, 0, sema.getValue());
	return *this;
}

BSema::~BSema(){
	sem_destroy(&osema);
}

int BSema::post(){
	return sem_post(&osema);
}

int BSema::wait(){
	int	r;
	
	while(1){
		r = sem_wait(&osema);
		if(r >= 0)
			break;
		else if((r < 0) && (errno != EINTR))
			break;
	}
	
	return r;
}

int BSema::timedWait(int timeOutUs){
	struct timeval	tv;
	struct timespec	ts;
	
	gettimeofday(&tv, 0);
	ts.tv_sec = tv.tv_sec + timeOutUs / 1000000;
	ts.tv_nsec = (tv.tv_usec + timeOutUs % 1000000) * 1000;
	ts.tv_sec += (ts.tv_nsec / 1000000000);
	ts.tv_nsec %=  1000000000;
	
#ifndef __Lynx__
	return sem_timedwait(&osema, &ts);
#else
#ifdef HAVE_SEM_TIMEDWAIT
	// LynxOS 4.2 new features - support has been added for two routines from POSIX 1003.1-2001, sem_timedwait() and pthread_mutex_timedlock(), etc.
	return sem_timedwait(&osema, &ts);
#else
	// sem_timedwait() is not available for LynxOS 4.0 or previous versions - use sem_wait() instead.
	return sem_wait(&osema);
#endif
#endif
}

int BSema::tryWait(){
	return sem_trywait(&osema);
}

int BSema::getValue() const {
	int	v;
	
	sem_getvalue((sem_t*)&osema, &v);
	return v;
}
