/****************************************************************************** * * 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 #include #include #include #include #include #include #include #include /*for CPU_SET, etc.. */ #include #include /* 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 . */ /* */ /* 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); }