/*
* Copyright (C) Texas Instruments - http://www.ti.com/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Semaphore.h"
#include "ErrorUtils.h"
#include <utils/Log.h>
#include <time.h>
namespace android {
/**
@brief Constructor for the semaphore class
@param none
@return none
*/
Semaphore::Semaphore()
{
///Initialize the semaphore to NULL
mSemaphore = NULL;
}
/**
@brief Destructor of the semaphore class
@param none
@return none
*/
Semaphore::~Semaphore()
{
Release();
}
/**
@brief: Releases semaphore
@param count >=0
@return NO_ERROR On Success
@return One of the android error codes based on semaphore de-initialization
*/
status_t Semaphore::Release()
{
int status = 0;
///Destroy only if the semaphore has been created
if(mSemaphore)
{
status = sem_destroy(mSemaphore);
free(mSemaphore);
mSemaphore = NULL;
}
///Initialize the semaphore and return the status
return ErrorUtils::posixToAndroidError(status);
}
/**
@brief Create the semaphore with initial count value
@param count >=0
@return NO_ERROR On Success
@return NO_MEMORY If unable to allocate memory for the semaphore
@return BAD_VALUE If an invalid count value is passed (<0)
@return One of the android error codes based on semaphore initialization
*/
status_t Semaphore::Create(int count)
{
status_t ret = NO_ERROR;
///count cannot be less than zero
if(count<0)
{
return BAD_VALUE;
}
ret = Release();
if ( NO_ERROR != ret )
{
return ret;
}
///allocate memory for the semaphore
mSemaphore = (sem_t*)malloc(sizeof(sem_t)) ;
///if memory is unavailable, return error
if(!mSemaphore)
{
return NO_MEMORY;
}
///Initialize the semaphore and return the status
return ErrorUtils::posixToAndroidError(sem_init(mSemaphore, 0x00, count));
}
/**
@brief Wait operation
@param none
@return BAD_VALUE if the semaphore is not initialized
@return NO_ERROR On success
@return One of the android error codes based on semaphore wait operation
*/
status_t Semaphore::Wait()
{
///semaphore should have been created first
if(!mSemaphore)
{
return BAD_VALUE;
}
///Wait and return the status after signalling
return ErrorUtils::posixToAndroidError(sem_wait(mSemaphore));
}
/**
@brief Signal operation
@param none
@return BAD_VALUE if the semaphore is not initialized
@return NO_ERROR On success
@return One of the android error codes based on semaphore signal operation
*/
status_t Semaphore::Signal()
{
///semaphore should have been created first
if(!mSemaphore)
{
return BAD_VALUE;
}
///Post to the semaphore
return ErrorUtils::posixToAndroidError(sem_post(mSemaphore));
}
/**
@brief Current semaphore count
@param none
@return Current count value of the semaphore
*/
int Semaphore::Count()
{
int val;
///semaphore should have been created first
if(!mSemaphore)
{
return BAD_VALUE;
}
///get the value of the semaphore
sem_getvalue(mSemaphore, &val);
return val;
}
/**
@brief Wait operation with a timeout
@param timeoutMicroSecs The timeout period in micro seconds
@return BAD_VALUE if the semaphore is not initialized
@return NO_ERROR On success
@return One of the android error codes based on semaphore wait operation
*/
status_t Semaphore::WaitTimeout(int timeoutMicroSecs)
{
status_t ret = NO_ERROR;
struct timespec timeSpec;
struct timeval currentTime;
///semaphore should have been created first
if( NULL == mSemaphore)
{
ret = BAD_VALUE;
}
if ( NO_ERROR == ret )
{
///setup the timeout values - timeout is specified in seconds and nanoseconds
gettimeofday(¤tTime, NULL);
timeSpec.tv_sec = currentTime.tv_sec;
timeSpec.tv_nsec = currentTime.tv_usec * 1000;
timeSpec.tv_sec += ( timeoutMicroSecs / 1000000 );
timeSpec.tv_nsec += ( timeoutMicroSecs % 1000000) * 1000;
///Wait for the timeout or signal and return the result based on whichever event occurred first
ret = sem_timedwait(mSemaphore, &timeSpec);
}
if ( NO_ERROR != ret )
{
Signal();
Create(0);
}
return ret;
}
};