Mbed Cloud example program for workshop in W27 2018.

Dependencies:   MMA7660 LM75B

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pal_plat_rtos.c Source File

pal_plat_rtos.c

00001 /*
00002  * Copyright (c) 2016 ARM Limited. All rights reserved.
00003  * SPDX-License-Identifier: Apache-2.0
00004  * Licensed under the Apache License, Version 2.0 (the License); you may
00005  * 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, WITHOUT
00012  * 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 
00038 typedef struct palThreadFuncWrapper
00039 {
00040     palTimerFuncPtr realThreadFunc;
00041     void* realThreadArgs;
00042     uint32_t threadIndex;
00043 } palThreadFuncWrapper_t;
00044 
00045 //! Thread structure
00046 typedef struct palThread
00047 {
00048     pthread_t  threadID;
00049     uint32_t   palThreadID;
00050     bool initialized;
00051     palThreadLocalStore_t* threadStore; //! please see pal_rtos.h for documentation
00052     palThreadFuncWrapper_t threadFuncWrapper;
00053     palThreadPriority_t priority;
00054     uint32_t stackSize;
00055 } palThread_t;
00056 
00057 /*! Count number of created threads. Initiate to zero.
00058 */
00059 PAL_PRIVATE uint32_t g_threadCounter = 0;
00060 
00061 palThread_t g_palThreads[PAL_MAX_NUMBER_OF_THREADS];
00062 
00063 /*
00064  * The realtime clock is in nano seconds resolution. This is too much for us, so we use "longer" ticks.
00065  * Below are relevant defines.
00066  * make sure they all coherent. Can use one at the other, but will add some unneeded calculations.
00067  */
00068 #define NANOS_PER_TICK 100
00069 #define TICKS_PER_MICRO  10L
00070 #define TICKS_PER_MILLI  TICKS_PER_MICRO * 1000
00071 #define TICKS_PER_SECOND TICKS_PER_MILLI * 1000
00072 
00073 // priorities must be positive, so shift all by this margin. we might want to do smarter convert.
00074 #define LINUX_THREAD_PRIORITY_BASE 10
00075 
00076 //  message Queues names related staff:
00077 #define MQ_FILENAME_LEN 10
00078 
00079 #ifndef CLOCK_MONOTONIC_RAW //a workaround for the operWRT port that missing this include
00080 #define CLOCK_MONOTONIC_RAW 4 //http://elixir.free-electrons.com/linux/latest/source/include/uapi/linux/time.h
00081 #endif
00082 
00083 PAL_PRIVATE char g_mqName[MQ_FILENAME_LEN];
00084 PAL_PRIVATE int g_mqNextNameNum = 0;
00085 
00086 
00087 extern palStatus_t pal_plat_getRandomBufferFromHW(uint8_t *randomBuf, size_t bufSizeBytes);
00088 
00089 inline PAL_PRIVATE void nextMessageQName()
00090 {
00091     g_mqNextNameNum++;
00092     for (int j = 4, divider = 10000; j < 9; j++, divider /= 10)
00093     {
00094         g_mqName[j] = '0' + (g_mqNextNameNum / divider) %10 ; //just to make sure we don't write more then 1 digit.
00095     }
00096     g_mqName[9] = '\0';
00097 }
00098 
00099 
00100 /*! Initiate a system reboot.
00101  */
00102 void pal_plat_osReboot (void)
00103 {
00104     struct utsname buf;
00105     buf.nodename[0] = 0;
00106     // Get the system names. Ignore error for this function call
00107     uname(&buf);
00108     // We assume that it is a desktop if "ubuntu" is returned.
00109     if(!strcmp(buf.nodename,"ubuntu"))
00110     {
00111         // We emulate resetting the device by running the application again.
00112         // Restart the application
00113         int status, timeout; // unused ifdef WAIT_FOR_COMPLETION ;
00114         const char *argv[] = {"0" , 0};
00115 
00116         //printf("program_invocation_name=%s, __progname=%s",program_invocation_name,__progname);
00117         argv[0] = program_invocation_name;
00118         pid_t   my_pid;
00119 
00120         if (0 == (my_pid = fork()))
00121         {
00122             char *const envp[] = { 0 };
00123             if (-1 == execve(argv[0], (char **)argv , envp))
00124             {
00125                 printf("child process execve failed [%s]",argv[0]);
00126             }
00127         }
00128         timeout = 1000;
00129 
00130         while (0 == waitpid(my_pid , &status , WNOHANG))
00131         {
00132             if ( --timeout < 0 ) {
00133                 perror("timeout");
00134                 //return -1;
00135             }
00136             sleep(1);
00137         }
00138     }
00139     else
00140     {
00141         // Reboot the device
00142         reboot(RB_AUTOBOOT);
00143     }
00144     return;
00145 }
00146 
00147 /*! Initialize all data structures (semaphores, mutexs, memory pools, message queues) at system initialization.
00148  *  In case of a failure in any of the initializations, the function returns with an error and stops the rest of the initializations.
00149  * @param[in] opaqueContext The context passed to the initialization (not required for generic CMSIS, pass NULL in this case).
00150  * \return PAL_SUCCESS(0) in case of success, PAL_ERR_CREATION_FAILED in case of failure.
00151  */
00152 palStatus_t pal_plat_RTOSInitialize (void* opaqueContext)
00153 {
00154     palStatus_t status = PAL_SUCCESS;
00155     (void) opaqueContext;
00156     strncpy(g_mqName, "/pal00001", MQ_FILENAME_LEN);
00157     g_mqNextNameNum = 1;   // used for the next name
00158 
00159     //Clean thread tables
00160     memset(g_palThreads,0,sizeof(palThread_t) * PAL_MAX_NUMBER_OF_THREADS);
00161 
00162     //Add implicit the running task as PAL main
00163     g_palThreads[0].initialized = true;
00164     g_palThreads[0].threadID =  pthread_self();
00165 
00166     pal_osAtomicIncrement((int32_t*)&g_threadCounter,1);
00167     //palThreadID = 24 bits for thread counter + 8 bits for thread index (= 0).
00168     g_palThreads[0].palThreadID = (g_threadCounter << 8 );
00169 
00170     return status;
00171 }
00172 
00173 /*! De-Initialize thread objects.
00174  */
00175 palStatus_t pal_plat_RTOSDestroy (void)
00176 {
00177     return PAL_SUCCESS;
00178 }
00179 
00180 
00181 /*return The RTOS kernel system timer counter, in microseconds
00182  */
00183 
00184 uint64_t pal_plat_osKernelSysTick (void) // optional API - not part of original CMSIS API.
00185 {
00186     /*Using clock_gettime is more accurate, but then we have to convert it to ticks. we are using a tick every 100 nanoseconds*/
00187     struct timespec ts;
00188     uint64_t ticks;
00189     //TODO: error handling
00190     clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
00191 
00192     ticks = (uint64_t) (ts.tv_sec * (uint64_t)TICKS_PER_SECOND
00193             + (ts.tv_nsec / NANOS_PER_TICK));
00194     return ticks;
00195 }
00196 
00197 /* Convert the value from microseconds to kernel sys ticks.
00198  * This is the same as CMSIS macro osKernelSysTickMicroSec.
00199  * since we return microsecods as ticks, just return the value
00200  */
00201 uint64_t pal_plat_osKernelSysTickMicroSec (uint64_t microseconds)
00202 {
00203 
00204     //convert to nanoseconds
00205     return microseconds * TICKS_PER_MICRO;
00206 }
00207 
00208 /*! Get the system tick frequency.
00209  * \return The system tick frequency.
00210  */
00211 inline uint64_t pal_plat_osKernelSysTickFrequency (void)
00212 {
00213     /* since we use clock_gettime, with resolution of 100 nanosecond per tick*/
00214     return TICKS_PER_SECOND;
00215 }
00216 
00217 inline PAL_PRIVATE void setDefaultThreadValues(palThread_t* thread)
00218 {
00219 
00220 #if PAL_UNIQUE_THREAD_PRIORITY
00221     g_palThreadPriorities[thread->priority + PRIORITY_INDEX_OFFSET] = 0;
00222 #endif //PAL_UNIQUE_THREAD_PRIORITY
00223     thread->threadStore = NULL;
00224     thread->threadFuncWrapper.realThreadArgs = NULL;
00225     thread->threadFuncWrapper.realThreadFunc = NULL;
00226     thread->threadFuncWrapper.threadIndex = 0;
00227     thread->priority = PAL_osPriorityError;
00228     thread->stackSize = 0;
00229     thread->threadID = (palThreadID_t)PAL_INVALID_THREAD;
00230     thread->palThreadID = 0;
00231     //! This line should be last thing to be done in this function.
00232     //! in order to prevent double accessing the same index between
00233     //! this function and the threadCreate function.
00234     thread->initialized = false;
00235 }
00236 
00237 /*! Clean thread data from the global thread data base (g_palThreads). Thread Safe API
00238  *
00239  * @param[in] index:    the index in the data base to be cleaned.
00240  */
00241 PAL_PRIVATE void threadCleanUp(uint32_t index)
00242 {
00243     uint32_t status = PAL_SUCCESS;
00244     uint32_t threadIndex = PAL_GET_THREAD_INDEX(index);
00245 
00246     status = pal_osMutexWait(g_palThreadInitMutex, PAL_RTOS_WAIT_FOREVER);
00247 
00248     if (PAL_SUCCESS != status)
00249     {
00250          PAL_LOG(ERR,"thread cleanup: mutex wait failed!\n");
00251     }
00252     else{
00253         if ((threadIndex < PAL_MAX_NUMBER_OF_THREADS) && (g_palThreads[threadIndex].palThreadID == index))
00254         {
00255             setDefaultThreadValues(&g_palThreads[threadIndex]);
00256         }
00257 
00258         status = pal_osMutexRelease(g_palThreadInitMutex);
00259         if (PAL_SUCCESS != status)
00260         {
00261              PAL_LOG(ERR,"thread cleanup: mutex release failed!\n");
00262         }
00263     }
00264     return;
00265 }
00266 
00267 /*! Thread wrapper function, this function will be set as the thread function (for every thread)
00268  *  and it will get as an argument the real data about the thread and call the REAL thread function
00269  *  with the REAL argument. Once the REAL thread function finished, \ref pal_threadClean() will be called.
00270  *
00271  *  @param[in] arg: data structure which contains the real data about the thread.
00272  */
00273 void* threadFunctionWrapper(void* arg)
00274 {
00275 
00276     palThreadFuncWrapper_t* threadWrapper = (palThreadFuncWrapper_t*) arg;
00277 
00278     if ((NULL != threadWrapper) && (NULL != threadWrapper->realThreadFunc))
00279     {
00280         if(g_palThreads[threadWrapper->threadIndex].threadID == NULLPTR)
00281         {
00282             g_palThreads[threadWrapper->threadIndex].threadID =  pthread_self();
00283         }
00284 
00285         threadWrapper->realThreadFunc(threadWrapper->realThreadArgs);
00286         threadCleanUp(g_palThreads[threadWrapper->threadIndex].palThreadID);
00287 
00288     }
00289     return NULL;
00290 }
00291 
00292 /*! Create and start a thread function.
00293  *
00294  * @param[in] function A function pointer to the thread callback function.
00295  * @param[in] funcArgument An argument for the thread function.
00296  * @param[in] priority The priority of the thread.
00297  * @param[in] stackSize The stack size of the thread.
00298  * @param[in] stackPtr A pointer to the thread's stack.
00299  * @param[in] store A pointer to thread's local store, can be NULL.
00300  * @param[out] threadID The created thread ID handle, zero indicates an error.
00301  *
00302  * \return The ID of the created thread, in case of error return zero.
00303  * \note Each thread MUST have a unique priority.
00304  * \note When the priority of the created thread function is higher than the current running thread, the
00305  *      created thread function starts instantly and becomes the new running thread.
00306  */
00307 palStatus_t pal_plat_osThreadCreate (palThreadFuncPtr function,
00308         void* funcArgument, palThreadPriority_t priority, uint32_t stackSize,
00309         uint32_t* stackPtr, palThreadLocalStore_t* store,
00310         palThreadID_t* threadID)
00311 {
00312     uint32_t firstAvailableThreadIndex = PAL_MAX_NUMBER_OF_THREADS;
00313     palStatus_t status = PAL_SUCCESS;
00314     uint32_t localPalThreadID = 0;
00315 
00316 
00317     {
00318         if ((NULL == threadID) || (NULL == function) || (0 == stackSize) || (priority > PAL_osPriorityRealtime))
00319         {
00320             return PAL_ERR_INVALID_ARGUMENT ;
00321         }
00322         status = pal_osMutexWait(g_palThreadInitMutex, PAL_RTOS_WAIT_FOREVER);
00323         if (PAL_SUCCESS == status)
00324         {
00325             for (uint32_t i = 0; i < PAL_MAX_NUMBER_OF_THREADS; ++i)
00326             {
00327                 if ((!g_palThreads[i].initialized))
00328                 {
00329                     g_palThreads[i].initialized = true;
00330                     firstAvailableThreadIndex = i;
00331                     break;
00332                 }
00333             }
00334 
00335             if (firstAvailableThreadIndex >= PAL_MAX_NUMBER_OF_THREADS)
00336             {
00337                 *threadID = PAL_INVALID_THREAD;
00338                 status = PAL_ERR_RTOS_RESOURCE ;
00339                 // release mutex if error.
00340                 pal_osMutexRelease(g_palThreadInitMutex);
00341                 goto finish;
00342             }
00343 
00344             g_palThreads[firstAvailableThreadIndex].threadStore = store;
00345             g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.realThreadArgs =
00346                     funcArgument;
00347             g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.realThreadFunc =
00348                     function;
00349             g_palThreads[firstAvailableThreadIndex].threadFuncWrapper.threadIndex =
00350                     firstAvailableThreadIndex;
00351             g_palThreads[firstAvailableThreadIndex].priority = priority;
00352             g_palThreads[firstAvailableThreadIndex].stackSize = stackSize;
00353             g_palThreads[firstAvailableThreadIndex].palThreadID = ((firstAvailableThreadIndex)+((pal_osAtomicIncrement((int32_t*)&g_threadCounter, 1)) << 8)); //palThreadID = 24 bits for thread counter + lower 8 bits for thread index.
00354             localPalThreadID = g_palThreads[firstAvailableThreadIndex].palThreadID;
00355 
00356             // release mutex before thread creation .
00357             status = pal_osMutexRelease(g_palThreadInitMutex);
00358 
00359             if (PAL_SUCCESS == status)
00360             {
00361                 // prepare thread attributes
00362                 pthread_attr_t attr;
00363                 pthread_attr_init(&attr);
00364 
00365                 int err = pthread_attr_setstacksize(&attr, stackSize);// Replace stack pointer with dynamically  allocated from the OS
00366                 if (0 != err)
00367                 {
00368                     status = PAL_ERR_INVALID_ARGUMENT ;
00369                     goto finish;
00370                 }
00371 
00372                 if (0 != pthread_attr_setschedpolicy(&attr, SCHED_RR))
00373                 {
00374                     status = PAL_ERR_INVALID_ARGUMENT ;
00375                     goto finish;
00376                 }
00377 
00378                 //PTHREAD_CREATE_JOINABLE in Linux save the stack TCB until join is call and detach clean every thing upon exit
00379                 //Because PAL is not forcing the user to call thread cancel the threads are detached
00380                 if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
00381                 {
00382                     status = PAL_ERR_INVALID_ARGUMENT ;
00383                     goto finish;
00384                 }
00385 
00386                 struct sched_param schedParam;
00387                 schedParam.sched_priority = LINUX_THREAD_PRIORITY_BASE + (int) priority;
00388                 if (0 != pthread_attr_setschedparam(&attr, &schedParam))
00389                 {
00390                     status = PAL_ERR_INVALID_ARGUMENT ;
00391                     goto finish;
00392                 }
00393 
00394                 //create the thread
00395                 pthread_t thread = (pthread_t)NULL;
00396 
00397                 int retVal = pthread_create(&thread, &attr, threadFunctionWrapper, (void*) &(g_palThreads[firstAvailableThreadIndex].threadFuncWrapper));
00398                 pthread_attr_destroy(&attr); //Destroy the thread attributes object, since it is no longer needed
00399                 if (0 != retVal)
00400                 {
00401                     if (EPERM == retVal)
00402                     {
00403                         // cannot set the priority
00404                         status = PAL_ERR_RTOS_PRIORITY ;
00405                     }
00406                     else
00407                     {
00408                         status = PAL_ERR_RTOS_RESOURCE ;
00409                     }
00410                     goto finish;
00411                 }
00412 
00413                 if((thread != (palThreadID_t)PAL_INVALID_THREAD) && (thread != 0))
00414                 {
00415                     // if we managed to do it, set in the the array, set threadID, and return
00416                     g_palThreads[firstAvailableThreadIndex].threadID = (palThreadID_t) thread;
00417                     *threadID = localPalThreadID;
00418                 }
00419             }
00420 
00421         }
00422     }
00423     finish:
00424     if (PAL_SUCCESS != status)
00425     {
00426         if (firstAvailableThreadIndex < PAL_MAX_NUMBER_OF_THREADS)
00427         {
00428             threadCleanUp(localPalThreadID);
00429         }
00430         *threadID = PAL_INVALID_THREAD;
00431     }
00432     return status;
00433 
00434 }
00435 
00436 /*! Terminate and free allocated data for the thread.
00437  *
00438  * @param[in] threadID The ID of the thread to stop and terminate.
00439  *
00440  * \return palStatus_t; PAL_SUCCESS(0) in case of success, a negative value indicating a specific error code in case of failure.
00441  */
00442 palStatus_t pal_plat_osThreadTerminate (palThreadID_t* threadID)
00443 {
00444     palStatus_t status = PAL_ERR_INVALID_ARGUMENT ;
00445     int statusOS = 0;
00446     uint32_t threadIndex = PAL_GET_THREAD_INDEX(*threadID);
00447 
00448     if ((PAL_INVALID_THREAD == *threadID) || (threadIndex >= PAL_MAX_NUMBER_OF_THREADS))
00449     {
00450         return PAL_ERR_INVALID_ARGUMENT ;
00451     }
00452 
00453     // if thread exited or was terminated already return success.
00454     if ((g_palThreads[threadIndex].palThreadID == 0) ||  // thread already exited
00455         (g_palThreads[threadIndex].palThreadID != *threadID) || // thread already exited and a new thread was created at the same index.
00456         (g_palThreads[threadIndex].threadID == (palThreadID_t)PAL_INVALID_THREAD))  // thread was terminsated.
00457     {
00458         return PAL_SUCCESS;
00459     }
00460 
00461 
00462     if((pthread_self() != g_palThreads[threadIndex].threadID))
00463     {//Kill only if not trying to kill from running task
00464         status = PAL_SUCCESS;
00465         if ((g_palThreads[threadIndex].initialized))
00466         {
00467             statusOS = pthread_cancel(g_palThreads[threadIndex].threadID);
00468             if((statusOS != 0) && (statusOS != ESRCH))
00469             {
00470                 status = PAL_ERR_RTOS_RESOURCE ;
00471             }
00472         }
00473     }
00474 
00475     if(status == PAL_SUCCESS)
00476     {
00477         threadCleanUp(*threadID);
00478         *threadID = PAL_INVALID_THREAD;
00479     }
00480 
00481     return status;
00482 }
00483 
00484 /*! Get the ID of the current thread.
00485  * \return The ID of the current thread, in case of error return PAL_maX_UINT32.
00486  * \note For a thread with real time priority, the function always returns PAL_maX_UINT32.
00487  */
00488 palThreadID_t pal_plat_osThreadGetId ()
00489 {
00490     int i = 0;
00491     pthread_t  osThreadID = pthread_self();
00492     palThreadID_t ret = PAL_INVALID_THREAD;
00493 
00494     for(i= 0; i < PAL_MAX_NUMBER_OF_THREADS; i++)
00495     {
00496         if(osThreadID == g_palThreads[i].threadID)
00497         {
00498             ret = i;
00499             break;
00500         }
00501     }
00502     return ret;
00503 }
00504 
00505 /*! Get the storage of the current thread.
00506  * \return The storage of the current thread.
00507  */
00508 palThreadLocalStore_t* pal_plat_osThreadGetLocalStore (void)
00509 {
00510     palThreadLocalStore_t* localStore = NULL;
00511     palThreadID_t id = pal_osThreadGetId();
00512 
00513     if( g_palThreads[id].initialized)
00514     {
00515         localStore = g_palThreads[id].threadStore;
00516     }
00517     return localStore;
00518 }
00519 
00520 /*! Wait for a specified period of time in milliseconds.
00521  *
00522  * @param[in] milliseconds The number of milliseconds to wait before proceeding.
00523  *
00524  * \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.
00525  */
00526 palStatus_t pal_plat_osDelay (uint32_t milliseconds)
00527 {
00528     struct timespec sTime;
00529     struct timespec rTime; // this will return how much sleep time still left in case of interrupted sleep
00530     int stat;
00531     //init rTime, as we will copy it over to stime inside the do-while loop.
00532     rTime.tv_sec = milliseconds / 1000;
00533     rTime.tv_nsec = PAL_MILLI_TO_NANO(milliseconds);
00534 
00535     do
00536     {
00537         sTime.tv_sec = rTime.tv_sec;
00538         sTime.tv_nsec = rTime.tv_nsec;
00539         stat = nanosleep(&sTime, &rTime);
00540     } while ((-1 == stat) && (EINTR ==errno)) ;
00541     return (stat == 0) ? PAL_SUCCESS : PAL_ERR_GENERIC_FAILURE;
00542 }
00543 
00544 /*
00545  * Internal struct to handle timers.
00546  */
00547 
00548 struct palTimerInfo
00549 {
00550     timer_t handle;
00551     palTimerFuncPtr function;
00552     void *funcArgs;
00553     palTimerType_t timerType;
00554     bool isHighRes;
00555 };
00556 
00557 /*
00558  * internal function used to handle timers expiration events.
00559  */
00560 PAL_PRIVATE void palTimerEventHandler(void* args)
00561 {
00562     struct palTimerInfo* timer = (struct palTimerInfo *) args;
00563 
00564     if (NULL == timer)
00565     { // no timer anymore, so just return.
00566         return;
00567     }
00568 
00569     //call the callback function
00570     timer->function(timer->funcArgs);
00571 }
00572 
00573 
00574 /*
00575 * Internal struct to handle timers.
00576 */
00577 
00578 #define PAL_HIGH_RES_TIMER_THRESHOLD_MS 100
00579 
00580 typedef struct palHighResTimerThreadContext
00581 {
00582     palTimerFuncPtr function;
00583     void *funcArgs;
00584     uint32_t intervalMS;
00585 } palHighResTimerThreadContext_t;
00586 
00587 
00588 static pthread_t s_palHighResTimerThreadID = {0};
00589 static bool s_palHighResTimerThreadInUse =  0;
00590 static palHighResTimerThreadContext_t s_palHighResTimerThreadContext = {0};
00591 
00592 /*
00593 *  callback for handling high precision timer callbacks (currently only one is supported)
00594 */
00595 
00596 PAL_PRIVATE void* palHighResTimerThread(void* args)
00597 {
00598     palHighResTimerThreadContext_t* context = (palHighResTimerThreadContext_t*)args;
00599     uint32_t timer_period_ms = context->intervalMS;
00600     int err = 0;
00601     struct timespec next_timeout_ts;
00602     err = clock_gettime(CLOCK_MONOTONIC, &next_timeout_ts);
00603     assert(err == 0);
00604 
00605     while(1) {
00606         // Determine absolute time we want to sleep until
00607         next_timeout_ts.tv_nsec += PAL_NANO_PER_MILLI * timer_period_ms;
00608         if (next_timeout_ts.tv_nsec >= PAL_NANO_PER_SECOND) 
00609         {
00610             next_timeout_ts.tv_nsec = next_timeout_ts.tv_nsec - PAL_NANO_PER_SECOND;
00611             next_timeout_ts.tv_sec += 1;
00612         }
00613 
00614         // Call nanosleep until error or no interrupt, ie. return code is 0
00615         do {
00616             err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_timeout_ts, NULL);
00617             assert(err == 0 || err == EINTR);
00618         } while(err == EINTR);
00619 
00620         // Done sleeping, call callback
00621         context->function(context->funcArgs);
00622     }
00623     return NULL;
00624 }
00625 
00626 PAL_PRIVATE palStatus_t startHighResTimerThread(palTimerFuncPtr function, void *funcArgs , uint32_t intervalMS)
00627 {
00628     int retVal = 0;
00629     palStatus_t status = PAL_SUCCESS;
00630     pthread_attr_t attr;
00631     pthread_attr_init(&attr);
00632 
00633     s_palHighResTimerThreadContext.function = function;
00634     s_palHighResTimerThreadContext.funcArgs = funcArgs;
00635     s_palHighResTimerThreadContext.intervalMS = intervalMS;
00636 
00637     retVal = pthread_attr_setstacksize(&attr, PAL_RTOS_HIGH_RES_TIMER_THREAD_STACK_SIZE);//sets the minimum stack size
00638     if (0 != retVal)
00639     {
00640         status = PAL_ERR_INVALID_ARGUMENT ;
00641         goto finish;
00642     }
00643 
00644     if (0 != pthread_attr_setschedpolicy(&attr, SCHED_RR))
00645     {
00646         status = PAL_ERR_INVALID_ARGUMENT ;
00647         goto finish;
00648     }
00649 
00650     //PTHREAD_CREATE_JOINABLE in Linux save the stack TCB until join is call and detach clean every thing upon exit
00651     //Because PAL is not forcing the user to call thread cancel the threads are detached
00652     if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
00653     {
00654         status = PAL_ERR_INVALID_ARGUMENT ;
00655         goto finish;
00656     }
00657 
00658     struct sched_param schedParam;
00659     schedParam.sched_priority = LINUX_THREAD_PRIORITY_BASE + (int)PAL_osPriorityRealtime;
00660     if (0 != pthread_attr_setschedparam(&attr, &schedParam))
00661     {
00662         status = PAL_ERR_INVALID_ARGUMENT ;
00663         goto finish;
00664     }
00665 
00666    retVal = pthread_create(&s_palHighResTimerThreadID, &attr, &palHighResTimerThread, &s_palHighResTimerThreadContext);
00667     if (0 != retVal)
00668     {
00669         if (EPERM == retVal)
00670         {
00671             // cannot set the priority
00672             status = PAL_ERR_RTOS_PRIORITY ;
00673         }
00674         else
00675         {
00676             status = PAL_ERR_RTOS_RESOURCE ;
00677         }
00678     }
00679 
00680 finish:
00681     pthread_attr_destroy(&attr); //Destroy the thread attributes object, since it is no longer needed
00682 
00683     return status;
00684 
00685 }
00686 
00687 
00688 /*! Create a timer.
00689  *
00690  * @param[in] function A function pointer to the timer callback function.
00691  * @param[in] funcArgument An argument for the timer callback function.
00692  * @param[in] timerType The timer type to be created, periodic or oneShot.
00693  * @param[out] timerID The ID of the created timer, zero value indicates an error.
00694  *
00695  * \return PAL_SUCCESS when the timer was created successfully. A specific error in case of failure.
00696  */
00697 palStatus_t pal_plat_osTimerCreate (palTimerFuncPtr function, void* funcArgument,
00698         palTimerType_t timerType, palTimerID_t* timerID)
00699 {
00700 
00701     palStatus_t status = PAL_SUCCESS;
00702     struct palTimerInfo* timerInfo = NULL;
00703     {
00704         struct sigevent sig;
00705         timer_t localTimer;
00706 
00707         if ((NULL == timerID) || (NULL == (void*) function))
00708         {
00709             return PAL_ERR_INVALID_ARGUMENT ;
00710         }
00711 
00712         timerInfo = (struct palTimerInfo*) malloc(sizeof(struct palTimerInfo));
00713         if (NULL == timerInfo)
00714         {
00715             status = PAL_ERR_NO_MEMORY ;
00716             goto finish;
00717         }
00718 
00719         timerInfo->function = function;
00720         timerInfo->funcArgs = funcArgument;
00721         timerInfo->timerType = timerType;
00722         timerInfo->isHighRes = false;
00723 
00724         memset(&sig, 0, sizeof(sig));
00725 
00726         sig.sigev_notify = SIGEV_THREAD;
00727         sig.sigev_signo = 0;
00728         sig.sigev_value.sival_ptr = timerInfo;
00729         sig.sigev_notify_function = (void (*)(union sigval)) palTimerEventHandler;
00730 
00731         int ret = timer_create(CLOCK_MONOTONIC, &sig, &localTimer);
00732         if (-1 == ret)
00733         {
00734             if (EINVAL == errno)
00735             {
00736                 status = PAL_ERR_INVALID_ARGUMENT ;
00737                 goto finish;
00738             }
00739             if (ENOMEM == errno)
00740             {
00741                 status = PAL_ERR_NO_MEMORY ;
00742                 goto finish;
00743             }
00744             PAL_LOG(ERR, "Rtos timer create error %d", ret);
00745             status = PAL_ERR_GENERIC_FAILURE;
00746             goto finish;
00747         }
00748 
00749         // managed to create the timer - finish up
00750         timerInfo->handle = localTimer;
00751         *timerID = (palTimerID_t) timerInfo;
00752     }
00753     finish: if (PAL_SUCCESS != status)
00754     {
00755         if (NULL != timerInfo)
00756         {
00757             free(timerInfo);
00758             *timerID = (palTimerID_t) NULL;
00759         }
00760     }
00761     return status;
00762 }
00763 
00764 /* Convert milliseconds into seconds and nanoseconds inside a timespec struct
00765  */
00766 PAL_PRIVATE void convertMilli2Timespec(uint32_t millisec, struct timespec* ts)
00767 {
00768     ts->tv_sec = millisec / 1000;
00769     ts->tv_nsec = PAL_MILLI_TO_NANO(millisec);
00770 }
00771 
00772 /*! Start or restart a timer.
00773  *
00774  * @param[in] timerID The handle for the timer to start.
00775  * @param[in] millisec The time in milliseconds to set the timer to.
00776  *
00777  * \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.
00778  */
00779 palStatus_t pal_plat_osTimerStart (palTimerID_t timerID, uint32_t millisec)
00780 {
00781     palStatus_t status = PAL_SUCCESS;
00782     if (NULL == (struct palTimerInfo *) timerID)
00783     {
00784         return PAL_ERR_INVALID_ARGUMENT ;
00785     }
00786 
00787     struct palTimerInfo* timerInfo = (struct palTimerInfo *) timerID;
00788     struct itimerspec its;
00789 
00790 
00791     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)
00792     {
00793         if (true == s_palHighResTimerThreadInUse)
00794         {
00795             status = PAL_ERR_NO_HIGH_RES_TIMER_LEFT ;
00796         }
00797         else
00798         {
00799             status = startHighResTimerThread(timerInfo->function, timerInfo->funcArgs, millisec);
00800             if (PAL_SUCCESS == status)
00801             {
00802                 timerInfo->isHighRes = true;
00803         s_palHighResTimerThreadInUse = true;
00804             }
00805 
00806         }
00807 
00808     }
00809     else // otherwise handle normally
00810     {
00811         convertMilli2Timespec(millisec, &(its.it_value));
00812 
00813         if (palOsTimerPeriodic  == timerInfo->timerType)
00814         {
00815             convertMilli2Timespec(millisec, &(its.it_interval));
00816         }
00817         else
00818         {  // one time timer
00819             convertMilli2Timespec(0, &(its.it_interval));
00820         }
00821 
00822         if (-1 == timer_settime(timerInfo->handle, 0, &its, NULL))
00823         {
00824             status = PAL_ERR_INVALID_ARGUMENT ;
00825         }
00826     }
00827 
00828     return status;
00829 }
00830 
00831 /*! Stop a timer.
00832  *
00833  * @param[in] timerID The handle for the timer to stop.
00834  *
00835  * \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.
00836  */
00837 palStatus_t pal_plat_osTimerStop (palTimerID_t timerID)
00838 {
00839     palStatus_t status = PAL_SUCCESS;
00840     if (NULL == (struct palTimerInfo *) timerID)
00841     {
00842         return PAL_ERR_INVALID_ARGUMENT ;
00843     }
00844 
00845     struct palTimerInfo* timerInfo = (struct palTimerInfo *) timerID;
00846     struct itimerspec its;
00847 
00848     if ((true == timerInfo->isHighRes) && (0 != s_palHighResTimerThreadInUse )) // if  high res timer clean up thread.
00849     {
00850         int statusOS = pthread_cancel(s_palHighResTimerThreadID);
00851         if ((statusOS != 0) && (statusOS != ESRCH))
00852         {
00853             return PAL_ERR_RTOS_RESOURCE ;
00854         }
00855         else
00856         {
00857             timerInfo->isHighRes = false;
00858             s_palHighResTimerThreadInUse = false;
00859             return PAL_SUCCESS;
00860         }
00861     }
00862     else // otherwise process normally
00863     {
00864         // set timer to 0 to disarm it.
00865         convertMilli2Timespec(0, &(its.it_value));
00866 
00867         convertMilli2Timespec(0, &(its.it_interval));
00868 
00869         if (-1 == timer_settime(timerInfo->handle, 0, &its, NULL))
00870         {
00871             status = PAL_ERR_INVALID_ARGUMENT ;
00872         }
00873     }
00874 
00875     return status;
00876 }
00877 
00878 /*! Delete the timer object
00879  *
00880  * @param[inout] timerID The handle for the timer to delete. In success, *timerID = NULL.
00881  *
00882  * \return PAL_SUCCESS when the timer was deleted successfully, PAL_ERR_RTOS_PARAMETER when the timerID is incorrect.
00883  */
00884 palStatus_t pal_plat_osTimerDelete (palTimerID_t* timerID)
00885 {
00886     palStatus_t status = PAL_SUCCESS;
00887     if (NULL == timerID)
00888     {
00889         return PAL_ERR_INVALID_ARGUMENT ;
00890     }
00891     struct palTimerInfo* timerInfo = (struct palTimerInfo *) *timerID;
00892     if (NULL == timerInfo)
00893     {
00894         status = PAL_ERR_RTOS_PARAMETER;
00895     }
00896 
00897     if ((true == timerInfo->isHighRes) && (0 != s_palHighResTimerThreadInUse)) //  if high res timer delted before stopping => clean up thread.
00898     {
00899         int statusOS = pthread_cancel(s_palHighResTimerThreadID);
00900         if ((statusOS != 0) && (statusOS != ESRCH))
00901         {
00902             status = PAL_ERR_RTOS_RESOURCE ;
00903         }
00904         else
00905         {
00906             timerInfo->isHighRes = false;
00907             s_palHighResTimerThreadInUse = false;
00908         }
00909     }
00910 
00911     if (PAL_SUCCESS == status)
00912     {
00913         timer_t lt = timerInfo->handle;
00914         if (-1 == timer_delete(lt))
00915         {
00916             status = PAL_ERR_RTOS_RESOURCE ;
00917         }
00918 
00919         free(timerInfo);
00920         *timerID = (palTimerID_t) NULL;
00921     }
00922     return status;
00923 }
00924 
00925 /*! Create and initialize a mutex object.
00926  *
00927  * @param[out] mutexID The created mutex ID handle, zero value indicates an error.
00928  *
00929  * \return PAL_SUCCESS when the mutex was created successfully, a specific error in case of failure.
00930  */
00931 palStatus_t pal_plat_osMutexCreate (palMutexID_t* mutexID)
00932 {
00933     palStatus_t status = PAL_SUCCESS;
00934     pthread_mutex_t* mutex = NULL;
00935     {
00936         int ret;
00937         if (NULL == mutexID)
00938         {
00939             return PAL_ERR_INVALID_ARGUMENT ;
00940         }
00941 
00942         mutex = malloc(sizeof(pthread_mutex_t));
00943         if (NULL == mutex)
00944         {
00945             status = PAL_ERR_NO_MEMORY ;
00946             goto finish;
00947         }
00948 
00949         pthread_mutexattr_t mutexAttr;
00950         pthread_mutexattr_init(&mutexAttr);
00951         pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE);
00952         ret = pthread_mutex_init(mutex, &mutexAttr);
00953 
00954         if (0 != ret)
00955         {
00956             if (ENOMEM == ret)
00957             {
00958                 status = PAL_ERR_NO_MEMORY ;
00959             }
00960             else
00961             {
00962                 PAL_LOG(ERR, "Rtos mutex create status %d", ret);
00963                 status = PAL_ERR_GENERIC_FAILURE;
00964             }
00965             goto finish;
00966         }
00967         *mutexID = (palMutexID_t) mutex;
00968     }
00969     finish: if (PAL_SUCCESS != status)
00970     {
00971         if (NULL != mutex)
00972         {
00973             free(mutex);
00974         }
00975     }
00976     return status;
00977 }
00978 
00979 /* Wait until a mutex becomes available.
00980  *
00981  * @param[in] mutexID The handle for the mutex.
00982  * @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.
00983  *
00984  * \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:
00985  *        PAL_ERR_RTOS_RESOURCE - Mutex not available but no timeout set.
00986  *        PAL_ERR_RTOS_TIMEOUT - Mutex was not available until timeout expired.
00987  *        PAL_ERR_RTOS_PARAMETER - Mutex ID is invalid.
00988  *        PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines.
00989  */
00990 palStatus_t pal_plat_osMutexWait (palMutexID_t mutexID, uint32_t millisec)
00991 {
00992     palStatus_t status = PAL_SUCCESS;
00993     int err;
00994     if (NULL == ((pthread_mutex_t*) mutexID))
00995     {
00996         return PAL_ERR_INVALID_ARGUMENT ;
00997     }
00998     pthread_mutex_t* mutex = (pthread_mutex_t*) mutexID;
00999 
01000     if (PAL_RTOS_WAIT_FOREVER != millisec)
01001     {
01002         /* calculate the wait absolute time */
01003         struct timespec ts;
01004         clock_gettime(CLOCK_REALTIME, &ts);
01005 
01006         ts.tv_sec += (millisec / PAL_MILLI_PER_SECOND);
01007         ts.tv_nsec += PAL_MILLI_TO_NANO(millisec);
01008         ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; // if there is some overflow in the addition of nanoseconds.
01009         ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND;
01010 
01011         while ((err = pthread_mutex_timedlock(mutex, &ts)) != 0 && err == EINTR)
01012         {
01013             continue; /* Restart if interrupted by handler */
01014         }
01015     }
01016     else
01017     { // wait for ever
01018         err = pthread_mutex_lock(mutex);
01019     }
01020 
01021     if (0 != err)
01022     {
01023         if (err == ETIMEDOUT)
01024         {
01025             status = PAL_ERR_RTOS_TIMEOUT ;
01026         }
01027         else
01028         {
01029             PAL_LOG(ERR, "Rtos mutex wait status %d", err);
01030             status = PAL_ERR_GENERIC_FAILURE;
01031         }
01032     }
01033 
01034     return status;
01035 }
01036 
01037 /* Release a mutex that was obtained by osMutexWait.
01038  *
01039  * @param[in] mutexID The handle for the mutex.
01040  *
01041  * \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.
01042  */
01043 palStatus_t pal_plat_osMutexRelease (palMutexID_t mutexID)
01044 {
01045     palStatus_t status = PAL_SUCCESS;
01046     int result = 0;
01047 
01048     pthread_mutex_t* mutex = (pthread_mutex_t*) mutexID;
01049     if (NULL == mutex)
01050     {
01051         return PAL_ERR_INVALID_ARGUMENT ;
01052     }
01053 
01054     result = pthread_mutex_unlock(mutex);
01055     if (0 != result)
01056     {
01057         // only reason this might fail - process don't have permission for mutex.
01058         PAL_LOG(ERR, "Rtos mutex release failure - %d",result);
01059         status = PAL_ERR_GENERIC_FAILURE;
01060     }
01061     return status;
01062 }
01063 
01064 /*Delete a mutex object.
01065  *
01066  * @param[inout] mutexID The ID of the mutex to delete. In success, *mutexID = NULL.
01067  *
01068  * \return PAL_SUCCESS when the mutex was deleted successfully, one of the following error codes in case of failure:
01069  *        PAL_ERR_RTOS_RESOURCE - Mutex already released.
01070  *        PAL_ERR_RTOS_PARAMETER - Mutex ID is invalid.
01071  *        PAL_ERR_RTOS_ISR - Cannot be called from interrupt service routines.
01072  * \note After this call, mutex_id is no longer valid and cannot be used.
01073  */
01074 palStatus_t pal_plat_osMutexDelete (palMutexID_t* mutexID)
01075 {
01076     palStatus_t status = PAL_SUCCESS;
01077     uint32_t ret;
01078     if (NULL == mutexID)
01079     {
01080         return PAL_ERR_INVALID_ARGUMENT ;
01081     }
01082     pthread_mutex_t* mutex = (pthread_mutex_t*) *mutexID;
01083 
01084     if (NULL == mutex)
01085     {
01086         status = PAL_ERR_RTOS_RESOURCE ;
01087     }
01088     ret = pthread_mutex_destroy(mutex);
01089     if ((PAL_SUCCESS == status) && (0 != ret))
01090     {
01091         PAL_LOG(ERR,"pal_plat_osMutexDelete 0x%x",ret);
01092         status = PAL_ERR_RTOS_RESOURCE ;
01093     }
01094     if (NULL != mutex)
01095     {
01096         free(mutex);
01097     }
01098 
01099     *mutexID = (palMutexID_t) NULL;
01100     return status;
01101 }
01102 
01103 /* Create and initialize a semaphore object.
01104  *
01105  * Semaphore is shared between threads, but not process.
01106  *
01107  * @param[in] count The number of available resources.
01108  * @param[out] semaphoreID The ID of the created semaphore, zero value indicates an error.
01109  *
01110  * \return PAL_SUCCESS when the semaphore was created successfully, a specific error in case of failure.
01111  */
01112 palStatus_t pal_plat_osSemaphoreCreate (uint32_t count,
01113         palSemaphoreID_t* semaphoreID)
01114 {
01115     palStatus_t status = PAL_SUCCESS;
01116     sem_t* semaphore = NULL;
01117 
01118     {
01119         if (NULL == semaphoreID)
01120         {
01121             return PAL_ERR_INVALID_ARGUMENT ;
01122         }
01123         semaphore = malloc(sizeof(sem_t));
01124         if (NULL == semaphore)
01125         {
01126             status = PAL_ERR_NO_MEMORY ;
01127             goto finish;
01128         }
01129         /* create the semaphore as shared between threads */
01130         int ret = sem_init(semaphore, 0, count);
01131         if (-1 == ret)
01132         {
01133             if (EINVAL == errno)
01134             {
01135                 /* count is too big */
01136                 status = PAL_ERR_INVALID_ARGUMENT ;
01137             }
01138             else
01139             {
01140                 PAL_LOG(ERR, "Rtos semaphore init error %d", ret);
01141                 status = PAL_ERR_GENERIC_FAILURE;
01142             }
01143             goto finish;
01144         }
01145 
01146         *semaphoreID = (palSemaphoreID_t) semaphore;
01147     }
01148     finish: if (PAL_SUCCESS != status)
01149     {
01150         if (NULL != semaphore)
01151         {
01152             free(semaphore);
01153         }
01154         *semaphoreID = (palSemaphoreID_t) NULL;
01155     }
01156     return status;
01157 }
01158 
01159 /* Wait until a semaphore token becomes available.
01160  *
01161  * @param[in] semaphoreID The handle for the semaphore.
01162  * @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.
01163  * @param[out] countersAvailable The number of semaphores available (before the wait), if semaphores are not available (timeout/error) zero is returned.
01164  *
01165  * \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:
01166  *      PAL_ERR_RTOS_TIMEOUT - Semaphore was not available until timeout expired.
01167  *      PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid.
01168  *      PAL_ERR_INVALID_ARGUMENT - countersAvailable is NULL
01169  *
01170  *      NOTES: 1. counterAvailable returns 0 in case there are no semaphores available or there are other threads waiting on it.
01171  *                Value is not thread safe - it might be changed by the time it is read/returned.
01172  *             2. timed wait is using absolute time.
01173  */
01174 palStatus_t pal_plat_osSemaphoreWait (palSemaphoreID_t semaphoreID,
01175         uint32_t millisec, int32_t* countersAvailable)
01176 {
01177     palStatus_t status = PAL_SUCCESS;
01178     int tmpCounters = 0;
01179     {
01180         int err;
01181         sem_t* sem = (sem_t*) semaphoreID;
01182         if ((NULL == sem))
01183         {
01184             return PAL_ERR_INVALID_ARGUMENT ;
01185         }
01186 
01187         if (PAL_RTOS_WAIT_FOREVER != millisec)
01188         {
01189             /* calculate the wait absolute time */
01190             struct timespec ts;
01191             clock_gettime(CLOCK_REALTIME, &ts);
01192             ts.tv_sec += millisec / PAL_MILLI_PER_SECOND;
01193             ts.tv_nsec += PAL_MILLI_TO_NANO(millisec);
01194             ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND; // in case there is overflow in the nanoseconds.
01195             ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND;
01196 
01197             while ((err = sem_timedwait(sem, &ts)) == -1 && errno == EINTR)
01198                 continue; /* Restart if interrupted by handler */
01199         }
01200         else
01201         { // wait for ever
01202             do
01203             {
01204                 err = sem_wait(sem);
01205 
01206                 /* loop again if the wait was interrupted by a signal */
01207             } while ((err == -1) && (errno == EINTR));
01208         }
01209 
01210         if (-1 == err)
01211         {
01212             tmpCounters = 0;
01213             if (errno == ETIMEDOUT)
01214             {
01215                 status = PAL_ERR_RTOS_TIMEOUT ;
01216             }
01217             else
01218             { /* seems this is not a valid semaphore */
01219                 status = PAL_ERR_RTOS_PARAMETER;
01220             }
01221             goto finish;
01222         }
01223         /* get the counter number, shouldn't fail, as we already know this is valid semaphore */
01224         sem_getvalue(sem, &tmpCounters);
01225     }
01226     finish:
01227     if (NULL != countersAvailable)
01228     {
01229         *countersAvailable = tmpCounters;
01230     }
01231     return status;
01232 }
01233 
01234 /*! Release a semaphore token.
01235  *
01236  * @param[in] semaphoreID The handle for the semaphore.
01237  *
01238  * \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.
01239  */
01240 palStatus_t pal_plat_osSemaphoreRelease (palSemaphoreID_t semaphoreID)
01241 {
01242     palStatus_t status = PAL_SUCCESS;
01243     sem_t* sem = (sem_t*) semaphoreID;
01244 
01245     if (NULL == sem)
01246     {
01247         return PAL_ERR_INVALID_ARGUMENT ;
01248     }
01249 
01250     if (-1 == sem_post(sem))
01251     {
01252         if (EINVAL == errno)
01253         {
01254             status = PAL_ERR_RTOS_PARAMETER;
01255         }
01256         else
01257         { /* max value of semaphore exeeded */
01258             PAL_LOG(ERR, "Rtos semaphore release error %d", errno);
01259             status = PAL_ERR_GENERIC_FAILURE;
01260         }
01261     }
01262 
01263     return status;
01264 }
01265 
01266 /*! Delete a semaphore object.
01267  *
01268  * @param[inout] semaphoreID: The ID of the semaphore to delete. In success, *semaphoreID = NULL.
01269  *
01270  * \return PAL_SUCCESS when the semaphore was deleted successfully, one of the following error codes in case of failure:
01271  *        PAL_ERR_RTOS_RESOURCE - Semaphore already released.
01272  *        PAL_ERR_RTOS_PARAMETER - Semaphore ID is invalid.
01273  * \note After this call, the semaphore_id is no longer valid and cannot be used.
01274  */
01275 palStatus_t pal_plat_osSemaphoreDelete (palSemaphoreID_t* semaphoreID)
01276 {
01277     palStatus_t status = PAL_SUCCESS;
01278     {
01279         if (NULL == semaphoreID)
01280         {
01281             return PAL_ERR_INVALID_ARGUMENT ;
01282         }
01283 
01284         sem_t* sem = (sem_t*) (*semaphoreID);
01285         if (NULL == sem)
01286         {
01287             status = PAL_ERR_RTOS_RESOURCE ;
01288             goto finish;
01289         }
01290         if (-1 == sem_destroy(sem))
01291         {
01292             status = PAL_ERR_RTOS_PARAMETER;
01293             goto finish;
01294         }
01295 
01296         if (NULL != sem)
01297         {
01298             free(sem);
01299         }
01300         *semaphoreID = (palSemaphoreID_t) NULL;
01301     }
01302     finish: return status;
01303 }
01304 
01305 typedef struct palMemoryPool
01306 {
01307     void *start;
01308     uint32_t blockCount;
01309     uint32_t blockSize;
01310     bool* allocated;
01311 } palMemoryPool_t;
01312 
01313 /*! Create and initialize a memory pool.
01314  *
01315  * @param[in] blockSize The size of a single block in bytes.
01316  * @param[in] blockCount The maximum number of blocks in the memory pool.
01317  * @param[out] memoryPoolID The ID of the created memory pool, zero value indicates an error.
01318  *
01319  * \return PAL_SUCCESS when the memory pool was created successfully, a specific error in case of failure.
01320  */
01321 palStatus_t pal_plat_osPoolCreate (uint32_t blockSize, uint32_t blockCount, palMemoryPoolID_t* memoryPoolID)
01322 {
01323     palStatus_t status = PAL_SUCCESS;
01324     palMemoryPool_t* mp = NULL;
01325     {
01326 
01327         if ((NULL == memoryPoolID) || (0 == blockSize) || (0 == blockCount))
01328         {
01329             return PAL_ERR_INVALID_ARGUMENT ;
01330         }
01331 
01332         mp = (palMemoryPool_t*) malloc(sizeof(palMemoryPool_t));
01333         if (NULL == mp)
01334         {
01335             status = PAL_ERR_RTOS_NO_MEMORY ;
01336             goto finish;
01337         }
01338 
01339         mp->blockCount = blockCount;
01340         mp->blockSize = blockSize;
01341         mp->allocated = NULL;
01342         mp->start = malloc((size_t)blockCount * blockSize);
01343         if (NULL == mp->start)
01344         {
01345             status = PAL_ERR_RTOS_NO_MEMORY ;
01346             goto finish;
01347         }
01348 
01349         mp->allocated = (bool*) malloc(blockCount * sizeof(bool));
01350         if (NULL == mp->allocated)
01351         {
01352             status = PAL_ERR_RTOS_NO_MEMORY ;
01353             goto finish;
01354         }
01355         for (uint32_t i = 0; i < blockCount; i++)
01356         {
01357             mp->allocated[i] = false;
01358         }
01359 
01360         *memoryPoolID = (palMemoryPoolID_t) mp;
01361     }
01362 
01363     finish:
01364 
01365     if (PAL_SUCCESS != status)
01366     {
01367         if (NULL != mp)
01368         {
01369             if (NULL != mp->start)
01370             {
01371                 free(mp->start);
01372             }
01373             if (NULL != mp->allocated) // in current code - we are not supposed to be here.
01374             {
01375                 free(mp->allocated);
01376             }
01377             free(mp);
01378         }
01379     }
01380 
01381     return status;
01382 }
01383 
01384 PAL_PRIVATE inline void* poolAlloc(palMemoryPoolID_t memoryPoolID, bool zero)
01385 {
01386     if (NULL == (palMemoryPool_t*) memoryPoolID)
01387     {
01388         return NULL;
01389     }
01390 
01391     palMemoryPool_t* mp = (palMemoryPool_t*) memoryPoolID;
01392 
01393     for (uint32_t i = 0; i < mp->blockCount; i++)
01394     {
01395         if (mp->allocated[i] == false)
01396         {
01397             mp->allocated[i] = true;
01398             void* block = (mp->start + i * mp->blockSize);
01399             if (zero == true)
01400             {
01401                 memset(block, 0, mp->blockSize);
01402             }
01403             return block;
01404         }
01405     }
01406     //we didn't find any
01407     return NULL;
01408 }
01409 /*! Allocate a single memory block from a memory pool.
01410  *
01411  * @param[in] memoryPoolID The handle for the memory pool.
01412  *
01413  * \return A pointer to a single allocated memory from the pool, NULL in case of failure.
01414  */
01415 void* pal_plat_osPoolAlloc (palMemoryPoolID_t memoryPoolID)
01416 {
01417     return poolAlloc(memoryPoolID, false);
01418 }
01419 
01420 /*! Allocate a single memory block from a memory pool and set memory block to zero.
01421  *
01422  * @param[in] memoryPoolID The handle for the memory pool.
01423  *
01424  * \return A pointer to a single allocated memory from the pool, NULL in case of failure.
01425  */
01426 void* pal_plat_osPoolCAlloc (palMemoryPoolID_t memoryPoolID)
01427 {
01428     return poolAlloc(memoryPoolID, true);
01429 }
01430 
01431 /*! Return the memoryPoolID of the memory block back to a specific memory pool.
01432  *
01433  * @param[in] memoryPoolID The handle for the memory pool.
01434  * @param[in] block The block to be freed.
01435  *
01436  * \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.
01437  */
01438 palStatus_t pal_plat_osPoolFree (palMemoryPoolID_t memoryPoolID, void* block)
01439 {
01440     palMemoryPool_t* mp = (palMemoryPool_t*) memoryPoolID;
01441     if ((NULL == (palMemoryPool_t*) memoryPoolID) || (NULL == block)
01442             || (mp->start > block)
01443             || ((mp->start + mp->blockCount * mp->blockSize) < block)
01444             || (0 != ((block - mp->start) % mp->blockSize)))
01445     {
01446         return PAL_ERR_INVALID_ARGUMENT ;
01447     }
01448 
01449     int index = (block - mp->start) / mp->blockSize;
01450     mp->allocated[index] = false;
01451     return PAL_SUCCESS;
01452 }
01453 
01454 /*! Delete a memory pool object.
01455  *
01456  * @param[inout] memoryPoolID The handle for the memory pool. In success, *memoryPoolID = NULL.
01457  *
01458  * \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.
01459  */
01460 palStatus_t pal_plat_osPoolDestroy (palMemoryPoolID_t* memoryPoolID)
01461 {
01462     if (NULL == memoryPoolID)
01463     {
01464         return PAL_ERR_INVALID_ARGUMENT ;
01465     }
01466     palMemoryPool_t* mp = (palMemoryPool_t*) *memoryPoolID;
01467     *memoryPoolID = (palMemoryPoolID_t) NULL; // don't let anyone use it anymore.
01468     free(mp->start);
01469     free(mp->allocated);
01470     free(mp);
01471     return PAL_SUCCESS;
01472 }
01473 
01474 typedef struct palMessageQ
01475 {
01476     mqd_t handle;
01477     char name[MQ_FILENAME_LEN];
01478 } palMessageQ_t;
01479 
01480 /*! Create and initialize a message queue.
01481  *
01482  * @param[in] messageQSize The size of the message queue.
01483  * @param[out] messageQID The ID of the created message queue, zero value indicates an error.
01484  *
01485  * \return PAL_SUCCESS when the message queue was created successfully, a specific error in case of failure.
01486  */
01487 palStatus_t pal_plat_osMessageQueueCreate (uint32_t messageQSize, palMessageQID_t* messageQID)
01488 {
01489     palStatus_t status = PAL_SUCCESS;
01490     palMessageQ_t *mq_h = NULL;
01491     {
01492         if (NULL == messageQID)
01493         {
01494             return PAL_ERR_INVALID_ARGUMENT ;
01495         }
01496         mq_h = malloc(sizeof(palMessageQ_t));
01497         if (NULL == mq_h)
01498         {
01499             status = PAL_ERR_NO_MEMORY ;
01500             goto finish;
01501         }
01502         // copy the name to be used, and advance it.
01503         // Note - not thread safe!!
01504         strncpy(mq_h->name, g_mqName, MQ_FILENAME_LEN-1);
01505         mq_h->name[MQ_FILENAME_LEN-1] = '\0';
01506         nextMessageQName();
01507 
01508         // set the attributes for the queue:
01509         struct mq_attr mqAttr;
01510         mqAttr.mq_flags = O_RDWR | O_CREAT | O_EXCL; // if the file for the messageQueue exists - we will fail.
01511         mqAttr.mq_maxmsg = messageQSize;
01512         mqAttr.mq_msgsize = sizeof(uint32_t);
01513         mqAttr.mq_curmsgs = 0;
01514         // create the message Queue. make sure no such filename exists. open with read/write/execute
01515         // for user & group.
01516 
01517         mq_h->handle = mq_open(mq_h->name, O_RDWR | O_CREAT | O_EXCL,
01518         S_IRWXU | S_IRWXG, &mqAttr);
01519         if (-1 == mq_h->handle)
01520         {
01521             status = PAL_ERR_CREATION_FAILED ;
01522             goto finish;
01523         }
01524 
01525         *messageQID = (palMessageQID_t) mq_h;
01526     }
01527     finish:
01528     if (PAL_SUCCESS != status)
01529     {
01530         if (NULL != mq_h)
01531         {
01532             free(mq_h);
01533         }
01534         *messageQID = 0;
01535     }
01536     return status;
01537 }
01538 
01539 /*! Put a message to a queue.
01540  *
01541  * @param[in] messageQID The handle for the message queue.
01542  * @param[in] info The data to send.
01543  * @param[in] timeout The timeout in milliseconds.
01544  *
01545  * All messages has the same priority (set as 0).
01546  *
01547  * \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.
01548  */
01549 palStatus_t pal_plat_osMessagePut (palMessageQID_t messageQID, uint32_t info,
01550         uint32_t timeout)
01551 {
01552     palStatus_t status = PAL_SUCCESS;
01553     int stat;
01554 
01555     palMessageQ_t* mq = (palMessageQ_t*) messageQID;
01556     if (NULL == mq)
01557     {
01558         return PAL_ERR_INVALID_ARGUMENT ;
01559     }
01560 
01561     if (PAL_RTOS_WAIT_FOREVER != timeout)
01562     {
01563         /* calculate the wait absolute time */
01564         struct timespec ts;
01565         clock_gettime(CLOCK_REALTIME, &ts);
01566 
01567         ts.tv_sec += timeout / PAL_MILLI_PER_SECOND;
01568         ts.tv_nsec += PAL_MILLI_TO_NANO(timeout);
01569         //in case there is overflow in the nanoseconds.
01570         ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND;
01571         ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND;
01572 
01573         while ((-1
01574                 == (stat = mq_timedsend(mq->handle, (const char*) &info,
01575                         sizeof(uint32_t), 0, &ts))) && (EINTR == errno))
01576         {
01577             continue; /* Restart if interrupted by handler */
01578         }
01579     }
01580     else
01581     { // wait for ever
01582         stat = mq_send(mq->handle, (const char*) &info, sizeof(uint32_t), 0);
01583     }
01584 
01585     if (-1 == stat)
01586     {
01587         if (EBADF == errno)
01588         {
01589             status = PAL_ERR_INVALID_ARGUMENT ;
01590         }
01591         else if (ETIMEDOUT == errno)
01592         {
01593             status = PAL_ERR_RTOS_TIMEOUT ;
01594         }
01595         else
01596         {
01597             // all other cases - return generic error.
01598             PAL_LOG(ERR, "Rtos put message status %d", stat);
01599             status = PAL_ERR_GENERIC_FAILURE;
01600         }
01601     }
01602     return status;
01603 }
01604 
01605 /*! Get a message or wait for a message from a queue.
01606  *
01607  * @param[in] messageQID The handle for the message queue.
01608  * @param[in] timeout The timeout in milliseconds.
01609  * @param[out] messageValue The data to send.
01610  *
01611  * \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:
01612  * PAL_ERR_RTOS_TIMEOUT -  No message arrived during the timeout period.
01613  * PAL_ERR_RTOS_RESOURCE -  No message received and there was no timeout.
01614  */
01615 palStatus_t pal_plat_osMessageGet (palMessageQID_t messageQID, uint32_t timeout,
01616         uint32_t* messageValue)
01617 {
01618     palStatus_t status = PAL_SUCCESS;
01619     int stat;
01620 
01621     palMessageQ_t* mq = (palMessageQ_t*) messageQID;
01622     if ((NULL == mq) || (NULL == messageValue))
01623     {
01624         return PAL_ERR_INVALID_ARGUMENT ;
01625     }
01626 
01627     if (PAL_RTOS_WAIT_FOREVER != timeout)
01628     {
01629         /* calculate the wait absolute time */
01630         struct timespec ts;
01631         clock_gettime(CLOCK_REALTIME, &ts);
01632 
01633         ts.tv_sec += timeout / PAL_MILLI_PER_SECOND;
01634         ts.tv_nsec += PAL_MILLI_TO_NANO(timeout);
01635         // in case there is an overflow in the nanoseconds
01636         ts.tv_sec += ts.tv_nsec / PAL_NANO_PER_SECOND;
01637         ts.tv_nsec = ts.tv_nsec % PAL_NANO_PER_SECOND;
01638 
01639         while ((-1
01640                 == (stat = mq_timedreceive(mq->handle, (char*) messageValue,
01641                         sizeof(uint32_t), 0, &ts))) && (EINTR == errno))
01642         {
01643             continue; /* Restart if interrupted by handler */
01644         }
01645     }
01646     else
01647     { // wait for ever
01648         stat = mq_receive(mq->handle, (char*) messageValue, sizeof(uint32_t), 0);
01649     }
01650 
01651     if (-1 == stat)
01652     {
01653         if (EBADF == errno)
01654         {
01655             status = PAL_ERR_INVALID_ARGUMENT ;
01656         }
01657         else if (ETIMEDOUT == errno)
01658         {
01659             status = PAL_ERR_RTOS_TIMEOUT ;
01660         }
01661         else
01662         {
01663             // all other cases - return resource error.
01664             status = PAL_ERR_RTOS_RESOURCE ;
01665         }
01666     }
01667 
01668     return status;
01669 }
01670 
01671 /*! Delete a message queue object.
01672  *
01673  * @param[inout] messageQID The handle for the message queue. In success, *messageQID = NULL.
01674  *
01675  * \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.
01676  */
01677 palStatus_t pal_plat_osMessageQueueDestroy (palMessageQID_t* messageQID)
01678 {
01679     palStatus_t status = PAL_SUCCESS;
01680     palMessageQ_t *mq = NULL;
01681     {
01682         if (NULL == messageQID)
01683         {
01684             return PAL_ERR_INVALID_ARGUMENT ;
01685         }
01686         //close the queue
01687         mq = (palMessageQ_t *) *messageQID;
01688         if (-1 == mq_close(mq->handle))
01689         {
01690             status = PAL_ERR_INVALID_ARGUMENT ;
01691             goto finish;
01692         }
01693 
01694         //unlink the file:
01695         if (-1 == mq_unlink(mq->name))
01696         {
01697             status = PAL_ERR_RTOS_RESOURCE ;
01698             goto finish;
01699         }
01700     }
01701     finish:
01702     free(mq);
01703     *messageQID = (palMessageQID_t) NULL;
01704     return status;
01705 }
01706 
01707 /*! Perform an atomic increment for a signed32 bit value.
01708  *
01709  * @param[in,out] valuePtr The address of the value to increment.
01710  * @param[in] increment The number by which to increment.
01711  *
01712  * \returns The value of the valuePtr after the increment operation.
01713  */
01714 int32_t pal_plat_osAtomicIncrement (int32_t* valuePtr, int32_t increment)
01715 {
01716     int32_t res = __sync_add_and_fetch(valuePtr, increment);
01717     return res;
01718 }
01719 
01720 
01721 void *pal_plat_malloc (size_t len)
01722 {
01723     return malloc(len);
01724 }
01725 
01726 
01727 void pal_plat_free (void * buffer)
01728 {
01729     return free(buffer);
01730 }
01731 
01732 palStatus_t pal_plat_osRandomBuffer (uint8_t *randomBuf, size_t bufSizeBytes)
01733 {
01734     palStatus_t status = PAL_SUCCESS;
01735 
01736     status = pal_plat_getRandomBufferFromHW(randomBuf, bufSizeBytes);
01737     return status;
01738 }
01739