Simple interface for Mbed Cloud Client

Dependents:  

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 #define _GNU_SOURCE // This is for ppoll found in poll.h
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  /*
00037  * The realtime clock is in nano seconds resolution. This is too much for us, so we use "longer" ticks.
00038  * Below are relevant defines.
00039  * make sure they all coherent. Can use one at the other, but will add some unneeded calculations.
00040  */
00041 #define NANOS_PER_TICK 100
00042 #define TICKS_PER_MICRO  10L
00043 #define TICKS_PER_MILLI  TICKS_PER_MICRO * 1000
00044 #define TICKS_PER_SECOND TICKS_PER_MILLI * 1000
00045 
00046 // priorities must be positive, so shift all by this margin. we might want to do smarter convert.
00047 #define LINUX_THREAD_PRIORITY_BASE 10
00048 
00049 //  message Queues names related staff:
00050 #define MQ_FILENAME_LEN 10
00051 
00052 #ifndef CLOCK_MONOTONIC_RAW //a workaround for the operWRT port that missing this include
00053 #define CLOCK_MONOTONIC_RAW 4 //http://elixir.free-electrons.com/linux/latest/source/include/uapi/linux/time.h
00054 #endif
00055 
00056 PAL_PRIVATE char g_mqName[MQ_FILENAME_LEN];
00057 PAL_PRIVATE int g_mqNextNameNum = 0;
00058 
00059 PAL_PRIVATE int16_t g_threadPriorityMap[PAL_NUMBER_OF_THREAD_PRIORITIES] = 
00060 { 
00061     7,  // PAL_osPriorityIdle
00062     8,  // PAL_osPriorityLow
00063     9,  // PAL_osPriorityReservedTRNG
00064     10, // PAL_osPriorityBelowNormal
00065     11, // PAL_osPriorityNormal
00066     12, // PAL_osPriorityAboveNormal
00067     13, // PAL_osPriorityReservedDNS
00068     14, // PAL_osPriorityReservedSockets
00069     15, // PAL_osPriorityHigh
00070     16, // PAL_osPriorityReservedHighResTimer
00071     17  // PAL_osPriorityRealtime
00072 };
00073 
00074 extern palStatus_t pal_plat_getRandomBufferFromHW(uint8_t *randomBuf, size_t bufSizeBytes, size_t* actualRandomSizeBytes);
00075 
00076 inline PAL_PRIVATE void nextMessageQName()
00077 {
00078     g_mqNextNameNum++;
00079     for (int j = 4, divider = 10000; j < 9; j++, divider /= 10)
00080     {
00081         g_mqName[j] = '0' + (g_mqNextNameNum / divider) %10 ; //just to make sure we don't write more then 1 digit.
00082     }
00083     g_mqName[9] = '\0';
00084 }
00085 
00086 
00087 /*! Initiate a system reboot.
00088  */
00089 void pal_plat_osReboot (void)
00090 {
00091     // Reboot the device
00092     reboot(RB_AUTOBOOT);
00093 }
00094 
00095 /*! Initialize all data structures (semaphores, mutexs, memory pools, message queues) at system initialization.
00096 *   In case of a failure in any of the initializations, the function returns with an error and stops the rest of the initializations.
00097 * @param[in] opaqueContext The context passed to the initialization (not required for generic CMSIS, pass NULL in this case).
00098 * \return PAL_SUCCESS(0) in case of success, PAL_ERR_CREATION_FAILED in case of failure.
00099 */
00100 palStatus_t pal_plat_RTOSInitialize (void* opaqueContext)
00101 {
00102     palStatus_t status = PAL_SUCCESS;
00103     (void)opaqueContext;
00104     strncpy(g_mqName, "/pal00001", MQ_FILENAME_LEN);
00105     g_mqNextNameNum = 1;   // used for the next name
00106 #if (PAL_USE_HW_RTC)
00107     status = pal_plat_rtcInit();
00108 #endif
00109     return status;
00110 }
00111 
00112 /*! De-Initialize thread objects.
00113  */
00114 palStatus_t pal_plat_RTOSDestroy (void)
00115 {
00116     palStatus_t ret = PAL_SUCCESS;
00117 #if PAL_USE_HW_RTC
00118     ret = pal_plat_rtcDeInit();
00119 #endif
00120     return ret;
00121 }
00122 
00123 /*return The RTOS kernel system timer counter, in microseconds
00124  */
00125 
00126 uint64_t pal_plat_osKernelSysTick (void) // optional API - not part of original CMSIS API.
00127 {
00128     /*Using clock_gettime is more accurate, but then we have to convert it to ticks. we are using a tick every 100 nanoseconds*/
00129     struct timespec ts;
00130     uint64_t ticks;
00131     //TODO: error handling
00132     clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
00133 
00134     ticks = (uint64_t) (ts.tv_sec * (uint64_t)TICKS_PER_SECOND
00135             + (ts.tv_nsec / NANOS_PER_TICK));
00136     return ticks;
00137 }
00138 
00139 /* Convert the value from microseconds to kernel sys ticks.
00140  * This is the same as CMSIS macro osKernelSysTickMicroSec.
00141  * since we return microsecods as ticks, just return the value
00142  */
00143 uint64_t pal_plat_osKernelSysTickMicroSec (uint64_t microseconds)
00144 {
00145 
00146     //convert to nanoseconds
00147     return microseconds * TICKS_PER_MICRO;
00148 }
00149 
00150 /*! Get the system tick frequency.
00151  * \return The system tick frequency.
00152  */
00153 inline uint64_t pal_plat_osKernelSysTickFrequency (void)
00154 {
00155     /* since we use clock_gettime, with resolution of 100 nanosecond per tick*/
00156     return TICKS_PER_SECOND;
00157 }
00158 
00159 void* threadFunction(void* arg)
00160 {
00161     palThreadServiceBridge_t* bridge = (palThreadServiceBridge_t*)arg;
00162     bridge->function(bridge->threadData );
00163     return NULL;
00164 }
00165 
00166 int16_t pal_plat_osThreadTranslatePriority (palThreadPriority_t priority)
00167 {
00168     return g_threadPriorityMap[priority];
00169 }
00170 
00171 palStatus_t pal_plat_osThreadDataInitialize (palThreadPortData* portData, int16_t priority, uint32_t stackSize)
00172 {
00173     return PAL_SUCCESS;
00174 }
00175 
00176 palStatus_t pal_plat_osThreadRun (palThreadServiceBridge_t* bridge, palThreadID_t* osThreadID)
00177 {
00178     palStatus_t status = PAL_SUCCESS;
00179     pthread_attr_t attr;
00180     pthread_attr_init(&attr);
00181     int err = pthread_attr_setstacksize(&attr, bridge->threadData ->stackSize );
00182     if (0 != err)
00183     {
00184         status = PAL_ERR_GENERIC_FAILURE;
00185         goto finish;
00186     }
00187     if (0 != pthread_attr_setschedpolicy(&attr, SCHED_RR))
00188     {
00189         status = PAL_ERR_GENERIC_FAILURE;
00190         goto finish;
00191     }
00192 #if (PAL_SIMULATOR_TEST_ENABLE == 0) //Disable ONLY for Linux PC simulator 
00193     if (0 != pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED))
00194     {
00195         status = PAL_ERR_GENERIC_FAILURE;
00196         goto finish;
00197     }
00198 #endif    
00199     if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
00200     {
00201         status = PAL_ERR_GENERIC_FAILURE;
00202         goto finish;
00203     }
00204 
00205     struct sched_param schedParam;
00206     schedParam.sched_priority = bridge->threadData ->osPriority ;
00207     if (0 != pthread_attr_setschedparam(&attr, &schedParam))
00208     {
00209         status = PAL_ERR_GENERIC_FAILURE;
00210         goto finish;
00211     }
00212 
00213     pthread_t threadID = (pthread_t)NULL;
00214     int retVal = pthread_create(&threadID, &attr, threadFunction, (void*)bridge);
00215     pthread_attr_destroy(&attr); // destroy the thread attributes object since it's no longer needed
00216     if (0 != retVal)
00217     {
00218         if (EPERM == retVal)
00219         {
00220             status = PAL_ERR_RTOS_PRIORITY ;
00221         }
00222         else
00223         {
00224             status = PAL_ERR_RTOS_RESOURCE ;
00225         }
00226         goto finish;
00227     }
00228 
00229     if (((palThreadID_t)PAL_INVALID_THREAD == threadID) || (0 == threadID))
00230     {
00231         status = PAL_ERR_GENERIC_FAILURE;
00232     }
00233     else
00234     {
00235         *osThreadID = (palThreadID_t)threadID;
00236     }
00237 
00238 finish:
00239     return status;
00240 }
00241 
00242 palStatus_t pal_plat_osThreadDataCleanup (palThreadData_t* threadData)
00243 {
00244     return PAL_SUCCESS;
00245 }
00246 
00247 palStatus_t pal_plat_osThreadTerminate (palThreadData_t* threadData)
00248 {
00249     palStatus_t status = PAL_ERR_RTOS_TASK ;
00250     int osStatus = 0;
00251     pthread_t threadID = (pthread_t)(threadData->osThreadID );
00252     if (pthread_self() != threadID) // terminate only if not trying to terminate from self
00253     {
00254         osStatus = pthread_cancel(threadID);
00255         if ((0 == osStatus) || (ESRCH == osStatus))
00256         {
00257             status = PAL_SUCCESS;
00258         }
00259         else
00260         {
00261             status = PAL_ERR_RTOS_RESOURCE ;
00262         }
00263     }
00264     return status;
00265 }
00266 
00267 palThreadID_t pal_plat_osThreadGetId (void)
00268 {
00269     palThreadID_t osThreadID = (palThreadID_t)pthread_self();
00270     return osThreadID;
00271 }
00272 
00273 /*! Wait for a specified period of time in milliseconds.
00274  *
00275  * @param[in] milliseconds The number of milliseconds to wait before proceeding.
00276  *
00277  * \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.
00278  */
00279 palStatus_t pal_plat_osDelay (uint32_t milliseconds)
00280 {
00281     struct timespec sTime;
00282     struct timespec rTime; // this will return how much sleep time still left in case of interrupted sleep
00283     int stat;
00284     //init rTime, as we will copy it over to stime inside the do-while loop.
00285     rTime.tv_sec = milliseconds / 1000;
00286     rTime.tv_nsec = PAL_MILLI_TO_NANO(milliseconds);
00287 
00288     do
00289     {
00290         sTime.tv_sec = rTime.tv_sec;
00291         sTime.tv_nsec = rTime.tv_nsec;
00292         stat = nanosleep(&sTime, &rTime);
00293     } while ((-1 == stat) && (EINTR ==errno)) ;
00294     return (stat == 0) ? PAL_SUCCESS : PAL_ERR_GENERIC_FAILURE;
00295 }
00296 
00297 /*
00298  * Internal struct to handle timers.
00299  */
00300 
00301 struct palTimerInfo
00302 {
00303     timer_t handle;
00304     palTimerFuncPtr function;
00305     void *funcArgs;
00306     palTimerType_t timerType;
00307     bool isHighRes;
00308 };
00309 
00310 /*
00311  * internal function used to handle timers expiration events.
00312  */
00313 PAL_PRIVATE void palTimerEventHandler(void* args)
00314 {
00315     struct palTimerInfo* timer = (struct palTimerInfo *) args;
00316 
00317     if (NULL == timer)
00318     { // no timer anymore, so just return.
00319         return;
00320     }
00321 
00322     //call the callback function
00323     timer->function(timer->funcArgs);
00324 }
00325 
00326 
00327 /*
00328 * Internal struct to handle timers.
00329 */
00330 
00331 #define PAL_HIGH_RES_TIMER_THRESHOLD_MS 100
00332 
00333 typedef struct palHighResTimerThreadContext
00334 {
00335     palTimerFuncPtr function;
00336     void *funcArgs;
00337     uint32_t intervalMS;
00338 } palHighResTimerThreadContext_t;
00339 
00340 
00341 static palThreadID_t s_palHighResTimerThreadID = NULLPTR;
00342 static bool s_palHighResTimerThreadInUse =  0;
00343 static palHighResTimerThreadContext_t s_palHighResTimerThreadContext = {0};
00344 
00345 /*
00346 *  callback for handling high precision timer callbacks (currently only one is supported)
00347 */
00348 
00349 PAL_PRIVATE void palHighResTimerThread(void const *args)
00350 {
00351     palHighResTimerThreadContext_t* context = (palHighResTimerThreadContext_t*)args;
00352     uint32_t timer_period_ms = context->intervalMS;
00353     int err = 0;
00354     struct timespec next_timeout_ts;
00355     err = clock_gettime(CLOCK_MONOTONIC, &next_timeout_ts);
00356     assert(err == 0);
00357 
00358     while(1) {
00359         // Determine absolute time we want to sleep until
00360         next_timeout_ts.tv_nsec += PAL_NANO_PER_MILLI * timer_period_ms;
00361         if (next_timeout_ts.tv_nsec >= PAL_NANO_PER_SECOND) 
00362         {
00363             next_timeout_ts.tv_nsec = next_timeout_ts.tv_nsec - PAL_NANO_PER_SECOND;
00364             next_timeout_ts.tv_sec += 1;
00365         }
00366 
00367         // Call nanosleep until error or no interrupt, ie. return code is 0
00368         do {
00369             err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_timeout_ts, NULL);
00370             assert(err == 0 || err == EINTR);
00371         } while(err == EINTR);
00372 
00373         // Done sleeping, call callback
00374         context->function(context->funcArgs);
00375     }
00376 }
00377 
00378 PAL_PRIVATE palStatus_t startHighResTimerThread(palTimerFuncPtr function, void *funcArgs , uint32_t intervalMS)
00379 {
00380     s_palHighResTimerThreadContext.function = function;
00381     s_palHighResTimerThreadContext.funcArgs = funcArgs;
00382     s_palHighResTimerThreadContext.intervalMS = intervalMS;
00383     palStatus_t status = pal_osThreadCreateWithAlloc(palHighResTimerThread, &s_palHighResTimerThreadContext, PAL_osPriorityReservedHighResTimer,
00384         PAL_RTOS_HIGH_RES_TIMER_THREAD_STACK_SIZE, NULL, &s_palHighResTimerThreadID);
00385     return status;
00386 }
00387 
00388 
00389 /*! Create a timer.
00390  *
00391  * @param[in] function A function pointer to the timer callback function.
00392  * @param[in] funcArgument An argument for the timer callback function.
00393  * @param[in] timerType The timer type to be created, periodic or oneShot.
00394  * @param[out] timerID The ID of the created timer, zero value indicates an error.
00395  *
00396  * \return PAL_SUCCESS when the timer was created successfully. A specific error in case of failure.
00397  */
00398 palStatus_t pal_plat_osTimerCreate (palTimerFuncPtr function, void* funcArgument,
00399         palTimerType_t timerType, palTimerID_t* timerID)
00400 {
00401 
00402     palStatus_t status = PAL_SUCCESS;
00403     struct palTimerInfo* timerInfo = NULL;
00404     {
00405         struct sigevent sig;
00406         timer_t localTimer;
00407 
00408         if ((NULL == timerID) || (NULL == (void*) function))
00409         {
00410             return PAL_ERR_INVALID_ARGUMENT ;
00411         }
00412 
00413         timerInfo = (struct palTimerInfo*) malloc(sizeof(struct palTimerInfo));
00414         if (NULL == timerInfo)
00415         {
00416             status = PAL_ERR_NO_MEMORY ;
00417             goto finish;
00418         }
00419 
00420         timerInfo->function = function;
00421         timerInfo->funcArgs = funcArgument;
00422         timerInfo->timerType = timerType;
00423         timerInfo->isHighRes = false;
00424 
00425         memset(&sig, 0, sizeof(sig));
00426 
00427         sig.sigev_notify = SIGEV_THREAD;
00428         sig.sigev_signo = 0;
00429         sig.sigev_value.sival_ptr = timerInfo;
00430         sig.sigev_notify_function = (void (*)(union sigval)) palTimerEventHandler;
00431 
00432         int ret = timer_create(CLOCK_MONOTONIC, &sig, &localTimer);
00433         if (-1 == ret)
00434         {
00435             if (EINVAL == errno)
00436             {
00437                 status = PAL_ERR_INVALID_ARGUMENT ;
00438                 goto finish;
00439             }
00440             if (ENOMEM == errno)
00441             {
00442                 status = PAL_ERR_NO_MEMORY ;
00443                 goto finish;
00444             }
00445             PAL_LOG(ERR, "Rtos timer create error %d", ret);
00446             status = PAL_ERR_GENERIC_FAILURE;
00447             goto finish;
00448         }
00449 
00450         // managed to create the timer - finish up
00451         timerInfo->handle = localTimer;
00452         *timerID = (palTimerID_t) timerInfo;
00453     }
00454     finish: if (PAL_SUCCESS != status)
00455     {
00456         if (NULL != timerInfo)
00457         {
00458             free(timerInfo);
00459             *timerID = (palTimerID_t) NULL;
00460         }
00461     }
00462     return status;
00463 }
00464 
00465 /* Convert milliseconds into seconds and nanoseconds inside a timespec struct
00466  */
00467 PAL_PRIVATE void convertMilli2Timespec(uint32_t millisec, struct timespec* ts)
00468 {
00469     ts->tv_sec = millisec / 1000;
00470     ts->tv_nsec = PAL_MILLI_TO_NANO(millisec);
00471 }
00472 
00473 /*! Start or restart a timer.
00474  *
00475  * @param[in] timerID The handle for the timer to start.
00476  * @param[in] millisec The time in milliseconds to set the timer to.
00477  *
00478  * \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.
00479  */
00480 palStatus_t pal_plat_osTimerStart (palTimerID_t timerID, uint32_t millisec)
00481 {
00482     palStatus_t status = PAL_SUCCESS;
00483     if (NULL == (struct palTimerInfo *) timerID)
00484     {
00485         return PAL_ERR_INVALID_ARGUMENT ;
00486     }
00487 
00488     struct palTimerInfo* timerInfo = (struct palTimerInfo *) timerID;
00489     struct itimerspec its;
00490 
00491 
00492     if ((millisec <= PAL_HIGH_RES_TIMER_THRESHOLD_MS) && (palOsTimerPeriodic  == timerInfo->timerType )) // periodic high res timer  - we only support 1 (workaround for issue when lots of threads are created in linux)
00493     {
00494         if (true == s_palHighResTimerThreadInUse)
00495         {
00496             status = PAL_ERR_NO_HIGH_RES_TIMER_LEFT;
00497         }
00498         else
00499         {
00500             status = startHighResTimerThread(timerInfo->function, timerInfo->funcArgs, millisec);
00501             if (PAL_SUCCESS == status)
00502             {
00503                 timerInfo->isHighRes = true;
00504                 s_palHighResTimerThreadInUse = true;
00505             }
00506         }
00507     }
00508     else // otherwise handle normally
00509     {
00510         convertMilli2Timespec(millisec, &(its.it_value));
00511 
00512         if (palOsTimerPeriodic  == timerInfo->timerType)
00513         {
00514             convertMilli2Timespec(millisec, &(its.it_interval));
00515         }
00516         else
00517         {  // one time timer
00518             convertMilli2Timespec(0, &(its.it_interval));
00519         }
00520 
00521         if (-1 == timer_settime(timerInfo->handle, 0, &its, NULL))
00522         {
00523             status = PAL_ERR_INVALID_ARGUMENT ;
00524         }
00525     }
00526 
00527     return status;
00528 }
00529 
00530 /*! Stop a timer.
00531  *
00532  * @param[in] timerID The handle for the timer to stop.
00533  *
00534  * \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.
00535  */
00536 palStatus_t pal_plat_osTimerStop (palTimerID_t timerID)
00537 {
00538     palStatus_t status = PAL_SUCCESS;
00539     if (NULL == (struct palTimerInfo *) timerID)
00540     {
00541         return PAL_ERR_INVALID_ARGUMENT ;
00542     }
00543 
00544     struct palTimerInfo* timerInfo = (struct palTimerInfo *) timerID;
00545     struct itimerspec its;
00546 
00547     if ((true == timerInfo->isHighRes) && (0 != s_palHighResTimerThreadInUse )) // if  high res timer clean up thread.
00548     {
00549         status = pal_osThreadTerminate(&s_palHighResTimerThreadID);
00550         if (PAL_SUCCESS == status)
00551         {
00552             timerInfo->isHighRes = false;
00553             s_palHighResTimerThreadInUse = false;
00554         }
00555     }
00556     else // otherwise process normally
00557     {
00558         // set timer to 0 to disarm it.
00559         convertMilli2Timespec(0, &(its.it_value));
00560 
00561         convertMilli2Timespec(0, &(its.it_interval));
00562 
00563         if (-1 == timer_settime(timerInfo->handle, 0, &its, NULL))
00564         {
00565             status = PAL_ERR_INVALID_ARGUMENT ;
00566         }
00567     }
00568 
00569     return status;
00570 }
00571 
00572 /*! Delete the timer object
00573  *
00574  * @param[inout] timerID The handle for the timer to delete. In success, *timerID = NULL.
00575  *
00576  * \return PAL_SUCCESS when the timer was deleted successfully, PAL_ERR_RTOS_PARAMETER when the timerID is incorrect.
00577  */
00578 palStatus_t pal_plat_osTimerDelete (palTimerID_t* timerID)
00579 {
00580     palStatus_t status = PAL_SUCCESS, tempStatus;
00581     if (NULL == timerID)
00582     {
00583         return PAL_ERR_INVALID_ARGUMENT ;
00584     }
00585     struct palTimerInfo* timerInfo = (struct palTimerInfo *) *timerID;
00586     if (NULL == timerInfo)
00587     {
00588         status = PAL_ERR_RTOS_PARAMETER ;
00589     }
00590 
00591     if ((PAL_SUCCESS == status) && (true == timerInfo->isHighRes) && (0 != s_palHighResTimerThreadInUse)) //  if high res timer delted before stopping => clean up thread.
00592     {
00593         tempStatus = pal_osThreadTerminate(&s_palHighResTimerThreadID);
00594         if (PAL_SUCCESS == tempStatus)
00595         {
00596             timerInfo->isHighRes = false;
00597             s_palHighResTimerThreadInUse = false;
00598         }
00599         else
00600         {
00601             status = tempStatus;
00602         }
00603     }
00604 
00605     if (PAL_SUCCESS == status)
00606     {
00607         timer_t lt = timerInfo->handle;
00608         if (-1 == timer_delete(lt))
00609         {
00610             status = PAL_ERR_RTOS_RESOURCE ;
00611         }
00612 
00613         free(timerInfo);
00614         *timerID = (palTimerID_t) NULL;
00615     }
00616     return status;
00617 }
00618 
00619 /*! Create and initialize a mutex object.
00620  *
00621  * @param[out] mutexID The created mutex ID handle, zero value indicates an error.
00622  *
00623  * \return PAL_SUCCESS when the mutex was created successfully, a specific error in case of failure.
00624  */
00625 palStatus_t pal_plat_osMutexCreate (palMutexID_t* mutexID)
00626 {
00627     palStatus_t status = PAL_SUCCESS;
00628     pthread_mutex_t* mutex = NULL;
00629     {
00630         int ret;
00631         if (NULL == mutexID)
00632         {
00633             return PAL_ERR_INVALID_ARGUMENT ;
00634         }
00635 
00636         mutex = malloc(sizeof(pthread_mutex_t));
00637         if (NULL == mutex)
00638         {
00639             status = PAL_ERR_NO_MEMORY ;
00640             goto finish;
00641         }
00642 
00643         pthread_mutexattr_t mutexAttr;
00644         pthread_mutexattr_init(&mutexAttr);
00645         pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE);
00646         ret = pthread_mutex_init(mutex, &mutexAttr);
00647 
00648         if (0 != ret)
00649         {
00650             if (ENOMEM == ret)
00651             {
00652                 status = PAL_ERR_NO_MEMORY ;
00653             }
00654             else
00655             {
00656                 PAL_LOG(ERR, "Rtos mutex create status %d", ret);
00657                 status = PAL_ERR_GENERIC_FAILURE;
00658             }
00659             goto finish;
00660         }
00661         *mutexID = (palMutexID_t) mutex;
00662     }
00663     finish: if (PAL_SUCCESS != status)
00664     {
00665         if (NULL != mutex)
00666         {
00667             free(mutex);
00668         }
00669     }
00670     return status;
00671 }
00672 
00673 /* Wait until a mutex becomes available.
00674  *
00675  * @param[in] mutexID The handle for the mutex.
00676  * @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.
00677  *
00678  * \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:
00679  *        PAL_ERR_RTOS_RESOURCE - Mutex not available but no timeout set.
00680  *        PAL_ERR_RTOS_TIMEOUT - Mutex was not available until timeout expired.
00681  *        PAL_ERR_RTOS_PARAMETER - Mutex ID is invalid.
00682  *        PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines.
00683  */
00684 palStatus_t pal_plat_osMutexWait (palMutexID_t mutexID, uint32_t millisec)
00685 {
00686     palStatus_t status = PAL_SUCCESS;
00687     int err;
00688     if (NULL == ((pthread_mutex_t*) mutexID))
00689     {
00690         return PAL_ERR_INVALID_ARGUMENT ;
00691     }
00692     pthread_mutex_t* mutex = (pthread_mutex_t*) mutexID;
00693 
00694     if (PAL_RTOS_WAIT_FOREVER != millisec)
00695     {
00696         /* calculate the wait absolute time */
00697         struct timespec ts;
00698         clock_gettime(CLOCK_REALTIME, &ts);
00699 
00700         ts.tv_sec += (millisec / PAL_MILLI_PER_SECOND);
00701         ts.tv_nsec += PAL_MILLI_TO_NANO(millisec);
00702         ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; // if there is some overflow in the addition of nanoseconds.
00703         ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND;
00704 
00705         while ((err = pthread_mutex_timedlock(mutex, &ts)) != 0 && err == EINTR)
00706         {
00707             continue; /* Restart if interrupted by handler */
00708         }
00709     }
00710     else
00711     { // wait for ever
00712         err = pthread_mutex_lock(mutex);
00713     }
00714 
00715     if (0 != err)
00716     {
00717         if (err == ETIMEDOUT)
00718         {
00719             status = PAL_ERR_RTOS_TIMEOUT ;
00720         }
00721         else
00722         {
00723             PAL_LOG(ERR, "Rtos mutex wait status %d", err);
00724             status = PAL_ERR_GENERIC_FAILURE;
00725         }
00726     }
00727 
00728     return status;
00729 }
00730 
00731 /* Release a mutex that was obtained by osMutexWait.
00732  *
00733  * @param[in] mutexID The handle for the mutex.
00734  *
00735  * \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.
00736  */
00737 palStatus_t pal_plat_osMutexRelease (palMutexID_t mutexID)
00738 {
00739     palStatus_t status = PAL_SUCCESS;
00740     int result = 0;
00741 
00742     pthread_mutex_t* mutex = (pthread_mutex_t*) mutexID;
00743     if (NULL == mutex)
00744     {
00745         return PAL_ERR_INVALID_ARGUMENT ;
00746     }
00747 
00748     result = pthread_mutex_unlock(mutex);
00749     if (0 != result)
00750     {
00751         // only reason this might fail - process don't have permission for mutex.
00752         PAL_LOG(ERR, "Rtos mutex release failure - %d",result);
00753         status = PAL_ERR_GENERIC_FAILURE;
00754     }
00755     return status;
00756 }
00757 
00758 /*Delete a mutex object.
00759  *
00760  * @param[inout] mutexID The ID of the mutex to delete. In success, *mutexID = NULL.
00761  *
00762  * \return PAL_SUCCESS when the mutex was deleted successfully, one of the following error codes in case of failure:
00763  *        PAL_ERR_RTOS_RESOURCE - Mutex already released.
00764  *        PAL_ERR_RTOS_PARAMETER - Mutex ID is invalid.
00765  *        PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines.
00766  * \note After this call, mutex_id is no longer valid and cannot be used.
00767  */
00768 palStatus_t pal_plat_osMutexDelete (palMutexID_t* mutexID)
00769 {
00770     palStatus_t status = PAL_SUCCESS;
00771     uint32_t ret;
00772     if (NULL == mutexID)
00773     {
00774         return PAL_ERR_INVALID_ARGUMENT ;
00775     }
00776     pthread_mutex_t* mutex = (pthread_mutex_t*) *mutexID;
00777 
00778     if (NULL == mutex)
00779     {
00780         status = PAL_ERR_RTOS_RESOURCE ;
00781     }
00782     ret = pthread_mutex_destroy(mutex);
00783     if ((PAL_SUCCESS == status) && (0 != ret))
00784     {
00785         PAL_LOG(ERR,"pal_plat_osMutexDelete 0x%x",ret);
00786         status = PAL_ERR_RTOS_RESOURCE ;
00787     }
00788     if (NULL != mutex)
00789     {
00790         free(mutex);
00791     }
00792 
00793     *mutexID = (palMutexID_t) NULL;
00794     return status;
00795 }
00796 
00797 /* Create and initialize a semaphore object.
00798  *
00799  * Semaphore is shared between threads, but not process.
00800  *
00801  * @param[in] count The number of available resources.
00802  * @param[out] semaphoreID The ID of the created semaphore, zero value indicates an error.
00803  *
00804  * \return PAL_SUCCESS when the semaphore was created successfully, a specific error in case of failure.
00805  */
00806 palStatus_t pal_plat_osSemaphoreCreate (uint32_t count,
00807         palSemaphoreID_t* semaphoreID)
00808 {
00809     palStatus_t status = PAL_SUCCESS;
00810     sem_t* semaphore = NULL;
00811 
00812     {
00813         if (NULL == semaphoreID)
00814         {
00815             return PAL_ERR_INVALID_ARGUMENT ;
00816         }
00817         semaphore = malloc(sizeof(sem_t));
00818         if (NULL == semaphore)
00819         {
00820             status = PAL_ERR_NO_MEMORY ;
00821             goto finish;
00822         }
00823         /* create the semaphore as shared between threads */
00824         int ret = sem_init(semaphore, 0, count);
00825         if (-1 == ret)
00826         {
00827             if (EINVAL == errno)
00828             {
00829                 /* count is too big */
00830                 status = PAL_ERR_INVALID_ARGUMENT ;
00831             }
00832             else
00833             {
00834                 PAL_LOG(ERR, "Rtos semaphore init error %d", ret);
00835                 status = PAL_ERR_GENERIC_FAILURE;
00836             }
00837             goto finish;
00838         }
00839 
00840         *semaphoreID = (palSemaphoreID_t) semaphore;
00841     }
00842     finish: if (PAL_SUCCESS != status)
00843     {
00844         if (NULL != semaphore)
00845         {
00846             free(semaphore);
00847         }
00848         *semaphoreID = (palSemaphoreID_t) NULL;
00849     }
00850     return status;
00851 }
00852 
00853 /* Wait until a semaphore token becomes available.
00854  *
00855  * @param[in] semaphoreID The handle for the semaphore.
00856  * @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.
00857  * @param[out] countersAvailable The number of semaphores available (before the wait), if semaphores are not available (timeout/error) zero is returned.
00858  *
00859  * \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:
00860  *      PAL_ERR_RTOS_TIMEOUT - Semaphore was not available until timeout expired.
00861  *      PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid.
00862  *      PAL_ERR_INVALID_ARGUMENT - countersAvailable is NULL
00863  *
00864  *      NOTES: 1. counterAvailable returns 0 in case there are no semaphores available or there are other threads waiting on it.
00865  *                Value is not thread safe - it might be changed by the time it is read/returned.
00866  *             2. timed wait is using absolute time.
00867  */
00868 palStatus_t pal_plat_osSemaphoreWait (palSemaphoreID_t semaphoreID,
00869         uint32_t millisec, int32_t* countersAvailable)
00870 {
00871     palStatus_t status = PAL_SUCCESS;
00872     int tmpCounters = 0;
00873     {
00874         int err;
00875         sem_t* sem = (sem_t*) semaphoreID;
00876         if ((NULL == sem))
00877         {
00878             return PAL_ERR_INVALID_ARGUMENT ;
00879         }
00880 
00881         if (PAL_RTOS_WAIT_FOREVER != millisec)
00882         {
00883             /* calculate the wait absolute time */
00884             struct timespec ts;
00885             clock_gettime(CLOCK_REALTIME, &ts);
00886             ts.tv_sec += millisec / PAL_MILLI_PER_SECOND;
00887             ts.tv_nsec += PAL_MILLI_TO_NANO(millisec);
00888             ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; // in case there is overflow in the nanoseconds.
00889             ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND;
00890 
00891             while ((err = sem_timedwait(sem, &ts)) == -1 && errno == EINTR)
00892                 continue; /* Restart if interrupted by handler */
00893         }
00894         else
00895         { // wait for ever
00896             do
00897             {
00898                 err = sem_wait(sem);
00899 
00900                 /* loop again if the wait was interrupted by a signal */
00901             } while ((err == -1) && (errno == EINTR));
00902         }
00903 
00904         if (-1 == err)
00905         {
00906             tmpCounters = 0;
00907             if (errno == ETIMEDOUT)
00908             {
00909                 status = PAL_ERR_RTOS_TIMEOUT ;
00910             }
00911             else
00912             { /* seems this is not a valid semaphore */
00913                 status = PAL_ERR_RTOS_PARAMETER ;
00914             }
00915             goto finish;
00916         }
00917         /* get the counter number, shouldn't fail, as we already know this is valid semaphore */
00918         sem_getvalue(sem, &tmpCounters);
00919     }
00920     finish:
00921     if (NULL != countersAvailable)
00922     {
00923         *countersAvailable = tmpCounters;
00924     }
00925     return status;
00926 }
00927 
00928 /*! Release a semaphore token.
00929  *
00930  * @param[in] semaphoreID The handle for the semaphore.
00931  *
00932  * \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.
00933  */
00934 palStatus_t pal_plat_osSemaphoreRelease (palSemaphoreID_t semaphoreID)
00935 {
00936     palStatus_t status = PAL_SUCCESS;
00937     sem_t* sem = (sem_t*) semaphoreID;
00938 
00939     if (NULL == sem)
00940     {
00941         return PAL_ERR_INVALID_ARGUMENT ;
00942     }
00943 
00944     if (-1 == sem_post(sem))
00945     {
00946         if (EINVAL == errno)
00947         {
00948             status = PAL_ERR_RTOS_PARAMETER ;
00949         }
00950         else
00951         { /* max value of semaphore exeeded */
00952             PAL_LOG(ERR, "Rtos semaphore release error %d", errno);
00953             status = PAL_ERR_GENERIC_FAILURE;
00954         }
00955     }
00956 
00957     return status;
00958 }
00959 
00960 /*! Delete a semaphore object.
00961  *
00962  * @param[inout] semaphoreID: The ID of the semaphore to delete. In success, *semaphoreID = NULL.
00963  *
00964  * \return PAL_SUCCESS when the semaphore was deleted successfully, one of the following error codes in case of failure:
00965  *        PAL_ERR_RTOS_RESOURCE - Semaphore already released.
00966  *        PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid.
00967  * \note After this call, the semaphore_id is no longer valid and cannot be used.
00968  */
00969 palStatus_t pal_plat_osSemaphoreDelete (palSemaphoreID_t* semaphoreID)
00970 {
00971     palStatus_t status = PAL_SUCCESS;
00972     {
00973         if (NULL == semaphoreID)
00974         {
00975             return PAL_ERR_INVALID_ARGUMENT ;
00976         }
00977 
00978         sem_t* sem = (sem_t*) (*semaphoreID);
00979         if (NULL == sem)
00980         {
00981             status = PAL_ERR_RTOS_RESOURCE ;
00982             goto finish;
00983         }
00984         if (-1 == sem_destroy(sem))
00985         {
00986             status = PAL_ERR_RTOS_PARAMETER ;
00987             goto finish;
00988         }
00989 
00990         if (NULL != sem)
00991         {
00992             free(sem);
00993         }
00994         *semaphoreID = (palSemaphoreID_t) NULL;
00995     }
00996     finish: return status;
00997 }
00998 
00999 /*! Perform an atomic increment for a signed32 bit value.
01000  *
01001  * @param[in,out] valuePtr The address of the value to increment.
01002  * @param[in] increment The number by which to increment.
01003  *
01004  * \returns The value of the valuePtr after the increment operation.
01005  */
01006 int32_t pal_plat_osAtomicIncrement (int32_t* valuePtr, int32_t increment)
01007 {
01008     int32_t res = __sync_add_and_fetch(valuePtr, increment);
01009     return res;
01010 }
01011 
01012 
01013 void *pal_plat_malloc (size_t len)
01014 {
01015     return malloc(len);
01016 }
01017 
01018 
01019 void pal_plat_free (void * buffer)
01020 {
01021     return free(buffer);
01022 }
01023 
01024 palStatus_t pal_plat_osRandomBuffer (uint8_t *randomBuf, size_t bufSizeBytes, size_t* actualRandomSizeBytes)
01025 {
01026     palStatus_t status = PAL_SUCCESS;
01027     status = pal_plat_getRandomBufferFromHW(randomBuf, bufSizeBytes, actualRandomSizeBytes);
01028     return status;
01029 }
01030 
01031 #if (PAL_USE_HW_RTC)
01032 #include <linux/rtc.h>
01033 #include <sys/ioctl.h>
01034 #include <time.h>
01035 palMutexID_t rtcMutex = NULLPTR;
01036 
01037 #if RTC_PRIVILEGE
01038 static const char default_rtc[] = "/dev/rtc0";
01039 
01040 PAL_PRIVATE  uint64_t pal_convertTimeStructToSeconds(const struct rtc_time *dateTime)
01041 {
01042     /* Number of days from begin of the non Leap-year*/
01043     uint64_t monthDays[] = {0, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
01044     uint64_t seconds, daysCount = 0;
01045     /* Compute number of days from 1970 till given year*/
01046     daysCount = (dateTime->tm_year + 1900 - 1970) * PAL_DAYS_IN_A_YEAR;
01047     /* Add leap year days */
01048     daysCount += (((dateTime->tm_year + 1900) / 4) - (1970U / 4));
01049     /* Add number of days till given month*/
01050     daysCount += monthDays[dateTime->tm_mon];
01051     /* Add days in given month minus one */
01052     daysCount += (dateTime->tm_mday - 1);
01053     if (!(((dateTime->tm_year + 1900) & 3U)) && (dateTime->tm_mon <= 2U))
01054     {
01055         daysCount--;
01056     }
01057 
01058     seconds = (daysCount * PAL_SECONDS_PER_DAY) + (dateTime->tm_hour * PAL_SECONDS_PER_HOUR) +
01059               (dateTime->tm_min * PAL_SECONDS_PER_MIN) + dateTime->tm_sec;
01060 
01061     return seconds;
01062 }
01063 #endif
01064 
01065 palStatus_t pal_plat_osGetRtcTime(uint64_t *rtcGetTime)
01066 {
01067     palStatus_t ret = PAL_SUCCESS;
01068 #if RTC_PRIVILEGE
01069     struct rtc_time GetTime ={0};
01070     if(rtcGetTime != NULL)
01071     {
01072         int fd, retval = 0;
01073         fd = open(default_rtc, O_RDONLY);
01074         if (fd == -1)
01075         {
01076             ret = PAL_ERR_RTOS_RTC_OPEN_DEVICE_ERROR;
01077         }
01078         else
01079         {
01080             retval = ioctl(fd, RTC_RD_TIME , &GetTime);
01081             if (retval == -1)
01082             {
01083                 ret = PAL_ERR_RTOS_RTC_OPEN_IOCTL_ERROR ;
01084             }
01085             else
01086             {
01087                 *rtcGetTime = pal_convertTimeStructToSeconds(&GetTime);
01088             }
01089             close(fd);
01090         }
01091     }
01092     else
01093     {
01094         ret = PAL_ERR_NULL_POINTER ;
01095     }
01096 #else
01097     *rtcGetTime = time(NULL);
01098 #endif
01099     return ret;
01100 }
01101 
01102 palStatus_t pal_plat_osSetRtcTime(uint64_t rtcSetTime)
01103 {
01104     palStatus_t ret = 0;
01105     int retval = 0;
01106 #if RTC_PRIVILEGE
01107     int fd = 0;
01108     int retval = 0;
01109     struct tm * convertedTime = gmtime((time_t*)&rtcSetTime);
01110 
01111     fd = open (default_rtc, O_RDONLY);
01112     retval = ioctl(fd, RTC_SET_TIME, (struct rtc_time*)convertedTime);
01113     if (retval == -1)
01114     {
01115         ret = PAL_ERR_RTOS_RTC_OPEN_IOCTL_ERROR ;
01116     }
01117     close(fd);
01118 #else
01119     ret = pal_osMutexWait(rtcMutex, 5 * PAL_MILLI_PER_SECOND * PAL_ONE_SEC);
01120     if(ret == PAL_SUCCESS)
01121     {
01122         retval = stime((time_t*)&rtcSetTime);
01123         if (retval == -1)
01124         {
01125             ret = PAL_ERR_RTOS_NO_PRIVILEGED; //need to give privilege mode "sudo setcap -v cap_sys_time=+epi [filename]"
01126         }
01127         pal_osMutexRelease(rtcMutex);
01128     }
01129 #endif
01130     return ret;
01131 }
01132 
01133 palStatus_t pal_plat_rtcInit(void)
01134 {
01135     palStatus_t ret = PAL_SUCCESS;
01136     if(NULLPTR == rtcMutex)
01137     {
01138         ret = pal_osMutexCreate(&rtcMutex);
01139     }
01140     return ret;
01141 }
01142 
01143 palStatus_t pal_plat_rtcDeInit(void)
01144 {
01145     palStatus_t ret = PAL_SUCCESS;
01146     if(NULLPTR != rtcMutex)
01147     {
01148         ret = pal_osMutexDelete(&rtcMutex);
01149         rtcMutex = NULLPTR;
01150     }
01151     return ret;
01152 }
01153 
01154 #endif //#if (PAL_USE_HW_RTC)
01155