sys_arch.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. /*
  2. * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without modification,
  6. * are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice,
  9. * this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright notice,
  11. * this list of conditions and the following disclaimer in the documentation
  12. * and/or other materials provided with the distribution.
  13. * 3. The name of the author may not be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  17. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  18. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  19. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  20. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  21. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  24. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  25. * OF SUCH DAMAGE.
  26. *
  27. * This file is part of the lwIP TCP/IP stack.
  28. *
  29. * Author: Adam Dunkels <adam@sics.se>
  30. *
  31. */
  32. //*****************************************************************************
  33. //
  34. // Include OS functionality.
  35. //
  36. //*****************************************************************************
  37. /* ------------------------ System architecture includes ----------------------------- */
  38. #include "arch/sys_arch.h"
  39. /* ------------------------ lwIP includes --------------------------------- */
  40. #include "lwip/opt.h"
  41. #include "lwip/debug.h"
  42. #include "lwip/def.h"
  43. #include "lwip/sys.h"
  44. #include "lwip/mem.h"
  45. #include "lwip/stats.h"
  46. #define LWIP_PLATFORM_DIAG(x) printf(message)
  47. /* Very crude mechanism used to determine if the critical section handling
  48. functions are being called from an interrupt context or not. This relies on
  49. the interrupt handler setting this variable manually. */
  50. portBASE_TYPE xInsideISR = pdFALSE;
  51. /*---------------------------------------------------------------------------*
  52. * Routine: sys_mbox_new
  53. *---------------------------------------------------------------------------*
  54. * Description:
  55. * Creates a new mailbox
  56. * Inputs:
  57. * int size -- Size of elements in the mailbox
  58. * Outputs:
  59. * sys_mbox_t -- Handle to new mailbox
  60. *---------------------------------------------------------------------------*/
  61. err_t sys_mbox_new( sys_mbox_t *pxMailBox, int iSize )
  62. {
  63. err_t xReturn = ERR_MEM;
  64. *pxMailBox = xQueueCreate( iSize, sizeof( void * ) );
  65. if( *pxMailBox != NULL )
  66. {
  67. xReturn = ERR_OK;
  68. SYS_STATS_INC_USED( mbox );
  69. }
  70. return xReturn;
  71. }
  72. /*---------------------------------------------------------------------------*
  73. * Routine: sys_mbox_free
  74. *---------------------------------------------------------------------------*
  75. * Description:
  76. * Deallocates a mailbox. If there are messages still present in the
  77. * mailbox when the mailbox is deallocated, it is an indication of a
  78. * programming error in lwIP and the developer should be notified.
  79. * Inputs:
  80. * sys_mbox_t mbox -- Handle of mailbox
  81. * Outputs:
  82. * sys_mbox_t -- Handle to new mailbox
  83. *---------------------------------------------------------------------------*/
  84. void sys_mbox_free( sys_mbox_t *pxMailBox )
  85. {
  86. unsigned long ulMessagesWaiting;
  87. ulMessagesWaiting = uxQueueMessagesWaiting( *pxMailBox );
  88. configASSERT( ( ulMessagesWaiting == 0 ) );
  89. #if SYS_STATS
  90. {
  91. if( ulMessagesWaiting != 0UL )
  92. {
  93. SYS_STATS_INC( mbox.err );
  94. }
  95. SYS_STATS_DEC( mbox.used );
  96. }
  97. #endif /* SYS_STATS */
  98. vQueueDelete( *pxMailBox );
  99. }
  100. /*---------------------------------------------------------------------------*
  101. * Routine: sys_mbox_post
  102. *---------------------------------------------------------------------------*
  103. * Description:
  104. * Post the "msg" to the mailbox.
  105. * Inputs:
  106. * sys_mbox_t mbox -- Handle of mailbox
  107. * void *data -- Pointer to data to post
  108. *---------------------------------------------------------------------------*/
  109. void sys_mbox_post( sys_mbox_t *pxMailBox, void *pxMessageToPost )
  110. {
  111. while( xQueueSendToBack( *pxMailBox, &pxMessageToPost, portMAX_DELAY ) != pdTRUE );
  112. }
  113. /*---------------------------------------------------------------------------*
  114. * Routine: sys_mbox_trypost
  115. *---------------------------------------------------------------------------*
  116. * Description:
  117. * Try to post the "msg" to the mailbox. Returns immediately with
  118. * error if cannot.
  119. * Inputs:
  120. * sys_mbox_t mbox -- Handle of mailbox
  121. * void *msg -- Pointer to data to post
  122. * Outputs:
  123. * err_t -- ERR_OK if message posted, else ERR_MEM
  124. * if not.
  125. *---------------------------------------------------------------------------*/
  126. err_t sys_mbox_trypost( sys_mbox_t *pxMailBox, void *pxMessageToPost )
  127. {
  128. err_t xReturn;
  129. portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
  130. if( xInsideISR != pdFALSE )
  131. {
  132. xReturn = xQueueSendFromISR( *pxMailBox, &pxMessageToPost, &xHigherPriorityTaskWoken );
  133. }
  134. else
  135. {
  136. xReturn = xQueueSend( *pxMailBox, &pxMessageToPost, ( TickType_t ) 0 );
  137. }
  138. if( xReturn == pdPASS )
  139. {
  140. xReturn = ERR_OK;
  141. }
  142. else
  143. {
  144. /* The queue was already full. */
  145. xReturn = ERR_MEM;
  146. SYS_STATS_INC( mbox.err );
  147. }
  148. return xReturn;
  149. }
  150. /*---------------------------------------------------------------------------*
  151. * Routine: sys_arch_mbox_fetch
  152. *---------------------------------------------------------------------------*
  153. * Description:
  154. * Blocks the thread until a message arrives in the mailbox, but does
  155. * not block the thread longer than "timeout" milliseconds (similar to
  156. * the sys_arch_sem_wait() function). The "msg" argument is a result
  157. * parameter that is set by the function (i.e., by doing "*msg =
  158. * ptr"). The "msg" parameter maybe NULL to indicate that the message
  159. * should be dropped.
  160. *
  161. * The return values are the same as for the sys_arch_sem_wait() function:
  162. * Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
  163. * timeout.
  164. *
  165. * Note that a function with a similar name, sys_mbox_fetch(), is
  166. * implemented by lwIP.
  167. * Inputs:
  168. * sys_mbox_t mbox -- Handle of mailbox
  169. * void **msg -- Pointer to pointer to msg received
  170. * u32_t timeout -- Number of milliseconds until timeout
  171. * Outputs:
  172. * u32_t -- SYS_ARCH_TIMEOUT if timeout, else number
  173. * of milliseconds until received.
  174. *---------------------------------------------------------------------------*/
  175. u32_t sys_arch_mbox_fetch( sys_mbox_t *pxMailBox, void **ppvBuffer, u32_t ulTimeOut )
  176. {
  177. void *pvDummy;
  178. TickType_t xStartTime, xEndTime, xElapsed;
  179. unsigned long ulReturn;
  180. xStartTime = xTaskGetTickCount();
  181. if( NULL == ppvBuffer )
  182. {
  183. ppvBuffer = &pvDummy;
  184. }
  185. if( ulTimeOut != 0UL )
  186. {
  187. configASSERT( xInsideISR == ( portBASE_TYPE ) 0 );
  188. if( pdTRUE == xQueueReceive( *pxMailBox, &( *ppvBuffer ), ulTimeOut/ portTICK_PERIOD_MS ) )
  189. {
  190. xEndTime = xTaskGetTickCount();
  191. xElapsed = ( xEndTime - xStartTime ) * portTICK_PERIOD_MS;
  192. ulReturn = xElapsed;
  193. }
  194. else
  195. {
  196. /* Timed out. */
  197. *ppvBuffer = NULL;
  198. ulReturn = SYS_ARCH_TIMEOUT;
  199. }
  200. }
  201. else
  202. {
  203. while( pdTRUE != xQueueReceive( *pxMailBox, &( *ppvBuffer ), portMAX_DELAY ) );
  204. xEndTime = xTaskGetTickCount();
  205. xElapsed = ( xEndTime - xStartTime ) * portTICK_PERIOD_MS;
  206. if( xElapsed == 0UL )
  207. {
  208. xElapsed = 1UL;
  209. }
  210. ulReturn = xElapsed;
  211. }
  212. return ulReturn;
  213. }
  214. /*---------------------------------------------------------------------------*
  215. * Routine: sys_arch_mbox_tryfetch
  216. *---------------------------------------------------------------------------*
  217. * Description:
  218. * Similar to sys_arch_mbox_fetch, but if message is not ready
  219. * immediately, we'll return with SYS_MBOX_EMPTY. On success, 0 is
  220. * returned.
  221. * Inputs:
  222. * sys_mbox_t mbox -- Handle of mailbox
  223. * void **msg -- Pointer to pointer to msg received
  224. * Outputs:
  225. * u32_t -- SYS_MBOX_EMPTY if no messages. Otherwise,
  226. * return ERR_OK.
  227. *---------------------------------------------------------------------------*/
  228. u32_t sys_arch_mbox_tryfetch( sys_mbox_t *pxMailBox, void **ppvBuffer )
  229. {
  230. void *pvDummy;
  231. unsigned long ulReturn;
  232. long lResult;
  233. portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
  234. if( ppvBuffer== NULL )
  235. {
  236. ppvBuffer = &pvDummy;
  237. }
  238. if( xInsideISR != pdFALSE )
  239. {
  240. lResult = xQueueReceiveFromISR( *pxMailBox, &( *ppvBuffer ), &xHigherPriorityTaskWoken );
  241. }
  242. else
  243. {
  244. lResult = xQueueReceive( *pxMailBox, &( *ppvBuffer ), 0UL );
  245. }
  246. if( lResult == pdPASS )
  247. {
  248. ulReturn = ERR_OK;
  249. }
  250. else
  251. {
  252. ulReturn = SYS_MBOX_EMPTY;
  253. }
  254. return ulReturn;
  255. }
  256. /*---------------------------------------------------------------------------*
  257. * Routine: sys_sem_new
  258. *---------------------------------------------------------------------------*
  259. * Description:
  260. * Creates and returns a new semaphore. The "ucCount" argument specifies
  261. * the initial state of the semaphore.
  262. * NOTE: Currently this routine only creates counts of 1 or 0
  263. * Inputs:
  264. * sys_mbox_t mbox -- Handle of mailbox
  265. * u8_t ucCount -- Initial ucCount of semaphore (1 or 0)
  266. * Outputs:
  267. * sys_sem_t -- Created semaphore or 0 if could not create.
  268. *---------------------------------------------------------------------------*/
  269. err_t sys_sem_new( sys_sem_t *pxSemaphore, u8_t ucCount )
  270. {
  271. err_t xReturn = ERR_MEM;
  272. vSemaphoreCreateBinary( ( *pxSemaphore ) );
  273. if( *pxSemaphore != NULL )
  274. {
  275. if( ucCount == 0U )
  276. {
  277. xSemaphoreTake( *pxSemaphore, 1UL );
  278. }
  279. xReturn = ERR_OK;
  280. SYS_STATS_INC_USED( sem );
  281. }
  282. else
  283. {
  284. SYS_STATS_INC( sem.err );
  285. }
  286. return xReturn;
  287. }
  288. /*---------------------------------------------------------------------------*
  289. * Routine: sys_arch_sem_wait
  290. *---------------------------------------------------------------------------*
  291. * Description:
  292. * Blocks the thread while waiting for the semaphore to be
  293. * signaled. If the "timeout" argument is non-zero, the thread should
  294. * only be blocked for the specified time (measured in
  295. * milliseconds).
  296. *
  297. * If the timeout argument is non-zero, the return value is the number of
  298. * milliseconds spent waiting for the semaphore to be signaled. If the
  299. * semaphore wasn't signaled within the specified time, the return value is
  300. * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
  301. * (i.e., it was already signaled), the function may return zero.
  302. *
  303. * Notice that lwIP implements a function with a similar name,
  304. * sys_sem_wait(), that uses the sys_arch_sem_wait() function.
  305. * Inputs:
  306. * sys_sem_t sem -- Semaphore to wait on
  307. * u32_t timeout -- Number of milliseconds until timeout
  308. * Outputs:
  309. * u32_t -- Time elapsed or SYS_ARCH_TIMEOUT.
  310. *---------------------------------------------------------------------------*/
  311. u32_t sys_arch_sem_wait( sys_sem_t *pxSemaphore, u32_t ulTimeout )
  312. {
  313. TickType_t xStartTime, xEndTime, xElapsed;
  314. unsigned long ulReturn;
  315. xStartTime = xTaskGetTickCount();
  316. if( ulTimeout != 0UL )
  317. {
  318. if( xSemaphoreTake( *pxSemaphore, ulTimeout / portTICK_PERIOD_MS ) == pdTRUE )
  319. {
  320. xEndTime = xTaskGetTickCount();
  321. xElapsed = (xEndTime - xStartTime) * portTICK_PERIOD_MS;
  322. ulReturn = xElapsed;
  323. }
  324. else
  325. {
  326. ulReturn = SYS_ARCH_TIMEOUT;
  327. }
  328. }
  329. else
  330. {
  331. while( xSemaphoreTake( *pxSemaphore, portMAX_DELAY ) != pdTRUE );
  332. xEndTime = xTaskGetTickCount();
  333. xElapsed = ( xEndTime - xStartTime ) * portTICK_PERIOD_MS;
  334. if( xElapsed == 0UL )
  335. {
  336. xElapsed = 1UL;
  337. }
  338. ulReturn = xElapsed;
  339. }
  340. return ulReturn;
  341. }
  342. /** Create a new mutex
  343. * @param mutex pointer to the mutex to create
  344. * @return a new mutex */
  345. err_t sys_mutex_new( sys_mutex_t *pxMutex )
  346. {
  347. err_t xReturn = ERR_MEM;
  348. *pxMutex = xSemaphoreCreateMutex();
  349. if( *pxMutex != NULL )
  350. {
  351. xReturn = ERR_OK;
  352. SYS_STATS_INC_USED( mutex );
  353. }
  354. else
  355. {
  356. SYS_STATS_INC( mutex.err );
  357. }
  358. return xReturn;
  359. }
  360. /** Lock a mutex
  361. * @param mutex the mutex to lock */
  362. void sys_mutex_lock( sys_mutex_t *pxMutex )
  363. {
  364. while( xSemaphoreTake( *pxMutex, portMAX_DELAY ) != pdPASS );
  365. }
  366. /** Unlock a mutex
  367. * @param mutex the mutex to unlock */
  368. void sys_mutex_unlock(sys_mutex_t *pxMutex )
  369. {
  370. xSemaphoreGive( *pxMutex );
  371. }
  372. /** Delete a semaphore
  373. * @param mutex the mutex to delete */
  374. void sys_mutex_free( sys_mutex_t *pxMutex )
  375. {
  376. SYS_STATS_DEC( mutex.used );
  377. vQueueDelete( *pxMutex );
  378. }
  379. /*---------------------------------------------------------------------------*
  380. * Routine: sys_sem_signal
  381. *---------------------------------------------------------------------------*
  382. * Description:
  383. * Signals (releases) a semaphore
  384. * Inputs:
  385. * sys_sem_t sem -- Semaphore to signal
  386. *---------------------------------------------------------------------------*/
  387. void sys_sem_signal( sys_sem_t *pxSemaphore )
  388. {
  389. portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
  390. if( xInsideISR != pdFALSE )
  391. {
  392. xSemaphoreGiveFromISR( *pxSemaphore, &xHigherPriorityTaskWoken );
  393. }
  394. else
  395. {
  396. xSemaphoreGive( *pxSemaphore );
  397. }
  398. }
  399. /*---------------------------------------------------------------------------*
  400. * Routine: sys_sem_free
  401. *---------------------------------------------------------------------------*
  402. * Description:
  403. * Deallocates a semaphore
  404. * Inputs:
  405. * sys_sem_t sem -- Semaphore to free
  406. *---------------------------------------------------------------------------*/
  407. void sys_sem_free( sys_sem_t *pxSemaphore )
  408. {
  409. SYS_STATS_DEC(sem.used);
  410. vQueueDelete( *pxSemaphore );
  411. }
  412. /*---------------------------------------------------------------------------*
  413. * Routine: sys_init
  414. *---------------------------------------------------------------------------*
  415. * Description:
  416. * Initialize sys arch
  417. *---------------------------------------------------------------------------*/
  418. void sys_init(void)
  419. {
  420. }
  421. u32_t sys_now(void)
  422. {
  423. return xTaskGetTickCount();
  424. }
  425. /*---------------------------------------------------------------------------*
  426. * Routine: sys_thread_new
  427. *---------------------------------------------------------------------------*
  428. * Description:
  429. * Starts a new thread with priority "prio" that will begin its
  430. * execution in the function "thread()". The "arg" argument will be
  431. * passed as an argument to the thread() function. The id of the new
  432. * thread is returned. Both the id and the priority are system
  433. * dependent.
  434. * Inputs:
  435. * char *name -- Name of thread
  436. * void (* thread)(void *arg) -- Pointer to function to run.
  437. * void *arg -- Argument passed into function
  438. * int stacksize -- Required stack amount in bytes
  439. * int prio -- Thread priority
  440. * Outputs:
  441. * sys_thread_t -- Pointer to per-thread timeouts.
  442. *---------------------------------------------------------------------------*/
  443. sys_thread_t sys_thread_new( const char *pcName, void( *pxThread )( void *pvParameters ), void *pvArg, int iStackSize, int iPriority )
  444. {
  445. TaskHandle_t xCreatedTask;
  446. portBASE_TYPE xResult;
  447. sys_thread_t xReturn;
  448. xResult = xTaskCreate( pxThread, pcName, iStackSize, pvArg, iPriority, &xCreatedTask );
  449. if( xResult == pdPASS )
  450. {
  451. xReturn = xCreatedTask;
  452. }
  453. else
  454. {
  455. xReturn = NULL;
  456. }
  457. return xReturn;
  458. }
  459. /*---------------------------------------------------------------------------*
  460. * Routine: sys_arch_protect
  461. *---------------------------------------------------------------------------*
  462. * Description:
  463. * This optional function does a "fast" critical region protection and
  464. * returns the previous protection level. This function is only called
  465. * during very short critical regions. An embedded system which supports
  466. * ISR-based drivers might want to implement this function by disabling
  467. * interrupts. Task-based systems might want to implement this by using
  468. * a mutex or disabling tasking. This function should support recursive
  469. * calls from the same task or interrupt. In other words,
  470. * sys_arch_protect() could be called while already protected. In
  471. * that case the return value indicates that it is already protected.
  472. *
  473. * sys_arch_protect() is only required if your port is supporting an
  474. * operating system.
  475. * Outputs:
  476. * sys_prot_t -- Previous protection level (not used here)
  477. *---------------------------------------------------------------------------*/
  478. sys_prot_t sys_arch_protect( void )
  479. {
  480. if( xInsideISR == pdFALSE )
  481. {
  482. taskENTER_CRITICAL();
  483. }
  484. return ( sys_prot_t ) 1;
  485. }
  486. /*---------------------------------------------------------------------------*
  487. * Routine: sys_arch_unprotect
  488. *---------------------------------------------------------------------------*
  489. * Description:
  490. * This optional function does a "fast" set of critical region
  491. * protection to the value specified by pval. See the documentation for
  492. * sys_arch_protect() for more information. This function is only
  493. * required if your port is supporting an operating system.
  494. * Inputs:
  495. * sys_prot_t -- Previous protection level (not used here)
  496. *---------------------------------------------------------------------------*/
  497. void sys_arch_unprotect( sys_prot_t xValue )
  498. {
  499. (void) xValue;
  500. if( xInsideISR == pdFALSE )
  501. {
  502. taskEXIT_CRITICAL();
  503. }
  504. }
  505. /*
  506. * Prints an assertion messages and aborts execution.
  507. */
  508. void sys_assert( const char *pcMessage )
  509. {
  510. (void) pcMessage;
  511. for (;;)
  512. {
  513. }
  514. }
  515. /*-------------------------------------------------------------------------*
  516. * End of File: sys_arch.c
  517. *-------------------------------------------------------------------------*/