Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pal_plat_rtos.c Source File

pal_plat_rtos.c

00001 /*******************************************************************************
00002  * Copyright 2016, 2017 ARM Ltd.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  *******************************************************************************/
00016 
00017 #include <stdlib.h>
00018 #include <stdio.h>
00019 #include <time.h>
00020 #include <pthread.h>
00021 #include <semaphore.h>
00022 #include <signal.h>
00023 #include <mqueue.h>
00024 #include <errno.h>
00025 #include <string.h>
00026 #include <unistd.h>
00027 #include <fcntl.h>
00028 #include <sys/reboot.h>
00029 #include <sys/types.h>
00030 #include <sys/wait.h>
00031 #include <sys/utsname.h>
00032 
00033 #include "pal.h"
00034 #include "pal_plat_rtos.h"
00035 
00036 #define TRACE_GROUP "PAL"
00037 
00038  /*
00039  * The realtime clock is in nano seconds resolution. This is too much for us, so we use "longer" ticks.
00040  * Below are relevant defines.
00041  * make sure they all coherent. Can use one at the other, but will add some unneeded calculations.
00042  */
00043 #define NANOS_PER_TICK 100
00044 #define TICKS_PER_MICRO  10L
00045 #define TICKS_PER_MILLI  TICKS_PER_MICRO * 1000
00046 #define TICKS_PER_SECOND TICKS_PER_MILLI * 1000
00047 
00048 // priorities must be positive, so shift all by this margin. we might want to do smarter convert.
00049 #define LINUX_THREAD_PRIORITY_BASE 10
00050 
00051 #ifndef CLOCK_MONOTONIC_RAW //a workaround for the operWRT port that missing this include
00052 #define CLOCK_MONOTONIC_RAW 4 //http://elixir.free-electrons.com/linux/latest/source/include/uapi/linux/time.h
00053 #endif
00054 
00055 #define PAL_THREAD_PRIORITY_TRANSLATE(x) ((int16_t)(x + 7))
00056 
00057 typedef struct palThreadData
00058 {
00059     palThreadFuncPtr userFunction;
00060     void* userFunctionArgument;
00061 } palThreadData_t;
00062 
00063 /*
00064  * Internal struct to handle timers.
00065  */
00066 struct palTimerInfo
00067 {
00068     struct palTimerInfo *next;
00069     timer_t handle;
00070     palTimerFuncPtr function;
00071     void *funcArgs;
00072     palTimerType_t timerType;
00073 };
00074 
00075 // Mutex to prevent simultaneus modification of the linked list of the timers in g_timerList.
00076 PAL_PRIVATE palMutexID_t g_timerListMutex = 0;
00077 
00078 #if (PAL_SIMULATE_RTOS_REBOOT == 1)
00079     extern char *program_invocation_name;
00080 #endif
00081 
00082 
00083 // A singly linked list of the timers, access may be done only if holding the g_timerListMutex.
00084 // The list is needed as the timers use async signals and when the signal is finally delivered, the
00085 // palTimerInfo timer struct may be already deleted. The signals themselves carry pointer to timer,
00086 // so whenever a signal is received, the thread will look if the palTimerInfo is still on the list,
00087 // and if it is, uses the struct to find the callback pointer and arguments.
00088 PAL_PRIVATE volatile struct palTimerInfo *g_timerList = NULL;
00089 
00090 extern palStatus_t pal_plat_getRandomBufferFromHW(uint8_t *randomBuf, size_t bufSizeBytes, size_t* actualRandomSizeBytes);
00091 
00092 PAL_PRIVATE palStatus_t startTimerThread();
00093 PAL_PRIVATE palStatus_t stopTimerThread();
00094 PAL_PRIVATE void palTimerThread(void const *args);
00095 
00096 /*! Initiate a system reboot.
00097  */
00098 void pal_plat_osReboot(void)
00099 {
00100 //Simulator is currently for Linux only
00101 #if (PAL_SIMULATE_RTOS_REBOOT == 1)
00102     const char *argv[] = {"0" , 0};
00103     char *const envp[] = { 0 };
00104     argv[0] = program_invocation_name;
00105 
00106     PAL_LOG_INFO("pal_plat_osReboot -> simulated reboot with execve(%s).\r\n", argv[0]);
00107 
00108     if (-1 == execve(argv[0], (char **)argv , envp))
00109     {
00110         PAL_LOG_ERR("child process execve failed [%s]\r\n", argv[0]);
00111     }
00112 #else
00113     PAL_LOG_INFO("Rebooting the system\r\n");
00114 
00115     // Syncronize cached files to persistant storage.
00116     sync();
00117     // Reboot the device
00118     reboot(RB_AUTOBOOT);
00119 #endif
00120 }
00121 
00122 /*! Initialize all data structures (semaphores, mutexs, memory pools, message queues) at system initialization.
00123 *   In case of a failure in any of the initializations, the function returns with an error and stops the rest of the initializations.
00124 * @param[in] opaqueContext The context passed to the initialization (not required for generic CMSIS, pass NULL in this case).
00125 * \return PAL_SUCCESS(0) in case of success, PAL_ERR_CREATION_FAILED in case of failure.
00126 */
00127 palStatus_t pal_plat_RTOSInitialize(void* opaqueContext)
00128 {
00129     palStatus_t status = PAL_SUCCESS;
00130     (void)opaqueContext;
00131 #if (PAL_USE_HW_RTC)
00132     status = pal_plat_rtcInit();
00133 #endif
00134 
00135     // Setup the signal handler thread which will be shared with all the timers
00136 
00137     status = pal_osMutexCreate(&g_timerListMutex);
00138 
00139     if (status == PAL_SUCCESS) {
00140 
00141         sigset_t blocked;
00142 
00143         sigemptyset(&blocked);
00144         sigaddset(&blocked, PAL_TIMER_SIGNAL);
00145 
00146         // Make PAL_TIMER_SIGNAL blocked from this thread and the others
00147         // created onwards. Note: there is no handler for that on purpose, as
00148         // the signal is handled by the timer thread itself by sigwaitinfo().
00149         int err = pthread_sigmask(SIG_BLOCK, &blocked, NULL);
00150 
00151         if (err != 0) {
00152 
00153             status = PAL_ERR_SYSCALL_FAILED ;
00154         }
00155     }
00156 
00157     if (status == PAL_SUCCESS) {
00158 
00159         status = startTimerThread();
00160     }
00161 
00162     return status;
00163 }
00164 
00165 /*! De-Initialize thread objects.
00166  */
00167 palStatus_t pal_plat_RTOSDestroy(void)
00168 {
00169     palStatus_t ret = PAL_SUCCESS;
00170 
00171 #if PAL_USE_HW_RTC
00172     ret = pal_plat_rtcDeInit();
00173 #endif
00174 
00175     // Is there really a point to check these, as if the shutdown fails, what can we do?
00176     // Nobody is going to call the shutdown again.
00177     if (ret == PAL_SUCCESS) {
00178         ret = stopTimerThread();
00179     }
00180 
00181     if (ret == PAL_SUCCESS) {
00182         ret = pal_osMutexDelete(&g_timerListMutex);
00183     }
00184 
00185     return ret;
00186 }
00187 
00188 /*return The RTOS kernel system timer counter, in microseconds
00189  */
00190 
00191 uint64_t pal_plat_osKernelSysTick(void) // optional API - not part of original CMSIS API.
00192 {
00193     /*Using clock_gettime is more accurate, but then we have to convert it to ticks. we are using a tick every 100 nanoseconds*/
00194     struct timespec ts;
00195     uint64_t ticks;
00196     //TODO: error handling
00197     clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
00198 
00199     ticks = (uint64_t) (ts.tv_sec * (uint64_t)TICKS_PER_SECOND
00200             + (ts.tv_nsec / NANOS_PER_TICK));
00201     return ticks;
00202 }
00203 
00204 /* Convert the value from microseconds to kernel sys ticks.
00205  * This is the same as CMSIS macro osKernelSysTickMicroSec.
00206  * since we return microsecods as ticks, just return the value
00207  */
00208 uint64_t pal_plat_osKernelSysTickMicroSec(uint64_t microseconds)
00209 {
00210 
00211     //convert to nanoseconds
00212     return microseconds * TICKS_PER_MICRO;
00213 }
00214 
00215 /*! Get the system tick frequency.
00216  * \return The system tick frequency.
00217  */
00218 inline uint64_t pal_plat_osKernelSysTickFrequency(void)
00219 {
00220     /* since we use clock_gettime, with resolution of 100 nanosecond per tick*/
00221     return TICKS_PER_SECOND;
00222 }
00223 
00224 PAL_PRIVATE void threadCleanupHandler(void* arg)
00225 {
00226     free(arg);
00227 }
00228 
00229 PAL_PRIVATE void* threadFunction(void* arg)
00230 {
00231     /*
00232     * note: even if a thread is only scheduled but has not started running, it will be cancelled only once it starts running and once it reaches a cancellation point, 
00233     *       hence the clean up handler will always be executed thus avoiding a memory leak.
00234     *       see section 2.9.5 @ http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html
00235     */
00236     pthread_cleanup_push(threadCleanupHandler, arg); // register a cleanup handler to be executed once the thread is finished/terminated (threads can terminate only when reaching a cancellation point)
00237     palThreadData_t* threadData = (palThreadData_t*)arg;
00238     threadData->userFunction(threadData->userFunctionArgument);
00239     pthread_cleanup_pop(1); // in case the thread has not terminated execute the cleanup handler (passing a non zero value to pthread_cleanup_pop)
00240     return NULL;
00241 }
00242 
00243 palStatus_t pal_plat_osThreadCreate(palThreadFuncPtr function, void* funcArgument, palThreadPriority_t priority, uint32_t stackSize, palThreadID_t* threadID)
00244 {
00245     palStatus_t status = PAL_ERR_GENERIC_FAILURE ;
00246     pthread_t sysThreadID = (pthread_t)NULL;
00247     struct sched_param schedParam;
00248     pthread_attr_t attr;
00249     pthread_attr_t* ptrAttr = NULL;
00250     palThreadData_t* threadData;
00251     int err = pthread_attr_init(&attr);
00252     if (0 != err)
00253     {
00254         goto finish;
00255     }
00256     ptrAttr = &attr;
00257 
00258     err = pthread_attr_setstacksize(ptrAttr, stackSize);
00259     if (0 != err)
00260     {
00261         goto finish;
00262     }
00263 
00264     err = pthread_attr_setschedpolicy(ptrAttr, SCHED_RR);
00265     if (0 != err)
00266     {
00267         goto finish;
00268     }
00269 
00270 #if (PAL_SIMULATOR_TEST_ENABLE == 0) // disable ONLY for Linux PC simulator 
00271     err = pthread_attr_setinheritsched(ptrAttr, PTHREAD_EXPLICIT_SCHED);
00272     if (0 != err)
00273     {
00274         goto finish;
00275     }
00276 #endif    
00277     
00278     err = pthread_attr_setdetachstate(ptrAttr, PTHREAD_CREATE_DETACHED);
00279     if (0 != err)
00280     {
00281         goto finish;
00282     }    
00283     
00284     schedParam.sched_priority = PAL_THREAD_PRIORITY_TRANSLATE(priority);
00285     err = pthread_attr_setschedparam(ptrAttr, &schedParam);
00286     if (0 != err)
00287     {
00288         goto finish;
00289     }
00290 
00291     threadData = (palThreadData_t*)malloc(sizeof(palThreadData_t));
00292     if (NULL == threadData)
00293     {
00294         status = PAL_ERR_RTOS_RESOURCE ;
00295         goto finish;
00296     }
00297     threadData->userFunction = function;
00298     threadData->userFunctionArgument = funcArgument;
00299 
00300     err = pthread_create(&sysThreadID, ptrAttr, threadFunction, (void*)threadData);
00301     if (0 != err)
00302     {        
00303         free(threadData);
00304         status = (EPERM == err) ? PAL_ERR_RTOS_PRIORITY  : PAL_ERR_RTOS_RESOURCE ;
00305         goto finish;
00306     }
00307 
00308     *threadID = (palThreadID_t)sysThreadID;
00309     status = PAL_SUCCESS;
00310 
00311 finish:
00312     if (NULL != ptrAttr)
00313     {
00314         err = pthread_attr_destroy(ptrAttr);
00315         if (0 != err)
00316         {
00317             PAL_LOG_ERR("pal_plat_osThreadCreate failed to destroy pthread_attr_t\n");
00318         }
00319     }
00320     return status;
00321 }
00322 
00323 palThreadID_t pal_plat_osThreadGetId(void)
00324 {
00325     palThreadID_t threadID = (palThreadID_t)pthread_self();
00326     return threadID;
00327 }
00328 
00329 palStatus_t pal_plat_osThreadTerminate(palThreadID_t* threadID)
00330 {
00331     palStatus_t status = PAL_ERR_RTOS_TASK ;
00332     int err;
00333     pthread_t sysThreadID = (pthread_t)*threadID;
00334     if (!pthread_equal(pthread_self(), sysThreadID)) // self termination not allowed
00335     {
00336         err = pthread_cancel(sysThreadID);
00337         if ((0 == err) || (ESRCH == err))
00338         {
00339             status = PAL_SUCCESS;
00340         }
00341         else
00342         {
00343             status = PAL_ERR_RTOS_RESOURCE ;
00344         }
00345     }
00346     return status;
00347 }
00348 
00349 /*! Wait for a specified period of time in milliseconds.
00350  *
00351  * @param[in] milliseconds The number of milliseconds to wait before proceeding.
00352  *
00353  * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure.
00354  */
00355 palStatus_t pal_plat_osDelay(uint32_t milliseconds)
00356 {
00357     struct timespec sTime;
00358     struct timespec rTime; // this will return how much sleep time still left in case of interrupted sleep
00359     int stat;
00360     //init rTime, as we will copy it over to stime inside the do-while loop.
00361     rTime.tv_sec = milliseconds / 1000;
00362     rTime.tv_nsec = PAL_MILLI_TO_NANO(milliseconds);
00363 
00364     do
00365     {
00366         sTime.tv_sec = rTime.tv_sec;
00367         sTime.tv_nsec = rTime.tv_nsec;
00368         stat = nanosleep(&sTime, &rTime);
00369     } while ((-1 == stat) && (EINTR ==errno)) ;
00370     return (stat == 0) ? PAL_SUCCESS : PAL_ERR_GENERIC_FAILURE ;
00371 }
00372 
00373 
00374 /*
00375 * Internal struct to handle timers.
00376 */
00377 
00378 typedef struct palTimerThreadContext
00379 {
00380     // semaphore used for signaling both the thread startup and thread closure
00381     palSemaphoreID_t startStopSemaphore;
00382 
00383     // If set, the timer thread will stop its loop, signal the startStopSemaphore
00384     // and run out of thread function. This is set and accessed while holding the
00385     // g_timerListMutex.
00386     volatile bool threadStopRequested;
00387 
00388 } palTimerThreadContext_t;
00389 
00390 
00391 static palThreadID_t s_palHighResTimerThreadID = NULLPTR;
00392 static palTimerThreadContext_t s_palTimerThreadContext = {0};
00393 
00394 /*
00395 * Thread for handling the signals from all timers by calling the attached callback
00396 */
00397 
00398 PAL_PRIVATE void palTimerThread(void const *args)
00399 {
00400     palTimerThreadContext_t* context = (palTimerThreadContext_t*)args;
00401 
00402     int err = 0;
00403 
00404     sigset_t signal_set_to_wait;
00405 
00406     sigemptyset(&signal_set_to_wait);
00407     sigaddset(&signal_set_to_wait, PAL_TIMER_SIGNAL);
00408 
00409     // signal the caller that thread has started
00410     if (pal_osSemaphoreRelease(context->startStopSemaphore) != PAL_SUCCESS) {
00411         PAL_LOG_ERR("pal_osSemaphoreRelease(context->startStopSemaphore) failed!");
00412     }
00413 
00414     // loop until signaled with threadStopRequested
00415     while (1) {
00416 
00417         siginfo_t info;
00418 
00419         // wait for signal from a timer
00420         err = sigwaitinfo(&signal_set_to_wait, &info);
00421 
00422         // A positive return value is the signal number, negative value is a sign of some
00423         // signal handler interrupting the OS call and errno should be then EINTR.
00424         // The other two documented errors, EAGAIN or EINVAL should not happen as we're
00425         // not using the timeout, but have them logged just in case.
00426         if (err <= 0) {
00427             if (errno != EINTR) {
00428                 PAL_LOG_ERR("palTimerThread: sigwaitinfo failed with %d\n", errno);
00429             }
00430         } else {
00431 
00432             // before using the timer list or threadStopRequested flag, we need to claim the mutex
00433             pal_osMutexWait(g_timerListMutex, PAL_RTOS_WAIT_FOREVER);
00434 
00435             if (context->threadStopRequested) {
00436 
00437                 // release mutex and bail out
00438                 // Coverity fix - Unchecked return value. Function pal_osMutexRelease already contains error trace.
00439                 (void)pal_osMutexRelease(g_timerListMutex);
00440                 break;
00441 
00442             } else {
00443 
00444                 // the sival_ptr contains the pointer of timer which caused it
00445                 struct palTimerInfo* signal_timer = (struct palTimerInfo*)info.si_value.sival_ptr;
00446 
00447                 struct palTimerInfo *temp_timer = (struct palTimerInfo*)g_timerList;
00448 
00449                 palTimerFuncPtr found_function = NULL;
00450                 void *found_funcArgs;
00451 
00452                 // Check, if the timer still is on the list. It may have been deleted, if the
00453                 // signal delivery / client callback has taken some time.
00454                 while (temp_timer != NULL) {
00455 
00456                     if (temp_timer == signal_timer) {
00457 
00458                         // Ok, found the timer from list, backup the parameters as we release
00459                         // the mutex after this loop, before calling the callback and the
00460                         // temp_timer may very well get deleted just after the mutex is released.
00461 
00462                         found_function = temp_timer->function;
00463                         found_funcArgs = temp_timer->funcArgs;
00464 
00465                         break;
00466                     } else {
00467                         temp_timer = temp_timer->next;
00468                     }
00469                 }
00470 
00471                 // Release the list mutex before callback to avoid callback deadlocking other threads
00472                 // if they try to create a timer.
00473                 // Coverity fix - 243862 Unchecked return value
00474                 (void)pal_osMutexRelease(g_timerListMutex);
00475 
00476                 // the function may be NULL here if the timer was already freed
00477                 if (found_function) {
00478                     // finally call the callback function
00479                     found_function(found_funcArgs);
00480                 }
00481             }
00482         }
00483     }
00484 
00485     // signal the caller that thread is now stopping and it can continue the pal_destroy()
00486     // Coverity fix - 243860 Unchecked return value. There is not much doable if fail.
00487     (void)pal_osSemaphoreRelease(context->startStopSemaphore);
00488 }
00489 
00490 PAL_PRIVATE palStatus_t startTimerThread()
00491 {
00492     palStatus_t status;
00493 
00494     status = pal_osSemaphoreCreate(0, &s_palTimerThreadContext.startStopSemaphore);
00495 
00496     if (status == PAL_SUCCESS) {
00497 
00498         s_palTimerThreadContext.threadStopRequested = false;
00499 
00500         status = pal_osThreadCreateWithAlloc(palTimerThread, &s_palTimerThreadContext, PAL_osPriorityReservedHighResTimer ,
00501                                                 PAL_RTOS_HIGH_RES_TIMER_THREAD_STACK_SIZE, NULL, &s_palHighResTimerThreadID);
00502 
00503         if (status == PAL_SUCCESS) {
00504 
00505             // the timer thread will signal on semaphore when it has started
00506             pal_osSemaphoreWait(s_palTimerThreadContext.startStopSemaphore, PAL_RTOS_WAIT_FOREVER, NULL);
00507 
00508         } else {
00509             // cleanup the semaphore
00510             pal_osSemaphoreDelete(&s_palTimerThreadContext.startStopSemaphore);
00511         }
00512     }
00513 
00514     return status;
00515 }
00516 
00517 PAL_PRIVATE palStatus_t stopTimerThread()
00518 {
00519     palStatus_t status;
00520 
00521     status = pal_osMutexWait(g_timerListMutex, PAL_RTOS_WAIT_FOREVER);
00522 
00523     if (status == PAL_SUCCESS) {
00524 
00525         // set the flag to end the thread
00526         s_palTimerThreadContext.threadStopRequested = true;
00527 
00528         // ping the timer thread that it should start shutdown
00529         pthread_t sysThreadID = (pthread_t)s_palHighResTimerThreadID;
00530         int err;
00531 
00532         do {
00533 
00534             // Send the signal to wake up helper thread. A cleaner way would
00535             // use pthread_sigqueue() as it allows sending the sival, but that
00536             // does not really matter as the threadStopRequested flag is
00537             // always checked before accessing the sival. pthread_sigqueue() is also
00538             // missing from eg. musl library.
00539             err = pthread_kill(sysThreadID, PAL_TIMER_SIGNAL);
00540 
00541         } while (err == EAGAIN); // retry (spin, yuck!) if the signal queue is full
00542 
00543         // Coverity fix - 243859 Unchecked return value. There is not much doable if fail. StopTimerThread is part of shutdown step.
00544         (void)pal_osMutexRelease(g_timerListMutex);
00545 
00546         // pthread_sigqueue() failed, which is a sign of thread being dead, so a wait
00547         // on semaphore would cause a deadlock.
00548         if (err == 0) {
00549 
00550             // wait for for acknowledgement that timer thread is going down
00551             pal_osSemaphoreWait(s_palTimerThreadContext.startStopSemaphore, PAL_RTOS_WAIT_FOREVER, NULL);
00552         }
00553 
00554         pal_osSemaphoreDelete(&s_palTimerThreadContext.startStopSemaphore);
00555 
00556         // and clean up the thread
00557         status = pal_osThreadTerminate(&s_palHighResTimerThreadID);
00558     }
00559     return status;
00560 }
00561 
00562 
00563 /*! Create a timer.
00564  *
00565  * @param[in] function A function pointer to the timer callback function.
00566  * @param[in] funcArgument An argument for the timer callback function.
00567  * @param[in] timerType The timer type to be created, periodic or oneShot.
00568  * @param[out] timerID The ID of the created timer, zero value indicates an error.
00569  *
00570  * \return PAL_SUCCESS when the timer was created successfully. A specific error in case of failure.
00571  */
00572 palStatus_t pal_plat_osTimerCreate(palTimerFuncPtr function, void* funcArgument,
00573         palTimerType_t timerType, palTimerID_t* timerID)
00574 {
00575 
00576     palStatus_t status = PAL_SUCCESS;
00577     struct palTimerInfo* timerInfo = NULL;
00578     {
00579         struct sigevent sig;
00580         timer_t localTimer;
00581 
00582         if ((NULL == timerID) || (NULL == (void*) function))
00583         {
00584             return PAL_ERR_INVALID_ARGUMENT ;
00585         }
00586 
00587         timerInfo = (struct palTimerInfo*) malloc(sizeof(struct palTimerInfo));
00588         if (NULL == timerInfo)
00589         {
00590             status = PAL_ERR_NO_MEMORY ;
00591             goto finish;
00592         }
00593 
00594         timerInfo->function = function;
00595         timerInfo->funcArgs = funcArgument;
00596         timerInfo->timerType = timerType;
00597 
00598         memset(&sig, 0, sizeof(sig));
00599 
00600         sig.sigev_notify = SIGEV_SIGNAL;
00601         sig.sigev_signo = PAL_TIMER_SIGNAL;
00602 
00603         // the signal handler uses this to find the correct timer context
00604         sig.sigev_value.sival_ptr = timerInfo;
00605 
00606         int ret = timer_create(CLOCK_MONOTONIC, &sig, &localTimer);
00607         if (-1 == ret)
00608         {
00609             if (EINVAL == errno)
00610             {
00611                 status = PAL_ERR_INVALID_ARGUMENT ;
00612                 goto finish;
00613             }
00614             if (ENOMEM == errno)
00615             {
00616                 status = PAL_ERR_NO_MEMORY ;
00617                 goto finish;
00618             }
00619             PAL_LOG_ERR("Rtos timer create error %d", ret);
00620             status = PAL_ERR_GENERIC_FAILURE ;
00621             goto finish;
00622         }
00623 
00624         // managed to create the timer - finish up
00625         timerInfo->handle = localTimer;
00626         *timerID = (palTimerID_t) timerInfo;
00627 
00628         pal_osMutexWait(g_timerListMutex, PAL_RTOS_WAIT_FOREVER);
00629 
00630         // add the new timer to head of the singly linked list
00631         timerInfo->next = (struct palTimerInfo *)g_timerList;
00632 
00633         g_timerList = timerInfo;
00634 
00635         // 243861 Unchecked return value
00636         (void)pal_osMutexRelease(g_timerListMutex);
00637     }
00638     finish: if (PAL_SUCCESS != status)
00639     {
00640         if (NULL != timerInfo)
00641         {
00642             free(timerInfo);
00643             *timerID = (palTimerID_t) NULL;
00644         }
00645     }
00646     return status;
00647 }
00648 
00649 /* Convert milliseconds into seconds and nanoseconds inside a timespec struct
00650  */
00651 PAL_PRIVATE void convertMilli2Timespec(uint32_t millisec, struct timespec* ts)
00652 {
00653     ts->tv_sec = millisec / 1000;
00654     ts->tv_nsec = PAL_MILLI_TO_NANO(millisec);
00655 }
00656 
00657 /*! Start or restart a timer.
00658  *
00659  * @param[in] timerID The handle for the timer to start.
00660  * @param[in] millisec The time in milliseconds to set the timer to.
00661  *
00662  * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure.
00663  */
00664 palStatus_t pal_plat_osTimerStart(palTimerID_t timerID, uint32_t millisec)
00665 {
00666     palStatus_t status = PAL_SUCCESS;
00667     if (NULL == (struct palTimerInfo *) timerID)
00668     {
00669         return PAL_ERR_INVALID_ARGUMENT ;
00670     }
00671 
00672     struct palTimerInfo* timerInfo = (struct palTimerInfo *) timerID;
00673     struct itimerspec its;
00674 
00675     convertMilli2Timespec(millisec, &(its.it_value));
00676 
00677     if (palOsTimerPeriodic  == timerInfo->timerType)
00678     {
00679         convertMilli2Timespec(millisec, &(its.it_interval));
00680     }
00681     else
00682     {  // one time timer
00683         convertMilli2Timespec(0, &(its.it_interval));
00684     }
00685 
00686     if (-1 == timer_settime(timerInfo->handle, 0, &its, NULL))
00687     {
00688         status = PAL_ERR_INVALID_ARGUMENT ;
00689     }
00690 
00691     return status;
00692 }
00693 
00694 /*! Stop a timer.
00695  *
00696  * @param[in] timerID The handle for the timer to stop.
00697  *
00698  * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure.
00699  */
00700 palStatus_t pal_plat_osTimerStop(palTimerID_t timerID)
00701 {
00702     palStatus_t status = PAL_SUCCESS;
00703     if (NULL == (struct palTimerInfo *) timerID)
00704     {
00705         return PAL_ERR_INVALID_ARGUMENT ;
00706     }
00707 
00708     struct palTimerInfo* timerInfo = (struct palTimerInfo *) timerID;
00709     struct itimerspec its;
00710 
00711     // set timer to 0 to disarm it.
00712     convertMilli2Timespec(0, &(its.it_value));
00713 
00714     convertMilli2Timespec(0, &(its.it_interval));
00715 
00716     if (-1 == timer_settime(timerInfo->handle, 0, &its, NULL))
00717     {
00718         status = PAL_ERR_INVALID_ARGUMENT ;
00719     }
00720 
00721     return status;
00722 }
00723 
00724 /*! Delete the timer object
00725  *
00726  * @param[inout] timerID The handle for the timer to delete. In success, *timerID = NULL.
00727  *
00728  * \return PAL_SUCCESS when the timer was deleted successfully, PAL_ERR_RTOS_PARAMETER when the timerID is incorrect.
00729  */
00730 palStatus_t pal_plat_osTimerDelete(palTimerID_t* timerID)
00731 {
00732     palStatus_t status = PAL_SUCCESS;
00733     if ((NULL == timerID) || ((struct palTimerInfo *)*timerID == NULL)) {
00734         return PAL_ERR_INVALID_ARGUMENT ;
00735     }
00736     struct palTimerInfo* timerInfo = (struct palTimerInfo *) *timerID;
00737 
00738     // the list of timers is protected by a mutex to avoid concurrency issues
00739     pal_osMutexWait(g_timerListMutex, PAL_RTOS_WAIT_FOREVER);
00740 
00741     // remove the timer from the list before freeing it
00742     struct palTimerInfo *prev_timer = NULL;
00743     struct palTimerInfo *temp_timer = (struct palTimerInfo *)g_timerList;
00744 
00745     while (temp_timer) {
00746 
00747         if (temp_timer == timerInfo) {
00748             // found the timer from list, now it needs to be removed from there
00749 
00750             if (prev_timer) {
00751                 // there was a previous item, so update its next to this objects next
00752                 prev_timer->next = temp_timer->next;
00753             } else {
00754                 // the item was the first/only one, so update the list head instead
00755                 g_timerList = temp_timer->next;
00756             }
00757             // all done now
00758             break;
00759 
00760         } else {
00761             prev_timer = temp_timer;
00762             temp_timer = temp_timer->next;
00763         }
00764     }
00765 
00766     timer_t lt = timerInfo->handle;
00767     if (-1 == timer_delete(lt)) {
00768         status = PAL_ERR_RTOS_RESOURCE ;
00769     }
00770 
00771     // 243863 Unchecked return value
00772     (void)pal_osMutexRelease(g_timerListMutex);
00773 
00774     free(timerInfo);
00775     *timerID = (palTimerID_t) NULL;
00776 
00777     return status;
00778 }
00779 
00780 /*! Create and initialize a mutex object.
00781  *
00782  * @param[out] mutexID The created mutex ID handle, zero value indicates an error.
00783  *
00784  * \return PAL_SUCCESS when the mutex was created successfully, a specific error in case of failure.
00785  */
00786 palStatus_t pal_plat_osMutexCreate(palMutexID_t* mutexID)
00787 {
00788     palStatus_t status = PAL_SUCCESS;
00789     pthread_mutex_t* mutex = NULL;
00790     {
00791         int ret;
00792         if (NULL == mutexID)
00793         {
00794             return PAL_ERR_INVALID_ARGUMENT ;
00795         }
00796 
00797         mutex = malloc(sizeof(pthread_mutex_t));
00798         if (NULL == mutex)
00799         {
00800             status = PAL_ERR_NO_MEMORY ;
00801             goto finish;
00802         }
00803 
00804         pthread_mutexattr_t mutexAttr;
00805         pthread_mutexattr_init(&mutexAttr);
00806         pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE);
00807         ret = pthread_mutex_init(mutex, &mutexAttr);
00808 
00809         if (0 != ret)
00810         {
00811             if (ENOMEM == ret)
00812             {
00813                 status = PAL_ERR_NO_MEMORY ;
00814             }
00815             else
00816             {
00817                 PAL_LOG_ERR("Rtos mutex create status %d", ret);
00818                 status = PAL_ERR_GENERIC_FAILURE ;
00819             }
00820             goto finish;
00821         }
00822         *mutexID = (palMutexID_t) mutex;
00823     }
00824     finish: if (PAL_SUCCESS != status)
00825     {
00826         if (NULL != mutex)
00827         {
00828             free(mutex);
00829         }
00830     }
00831     return status;
00832 }
00833 
00834 /* Wait until a mutex becomes available.
00835  *
00836  * @param[in] mutexID The handle for the mutex.
00837  * @param[in] millisec The timeout for the waiting operation if the timeout expires before the semaphore is released and an error is returned from the function.
00838  *
00839  * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, one of the following error codes in case of failure:
00840  *        PAL_ERR_RTOS_RESOURCE - Mutex not available but no timeout set.
00841  *        PAL_ERR_RTOS_TIMEOUT - Mutex was not available until timeout expired.
00842  *        PAL_ERR_RTOS_PARAMETER - Mutex ID is invalid.
00843  *        PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines.
00844  */
00845 palStatus_t pal_plat_osMutexWait(palMutexID_t mutexID, uint32_t millisec)
00846 {
00847     palStatus_t status = PAL_SUCCESS;
00848     int err;
00849     if (NULL == ((pthread_mutex_t*) mutexID))
00850     {
00851         return PAL_ERR_INVALID_ARGUMENT ;
00852     }
00853     pthread_mutex_t* mutex = (pthread_mutex_t*) mutexID;
00854 
00855     if (PAL_RTOS_WAIT_FOREVER != millisec)
00856     {
00857         /* calculate the wait absolute time */
00858         struct timespec ts;
00859         clock_gettime(CLOCK_REALTIME, &ts);
00860 
00861         ts.tv_sec += (millisec / PAL_MILLI_PER_SECOND);
00862         ts.tv_nsec += PAL_MILLI_TO_NANO(millisec);
00863         ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; // if there is some overflow in the addition of nanoseconds.
00864         ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND;
00865 
00866         while ((err = pthread_mutex_timedlock(mutex, &ts)) != 0 && err == EINTR)
00867         {
00868             continue; /* Restart if interrupted by handler */
00869         }
00870     }
00871     else
00872     { // wait for ever
00873         err = pthread_mutex_lock(mutex);
00874     }
00875 
00876     if (0 != err)
00877     {
00878         if (err == ETIMEDOUT)
00879         {
00880             status = PAL_ERR_RTOS_TIMEOUT ;
00881         }
00882         else
00883         {
00884             PAL_LOG_ERR("Rtos mutex wait status %d", err);
00885             status = PAL_ERR_GENERIC_FAILURE ;
00886         }
00887     }
00888 
00889     return status;
00890 }
00891 
00892 /* Release a mutex that was obtained by osMutexWait.
00893  *
00894  * @param[in] mutexID The handle for the mutex.
00895  *
00896  * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure.
00897  */
00898 palStatus_t pal_plat_osMutexRelease(palMutexID_t mutexID)
00899 {
00900     palStatus_t status = PAL_SUCCESS;
00901     int result = 0;
00902 
00903     pthread_mutex_t* mutex = (pthread_mutex_t*) mutexID;
00904     if (NULL == mutex)
00905     {
00906         return PAL_ERR_INVALID_ARGUMENT ;
00907     }
00908 
00909     result = pthread_mutex_unlock(mutex);
00910     if (0 != result)
00911     {
00912         // only reason this might fail - process don't have permission for mutex.
00913         PAL_LOG_ERR("Rtos mutex release failure - %d",result);
00914         status = PAL_ERR_GENERIC_FAILURE ;
00915     }
00916     return status;
00917 }
00918 
00919 /*Delete a mutex object.
00920  *
00921  * @param[inout] mutexID The ID of the mutex to delete. In success, *mutexID = NULL.
00922  *
00923  * \return PAL_SUCCESS when the mutex was deleted successfully, one of the following error codes in case of failure:
00924  *        PAL_ERR_RTOS_RESOURCE - Mutex already released.
00925  *        PAL_ERR_RTOS_PARAMETER - Mutex ID is invalid.
00926  *        PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines.
00927  * \note After this call, mutex_id is no longer valid and cannot be used.
00928  */
00929 palStatus_t pal_plat_osMutexDelete(palMutexID_t* mutexID)
00930 {
00931     palStatus_t status = PAL_SUCCESS;
00932     uint32_t ret;
00933     if (NULL == mutexID) {
00934         return PAL_ERR_INVALID_ARGUMENT ;
00935     }
00936     pthread_mutex_t* mutex = (pthread_mutex_t*) *mutexID;
00937 
00938     if (NULL == mutex) {
00939         status = PAL_ERR_RTOS_RESOURCE ;
00940     }
00941     else {
00942         ret = pthread_mutex_destroy(mutex);
00943         if ((PAL_SUCCESS == status) && (0 != ret))
00944         {
00945         PAL_LOG_ERR("pal_plat_osMutexDelete 0x%x",ret);
00946             status = PAL_ERR_RTOS_RESOURCE ;
00947         }
00948         free(mutex);
00949         *mutexID = (palMutexID_t) NULL;
00950     }
00951     return status;
00952 }
00953 
00954 /* Create and initialize a semaphore object.
00955  *
00956  * Semaphore is shared between threads, but not process.
00957  *
00958  * @param[in] count The number of available resources.
00959  * @param[out] semaphoreID The ID of the created semaphore, zero value indicates an error.
00960  *
00961  * \return PAL_SUCCESS when the semaphore was created successfully, a specific error in case of failure.
00962  */
00963 palStatus_t pal_plat_osSemaphoreCreate(uint32_t count,
00964         palSemaphoreID_t* semaphoreID)
00965 {
00966     palStatus_t status = PAL_SUCCESS;
00967     sem_t* semaphore = NULL;
00968 
00969     {
00970         if (NULL == semaphoreID)
00971         {
00972             return PAL_ERR_INVALID_ARGUMENT ;
00973         }
00974         semaphore = malloc(sizeof(sem_t));
00975         if (NULL == semaphore)
00976         {
00977             status = PAL_ERR_NO_MEMORY ;
00978             goto finish;
00979         }
00980         /* create the semaphore as shared between threads */
00981         int ret = sem_init(semaphore, 0, count);
00982         if (-1 == ret)
00983         {
00984             if (EINVAL == errno)
00985             {
00986                 /* count is too big */
00987                 status = PAL_ERR_INVALID_ARGUMENT ;
00988             }
00989             else
00990             {
00991                 PAL_LOG_ERR("Rtos semaphore init error %d", ret);
00992                 status = PAL_ERR_GENERIC_FAILURE ;
00993             }
00994             goto finish;
00995         }
00996 
00997         *semaphoreID = (palSemaphoreID_t) semaphore;
00998     }
00999     finish: if (PAL_SUCCESS != status)
01000     {
01001         if (NULL != semaphore)
01002         {
01003             free(semaphore);
01004         }
01005         *semaphoreID = (palSemaphoreID_t) NULL;
01006     }
01007     return status;
01008 }
01009 
01010 /* Wait until a semaphore token becomes available.
01011  *
01012  * @param[in] semaphoreID The handle for the semaphore.
01013  * @param[in] millisec The timeout for the waiting operation if the timeout expires before the semaphore is released and an error is returned from the function.
01014  * @param[out] countersAvailable The number of semaphores available (before the wait), if semaphores are not available (timeout/error) zero is returned.
01015  *
01016  * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, one of the following error codes in case of failure:
01017  *      PAL_ERR_RTOS_TIMEOUT - Semaphore was not available until timeout expired.
01018  *      PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid.
01019  *      PAL_ERR_INVALID_ARGUMENT - countersAvailable is NULL
01020  *
01021  *      NOTES: 1. counterAvailable returns 0 in case there are no semaphores available or there are other threads waiting on it.
01022  *                Value is not thread safe - it might be changed by the time it is read/returned.
01023  *             2. timed wait is using absolute time.
01024  */
01025 palStatus_t pal_plat_osSemaphoreWait(palSemaphoreID_t semaphoreID,
01026         uint32_t millisec, int32_t* countersAvailable)
01027 {
01028     palStatus_t status = PAL_SUCCESS;
01029     int tmpCounters = 0;
01030     {
01031         int err;
01032         sem_t* sem = (sem_t*) semaphoreID;
01033         if ((NULL == sem))
01034         {
01035             return PAL_ERR_INVALID_ARGUMENT ;
01036         }
01037 
01038         if (PAL_RTOS_WAIT_FOREVER != millisec)
01039         {
01040             /* calculate the wait absolute time */
01041             struct timespec ts;
01042             clock_gettime(CLOCK_REALTIME, &ts);
01043             ts.tv_sec += millisec / PAL_MILLI_PER_SECOND;
01044             ts.tv_nsec += PAL_MILLI_TO_NANO(millisec);
01045             ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; // in case there is overflow in the nanoseconds.
01046             ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND;
01047 
01048             while ((err = sem_timedwait(sem, &ts)) == -1 && errno == EINTR)
01049                 continue; /* Restart if interrupted by handler */
01050         }
01051         else
01052         { // wait for ever
01053             do
01054             {
01055                 err = sem_wait(sem);
01056 
01057                 /* loop again if the wait was interrupted by a signal */
01058             } while ((err == -1) && (errno == EINTR));
01059         }
01060 
01061         if (-1 == err)
01062         {
01063             tmpCounters = 0;
01064             if (errno == ETIMEDOUT)
01065             {
01066                 status = PAL_ERR_RTOS_TIMEOUT ;
01067             }
01068             else
01069             { /* seems this is not a valid semaphore */
01070                 status = PAL_ERR_RTOS_PARAMETER ;
01071             }
01072             goto finish;
01073         }
01074         /* get the counter number, shouldn't fail, as we already know this is valid semaphore */
01075         sem_getvalue(sem, &tmpCounters);
01076     }
01077     finish:
01078     if (NULL != countersAvailable)
01079     {
01080         *countersAvailable = tmpCounters;
01081     }
01082     return status;
01083 }
01084 
01085 /*! Release a semaphore token.
01086  *
01087  * @param[in] semaphoreID The handle for the semaphore.
01088  *
01089  * \return The status in the form of palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure.
01090  */
01091 palStatus_t pal_plat_osSemaphoreRelease(palSemaphoreID_t semaphoreID)
01092 {
01093     palStatus_t status = PAL_SUCCESS;
01094     sem_t* sem = (sem_t*) semaphoreID;
01095 
01096     if (NULL == sem)
01097     {
01098         return PAL_ERR_INVALID_ARGUMENT ;
01099     }
01100 
01101     if (-1 == sem_post(sem))
01102     {
01103         if (EINVAL == errno)
01104         {
01105             status = PAL_ERR_RTOS_PARAMETER ;
01106         }
01107         else
01108         { /* max value of semaphore exeeded */
01109             PAL_LOG_ERR("Rtos semaphore release error %d", errno);
01110             status = PAL_ERR_GENERIC_FAILURE ;
01111         }
01112     }
01113 
01114     return status;
01115 }
01116 
01117 /*! Delete a semaphore object.
01118  *
01119  * @param[inout] semaphoreID: The ID of the semaphore to delete. In success, *semaphoreID = NULL.
01120  *
01121  * \return PAL_SUCCESS when the semaphore was deleted successfully, one of the following error codes in case of failure:
01122  *        PAL_ERR_RTOS_RESOURCE - Semaphore already released.
01123  *        PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid.
01124  * \note After this call, the semaphore_id is no longer valid and cannot be used.
01125  */
01126 palStatus_t pal_plat_osSemaphoreDelete(palSemaphoreID_t* semaphoreID)
01127 {
01128     palStatus_t status = PAL_SUCCESS;
01129     {
01130         if (NULL == semaphoreID)
01131         {
01132             return PAL_ERR_INVALID_ARGUMENT ;
01133         }
01134 
01135         sem_t* sem = (sem_t*) (*semaphoreID);
01136         if (NULL == sem)
01137         {
01138             status = PAL_ERR_RTOS_RESOURCE ;
01139             goto finish;
01140         }
01141         if (-1 == sem_destroy(sem))
01142         {
01143             status = PAL_ERR_RTOS_PARAMETER ;
01144             goto finish;
01145         }
01146 
01147         if (NULL != sem)
01148         {
01149             free(sem);
01150         }
01151         *semaphoreID = (palSemaphoreID_t) NULL;
01152     }
01153     finish: return status;
01154 }
01155 
01156 /*! Perform an atomic increment for a signed32 bit value.
01157  *
01158  * @param[in,out] valuePtr The address of the value to increment.
01159  * @param[in] increment The number by which to increment.
01160  *
01161  * \returns The value of the valuePtr after the increment operation.
01162  */
01163 int32_t pal_plat_osAtomicIncrement(int32_t* valuePtr, int32_t increment)
01164 {
01165     int32_t res = __sync_add_and_fetch(valuePtr, increment);
01166     return res;
01167 }
01168 
01169 
01170 void *pal_plat_malloc(size_t len)
01171 {
01172     return malloc(len);
01173 }
01174 
01175 
01176 void pal_plat_free(void * buffer)
01177 {
01178     return free(buffer);
01179 }
01180 
01181 palStatus_t pal_plat_osRandomBuffer(uint8_t *randomBuf, size_t bufSizeBytes, size_t* actualRandomSizeBytes)
01182 {
01183     palStatus_t status = PAL_SUCCESS;
01184     status = pal_plat_getRandomBufferFromHW(randomBuf, bufSizeBytes, actualRandomSizeBytes);
01185     return status;
01186 }
01187 
01188 #if (PAL_USE_HW_RTC)
01189 #include <linux/rtc.h>
01190 #include <sys/ioctl.h>
01191 #include <time.h>
01192 palMutexID_t rtcMutex = NULLPTR;
01193 
01194 #if RTC_PRIVILEGE
01195 static const char default_rtc[] = "/dev/rtc0";
01196 
01197 PAL_PRIVATE  uint64_t pal_convertTimeStructToSeconds(const struct rtc_time *dateTime)
01198 {
01199     /* Number of days from begin of the non Leap-year*/
01200     uint64_t monthDays[] = {0, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
01201     uint64_t seconds, daysCount = 0;
01202     /* Compute number of days from 1970 till given year*/
01203     daysCount = (dateTime->tm_year + 1900 - 1970) * PAL_DAYS_IN_A_YEAR;
01204     /* Add leap year days */
01205     daysCount += (((dateTime->tm_year + 1900) / 4) - (1970U / 4));
01206     /* Add number of days till given month*/
01207     daysCount += monthDays[dateTime->tm_mon];
01208     /* Add days in given month minus one */
01209     daysCount += (dateTime->tm_mday - 1);
01210     if (!(((dateTime->tm_year + 1900) & 3U)) && (dateTime->tm_mon <= 2U))
01211     {
01212         daysCount--;
01213     }
01214 
01215     seconds = (daysCount * PAL_SECONDS_PER_DAY) + (dateTime->tm_hour * PAL_SECONDS_PER_HOUR) +
01216               (dateTime->tm_min * PAL_SECONDS_PER_MIN) + dateTime->tm_sec;
01217 
01218     return seconds;
01219 }
01220 #endif
01221 
01222 palStatus_t pal_plat_osGetRtcTime(uint64_t *rtcGetTime)
01223 {
01224     palStatus_t ret = PAL_SUCCESS;
01225 #if RTC_PRIVILEGE
01226     struct rtc_time GetTime ={0};
01227     if(rtcGetTime != NULL)
01228     {
01229         int fd, retval = 0;
01230         fd = open(default_rtc, O_RDONLY);
01231         if (fd == -1)
01232         {
01233             ret = PAL_ERR_RTOS_RTC_OPEN_DEVICE_ERROR;
01234         }
01235         else
01236         {
01237             retval = ioctl(fd, RTC_RD_TIME , &GetTime);
01238             if (retval == -1)
01239             {
01240                 ret = PAL_ERR_RTOS_RTC_OPEN_IOCTL_ERROR;
01241             }
01242             else
01243             {
01244                 *rtcGetTime = pal_convertTimeStructToSeconds(&GetTime);
01245             }
01246             close(fd);
01247         }
01248     }
01249     else
01250     {
01251         ret = PAL_ERR_NULL_POINTER ;
01252     }
01253 #else
01254     *rtcGetTime = time(NULL);
01255 #endif
01256     return ret;
01257 }
01258 
01259 palStatus_t pal_plat_osSetRtcTime(uint64_t rtcSetTime)
01260 {
01261     palStatus_t ret = 0;
01262     int retval = 0;
01263 #if RTC_PRIVILEGE
01264     int fd = 0;
01265     int retval = 0;
01266     struct tm * convertedTime = gmtime((time_t*)&rtcSetTime);
01267 
01268     fd = open (default_rtc, O_RDONLY);
01269     retval = ioctl(fd, RTC_SET_TIME, (struct rtc_time*)convertedTime);
01270     if (retval == -1)
01271     {
01272         ret = PAL_ERR_RTOS_RTC_OPEN_IOCTL_ERROR;
01273     }
01274     close(fd);
01275 #else
01276     ret = pal_osMutexWait(rtcMutex, 5 * PAL_MILLI_PER_SECOND * PAL_ONE_SEC);
01277     if(ret == PAL_SUCCESS)
01278     {
01279         retval = stime((time_t*)&rtcSetTime);
01280         if (retval == -1)
01281         {
01282             ret = PAL_ERR_RTOS_NO_PRIVILEGED ; //need to give privilege mode "sudo setcap -v cap_sys_time=+epi [filename]"
01283         }
01284         pal_osMutexRelease(rtcMutex);
01285     }
01286 #endif
01287     return ret;
01288 }
01289 
01290 palStatus_t pal_plat_rtcInit(void)
01291 {
01292     palStatus_t ret = PAL_SUCCESS;
01293     if(NULLPTR == rtcMutex)
01294     {
01295         ret = pal_osMutexCreate(&rtcMutex);
01296     }
01297     return ret;
01298 }
01299 
01300 palStatus_t pal_plat_rtcDeInit(void)
01301 {
01302     palStatus_t ret = PAL_SUCCESS;
01303     if(NULLPTR != rtcMutex)
01304     {
01305         ret = pal_osMutexDelete(&rtcMutex);
01306         rtcMutex = NULLPTR;
01307     }
01308     return ret;
01309 }
01310 
01311 #endif //#if (PAL_USE_HW_RTC)
01312