Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Tue Jul 12 2022 19:01:36 by 1.7.2