/******************************************************************************
*
* Copyright (C) 2018 The Android Open Source Project
*
* 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.
*
*****************************************************************************
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
/*****************************************************************************/
/* */
/* File Name : osal_thread.c */
/* */
/* Description : This file contains Thread API's implemented for */
/* different platforms. */
/* */
/* List of Functions : osal_thread_create */
/* osal_thread_destroy */
/* osal_func */
/* osal_set_thread_priority */
/* osal_set_thread_core_affinity */
/* osal_thread_sleep */
/* osal_thread_yield */
/* osal_thread_suspend */
/* osal_thread_resume */
/* osal_thread_wait */
/* osal_get_thread_handle */
/* osal_get_time */
/* osal_get_time_usec */
/* osal_get_last_error */
/* osal_print_last_error */
/* */
/* Issues / Problems : None */
/* */
/* Revision History : */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 06 03 2006 Ittiam Draft */
/* */
/*****************************************************************************/
/*****************************************************************************/
/* File Includes */
/*****************************************************************************/
/* System include files */
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <math.h>
#include <sched.h> /*for CPU_SET, etc.. */
#include <linux/unistd.h>
#include <sys/syscall.h>
/* User include files */
#include "cast_types.h"
#include "osal.h"
#include "osal_handle.h"
#include "osal_thread.h"
#include "osal_errno.h"
/*****************************************************************************/
/* Static Function Declarations */
/*****************************************************************************/
static void osal_func(void *param);
/*****************************************************************************/
/* */
/* Function Name : osal_thread_create */
/* */
/* Description : This function create a new thread. */
/* */
/* Inputs : OSAL handle */
/* Memory Manager Handle */
/* Thread creation attributes */
/* */
/* Globals : None */
/* */
/* Processing : This function calls OS specific thread create API's and */
/* creates a new thread with specified attributes. */
/* */
/* Outputs : Status of thread creation */
/* */
/* Returns : On SUCCESS - 0 */
/* On FAILURE - -1 */
/* */
/* Issues : Only supports creating threads with default attributes */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 06 03 2006 Ittiam Draft */
/* */
/*****************************************************************************/
void *osal_thread_create(IN void *osal_handle, IN osal_thread_attr_t *attr)
{
osal_t *handle = (osal_t *)osal_handle;
WORD32 priority = 0;
void *mmr_handle = 0;
/* If Handle or attributes are not valid, return ERRORED. */
if(0 == attr)
return 0;
if(0 == handle || 0 == handle->alloc || 0 == handle->free)
return 0;
/* Initialize MMR handle */
mmr_handle = handle->mmr_handle;
{
pthread_attr_t tattr;
thread_handle_t *hdl = 0;
attr->sched_policy = OSAL_SCHED_RR;
/* Allocate memory for thread handle */
hdl = handle->alloc(mmr_handle, sizeof(thread_handle_t));
if(0 == hdl)
return 0;
/* Initialize thread handle parameters */
hdl->mmr_handle = mmr_handle;
hdl->hdl = handle;
hdl->exit_code = attr->exit_code;
hdl->priority = priority;
hdl->thread_func = attr->thread_func;
hdl->thread_param = attr->thread_param;
/* initialized with default attributes */
if(0 != pthread_attr_init(&tattr))
{
handle->free(hdl->mmr_handle, hdl);
return 0;
}
/* Create the thread */
hdl->thread_id = pthread_create(
&(hdl->thread_handle), /* Thread Handle */
&tattr, /* Attributes */
(void *(*)(void *))osal_func,
hdl); /* Parameters */
/* In case of error in thread creationn, Free the handle memory and */
/* return error. */
if(0 != hdl->thread_id)
{
handle->free(hdl->mmr_handle, hdl);
return 0;
}
pthread_attr_destroy(&tattr);
return hdl;
}
}
/*****************************************************************************/
/* */
/* Function Name : osal_thread_destroy */
/* */
/* Description : This function calls OS specific API's to close a thread */
/* which is represented by specified handle. */
/* */
/* Inputs : Initialized thread handle */
/* */
/* Globals : None */
/* */
/* Processing : Closing other threads is supported only in windows. So, */
/* only windows platform supports this API. */
/* */
/* Outputs : Status of thread close */
/* */
/* Returns : On SUCCESS - 0 */
/* On FAILURE - -1 */
/* */
/* Issues : None */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 06 03 2006 Ittiam Draft */
/* */
/*****************************************************************************/
WORD32 osal_thread_destroy(IN void *thread_handle)
{
/* If thread handle is not valid, return error */
if(0 == thread_handle)
return OSAL_ERROR;
{
thread_handle_t *hdl = (thread_handle_t *)thread_handle;
/* Free memory allocated for Thread handle */
((osal_t *)hdl->hdl)->free(hdl->mmr_handle, hdl);
return OSAL_SUCCESS;
}
}
/*****************************************************************************/
/* */
/* Function Name : osal_func */
/* */
/* Description : This function calls the registered threads calling */
/* function */
/* */
/* Inputs : Thread Handle */
/* */
/* Globals : None */
/* */
/* Processing : Calls each registered thread function */
/* */
/* Outputs : None */
/* Returns : None */
/* */
/* Issues : None */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 10 05 2006 Ittiam Draft */
/* */
/*****************************************************************************/
void osal_func(IN void *param)
{
thread_handle_t *hdl = (thread_handle_t *)param;
while(1)
{
/* Untill thread returns exit code, invoke the thread function */
if(hdl->exit_code == hdl->thread_func(hdl->thread_param))
break;
}
/* On Linux platforms call pthread_exit() to release all the resources */
/* allocated. */
pthread_exit(NULL);
}
/*****************************************************************************/
/* */
/* Function Name : osal_thread_sleep */
/* */
/* Description : This function calls OS specific API and makes thread */
/* sleep for specified number of milli seconds. */
/* */
/* Inputs : Initialized thread handle */
/* Time to sleep in millisceonds */
/* */
/* Globals : None */
/* */
/* Processing : Calls API to sleep for specified number of milli seconds */
/* */
/* Outputs : Status of sleep */
/* */
/* Returns : On SUCCESS - 0 */
/* On FAILURE - -1 */
/* */
/* Issues : None */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 06 03 2006 Ittiam Draft */
/* */
/*****************************************************************************/
WORD32 osal_thread_sleep(IN UWORD32 milli_seconds)
{
{
struct timespec timer;
/* Convert time in milliseconds into seconds and nano seconds */
timer.tv_sec = milli_seconds / 1000;
milli_seconds -= (timer.tv_sec * 1000);
timer.tv_nsec = milli_seconds * MEGA_CONST;
/* Using Monotonic clock to sleep, also flag is set to 0 for relative */
/* time to current clock time */
if(0 == clock_nanosleep(CLOCK_MONOTONIC, 0, &timer, NULL))
{
return OSAL_SUCCESS;
}
return OSAL_ERROR;
}
}
/*****************************************************************************/
/* */
/* Function Name : osal_thread_yield */
/* */
/* Description : This function causes the yield its execution. */
/* */
/* Inputs : Thread Handle */
/* */
/* Globals : None */
/* */
/* Processing : Calls OS specific yield calls. */
/* */
/* Outputs : Status of Thread Yield */
/* */
/* Returns : On SUCCESS - 0 */
/* On FAILURE - -1 */
/* */
/* Issues : Yield in WIN32 (whihc is a 16 - bit API) is still present*/
/* only to maintian backward compatibility. Can get */
/* deprecated in future. */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 06 03 2006 Ittiam Draft */
/* */
/*****************************************************************************/
WORD32 osal_thread_yield()
{
if(0 == sched_yield())
return OSAL_SUCCESS;
return OSAL_ERROR;
}
/*****************************************************************************/
/* */
/* Function Name : osal_thread_suspend */
/* */
/* Description : This function causes the suspension its execution. */
/* */
/* Inputs : Thread Handle */
/* */
/* Globals : None */
/* */
/* Processing : Calls OS specific suspend calls. */
/* */
/* Outputs : Status of Thread Suspend */
/* */
/* Returns : On SUCCESS - 0 */
/* On FAILURE - -1 */
/* */
/* Issues : API not supported in Redhat Linux. Refer Redhat */
/* documentation in: */
/* http://www.redhat.com/docs/wp/solaris_port/c1347.html */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 30 03 2006 Ittiam Draft */
/* */
/*****************************************************************************/
WORD32 osal_thread_suspend(IN void *thread_handle)
{
/* If thread handle is not valid, return error */
if(0 == thread_handle)
return OSAL_ERROR;
{
/* Thread suspend are not supported in Redhat Linux. Refer link */
/* http://www.redhat.com/docs/wp/solaris_port/c1347.html */
return OSAL_NOT_SUPPORTED;
}
}
/*****************************************************************************/
/* */
/* Function Name : osal_thread_resume */
/* */
/* Description : This function causes the resumption its execution. */
/* */
/* Inputs : Thread Handle */
/* */
/* Globals : None */
/* */
/* Processing : Calls OS specific resume calls. */
/* */
/* Outputs : Status of Thread Suspend */
/* */
/* Returns : On SUCCESS - 0 */
/* On FAILURE - -1 */
/* */
/* Issues : API not supported in Redhat Linux. Refer Redhat */
/* documentation in: */
/* http://www.redhat.com/docs/wp/solaris_port/c1347.html */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 30 03 2006 Ittiam Draft */
/* */
/*****************************************************************************/
WORD32 osal_thread_resume(IN void *thread_handle)
{
/* If thread handle is not valid, return error */
if(0 == thread_handle)
return OSAL_ERROR;
{
/* Thread suspend are not supported in Redhat Linux. Refer link */
/* http://www.redhat.com/docs/wp/solaris_port/c1347.html */
return OSAL_NOT_SUPPORTED;
}
}
/*****************************************************************************/
/* */
/* Function Name : osal_thread_wait */
/* */
/* Description : This function causes the wait untill called thread */
/* finishes execution */
/* */
/* Inputs : Thread Handle */
/* */
/* Globals : None */
/* */
/* Processing : Calls OS specific wait call for wait on another thread */
/* */
/* Outputs : Status of Thread wait */
/* */
/* Returns : On SUCCESS - 0 */
/* On FAILURE - -1 */
/* */
/* Issues : None */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 30 03 2006 Ittiam Draft */
/* */
/*****************************************************************************/
WORD32 osal_thread_wait(IN void *thread_handle)
{
if(0 == thread_handle)
return OSAL_ERROR;
{
WORD32 result = 0;
void *status = 0;
thread_handle_t *hdl = (thread_handle_t *)thread_handle;
/* Join the thread to wait for thread to complete execution */
result = pthread_join(hdl->thread_handle, (void **)&status);
return result;
}
}
/*****************************************************************************/
/* */
/* Function Name : osal_get_thread_handle */
/* */
/* Description : This function gets current thread handle. Currently not */
/* supported */
/* */
/* Inputs : OSAL handle. */
/* */
/* Globals : None */
/* */
/* Processing : Gets all the thread properities and constructs a new */
/* thread handle . */
/* */
/* Outputs : Thread handle to current thread. */
/* */
/* Returns : On SUCCESS - Current thread handle */
/* On FAILURE - NULL */
/* */
/* Issues : Not supported on Linux and BIOS platforms. */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 10 05 2006 Ittiam Draft */
/* */
/*****************************************************************************/
void *osal_get_thread_handle(IN void *osal_handle)
{
osal_t *handle = (osal_t *)osal_handle;
if(0 == osal_handle)
return 0;
{
thread_handle_t *hdl = handle->alloc(handle->mmr_handle, sizeof(thread_handle_t));
WORD32 schedpolicy;
struct sched_param schedparam;
if(0 == hdl)
return 0;
hdl->mmr_handle = handle->mmr_handle;
hdl->hdl = handle;
hdl->exit_code = 0;
hdl->thread_func = 0;
hdl->thread_param = 0;
hdl->thread_handle = pthread_self();
hdl->thread_id = 0;
hdl->priority = schedparam.sched_priority;
/* Get thread priority from scheduling parameters */
if(0 != pthread_getschedparam(hdl->thread_handle, &schedpolicy, &schedparam))
{
return 0;
}
return hdl;
}
}
/*****************************************************************************/
/* */
/* Function Name : osal_get_time */
/* */
/* Description : This function returns absolute time in milli seconds */
/* */
/* Inputs : None */
/* Globals : None */
/* */
/* Processing : Gets the absolute time by calling OS specific API's. */
/* */
/* Outputs : Absolute time in milli seconds. */
/* */
/* Returns : +ve 32 bit value */
/* */
/* Issues : None */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 06 03 2006 Ittiam Draft */
/* */
/*****************************************************************************/
UWORD32 osal_get_time()
{
{
struct timespec time_val;
int cur_time;
/* Get the Monotonic time */
clock_gettime(CLOCK_MONOTONIC, &time_val);
/* Convert time in seconds and micro seconds into milliseconds time */
cur_time = time_val.tv_sec * 1000 + time_val.tv_nsec / 1000000;
return cur_time;
}
}
/*****************************************************************************/
/* */
/* Function Name : osal_get_time_usec */
/* */
/* Description : This function returns absolute time in micro seconds */
/* */
/* Inputs : None */
/* Globals : None */
/* */
/* Processing : Gets the absolute time by calling OS specific API's. */
/* */
/* Outputs : Absolute time in micro seconds. */
/* */
/* Returns : +ve 32 bit value */
/* */
/* Issues : None */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 06 03 2009 Ittiam Draft */
/* */
/*****************************************************************************/
WORD32 osal_get_time_usec(UWORD32 *sec, UWORD32 *usec)
{
if((0 == sec) || (0 == usec))
return OSAL_ERROR;
{
struct timespec time_val;
/* Get the Monotonic time */
clock_gettime(CLOCK_MONOTONIC, &time_val);
/* Convert time in seconds and micro seconds into milliseconds time */
*sec = time_val.tv_sec;
*usec = time_val.tv_nsec / 1000;
return OSAL_SUCCESS;
}
}
/*****************************************************************************/
/* */
/* Function Name : osal_get_last_error */
/* */
/* Description : This function gets the last error code. */
/* */
/* Inputs : None */
/* Globals : None */
/* */
/* Processing : Gets the last occured error code by calling OS specific */
/* API call. */
/* */
/* Outputs : Error Number */
/* */
/* Returns : If no error - 0 */
/* Else - +ve number */
/* */
/* Issues : None */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 06 03 2006 Ittiam Draft */
/* */
/*****************************************************************************/
UWORD32 osal_get_last_error()
{
UWORD32 get_linux_error(void);
return get_linux_error();
}
/*****************************************************************************/
/* */
/* Function Name : osal_print_last_error */
/* */
/* Description : This function prints the last error message. */
/* */
/* Inputs : None */
/* Globals : None */
/* */
/* Processing : Gets the last occured error code by calling OS specific */
/* API call. It prints argument string (if not NULL), */
/* followed by ': ' then the error_string and <new_line>. */
/* */
/* Outputs : None */
/* */
/* Returns : None */
/* */
/* Issues : None */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 10 03 2006 Ittiam Draft */
/* */
/*****************************************************************************/
void osal_print_last_error(IN const STRWORD8 *string)
{
perror(string);
}
/*****************************************************************************/
/* */
/* Function Name : osal_get_current_tid */
/* */
/* Description : Gets the tid of the thread in whose context this call */
/* was made */
/* */
/* Inputs : None */
/* Globals : None */
/* Processing : None */
/* Outputs : None */
/* Returns : Thread ID, as a WORD32 */
/* Issues : None */
/* */
/* Revision History: */
/* */
/* DD MM YYYY Author(s) Changes (Describe the changes made) */
/* 07 05 2015 Ittiam Draft */
/* */
/*****************************************************************************/
WORD32 osal_get_current_tid(void)
{
return syscall(__NR_gettid);
}