]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/lwIP_MCF5235_GCC/lwip/contrib/port/FreeRTOS/MCF5235/sys_arch.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / lwIP_MCF5235_GCC / lwip / contrib / port / FreeRTOS / MCF5235 / sys_arch.c
1 /*\r
2  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
3  * Modifications Copyright (c) 2006 Christian Walter <wolti@sil.at>\r
4  * All rights reserved.\r
5  *\r
6  * Redistribution and use in source and binary forms, with or without modification,\r
7  * are permitted provided that the following conditions are met:\r
8  *\r
9  * 1. Redistributions of source code must retain the above copyright notice,\r
10  *    this list of conditions and the following disclaimer.\r
11  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
12  *    this list of conditions and the following disclaimer in the documentation\r
13  *    and/or other materials provided with the distribution.\r
14  * 3. The name of the author may not be used to endorse or promote products\r
15  *    derived from this software without specific prior written permission.\r
16  *\r
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
20  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
22  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
26  * OF SUCH DAMAGE.\r
27  *\r
28  * This file is part of the lwIP TCP/IP stack.\r
29  *\r
30  * Author: Adam Dunkels <adam@sics.se>\r
31  * Modifcations: Christian Walter <wolti@sil.at>\r
32  *\r
33  * $Id: sys_arch.c,v 1.6 2006/09/24 22:04:53 wolti Exp $\r
34  */\r
35 \r
36 /* ------------------------ System includes ------------------------------- */\r
37 #include <string.h>\r
38 #include <stdlib.h>\r
39 #include <stdarg.h>\r
40 #include <stdio.h>\r
41 \r
42 /* ------------------------ FreeRTOS includes ----------------------------- */\r
43 #include "FreeRTOS.h"\r
44 #include "task.h"\r
45 #include "semphr.h"\r
46 \r
47 /* ------------------------ lwIP includes --------------------------------- */\r
48 #include "lwip/debug.h"\r
49 #include "lwip/def.h"\r
50 #include "lwip/sys.h"\r
51 #include "lwip/mem.h"\r
52 #include "lwip/sio.h"\r
53 #include "lwip/stats.h"\r
54 \r
55 /* ------------------------ Project includes ------------------------------ */\r
56 \r
57 /* ------------------------ Defines --------------------------------------- */\r
58 /* This is the number of threads that can be started with sys_thead_new() */\r
59 #define SYS_MBOX_SIZE               ( 16 )\r
60 #define MS_TO_TICKS( ms )           \\r
61     ( portTickType )( ( portTickType ) ( ms ) / portTICK_RATE_MS )\r
62 #define TICKS_TO_MS( ticks )        \\r
63     ( unsigned long )( ( portTickType ) ( ticks ) * portTICK_RATE_MS )\r
64 #define THREAD_STACK_SIZE           ( 1024 )\r
65 #define THREAD_NAME                 "lwIP"\r
66 \r
67 #define THREAD_INIT( tcb ) \\r
68     do { \\r
69         tcb->next = NULL; \\r
70         tcb->pid = ( xTaskHandle )0; \\r
71         tcb->timeouts.next = NULL; \\r
72     } while( 0 )\r
73 \r
74 /* ------------------------ Type definitions ------------------------------ */\r
75 typedef struct sys_tcb\r
76 {\r
77     struct sys_tcb *next;\r
78     struct sys_timeouts timeouts;\r
79     xTaskHandle     pid;\r
80 } sys_tcb_t;\r
81 \r
82 /* ------------------------ Prototypes ------------------------------------ */\r
83 \r
84 /* ------------------------ Static functions ------------------------------ */\r
85 sys_tcb_t      *sys_thread_current( void );\r
86 \r
87 /* ------------------------ Static variables ------------------------------ */\r
88 static sys_tcb_t *tasks = NULL;\r
89 \r
90 /* ------------------------ Start implementation -------------------------- */\r
91 void\r
92 sys_init( void )\r
93 {\r
94     LWIP_ASSERT( "sys_init: not called first", tasks == NULL );\r
95     tasks = NULL;\r
96 }\r
97 \r
98 /*\r
99  * This optional function does a "fast" critical region protection and returns\r
100  * the previous protection level. This function is only called during very short\r
101  * critical regions. An embedded system which supports ISR-based drivers might\r
102  * want to implement this function by disabling interrupts. Task-based systems\r
103  * might want to implement this by using a mutex or disabling tasking. This\r
104  * function should support recursive calls from the same task or interrupt. In\r
105  * other words, sys_arch_protect() could be called while already protected. In\r
106  * that case the return value indicates that it is already protected.\r
107  *\r
108  * sys_arch_protect() is only required if your port is supporting an operating\r
109  * system.\r
110  */\r
111 sys_prot_t\r
112 sys_arch_protect( void )\r
113 {\r
114     vPortEnterCritical(  );\r
115     return 1;\r
116 }\r
117 \r
118 /*\r
119  * This optional function does a "fast" set of critical region protection to the\r
120  * value specified by pval. See the documentation for sys_arch_protect() for\r
121  * more information. This function is only required if your port is supporting\r
122  * an operating system.\r
123  */\r
124 void\r
125 sys_arch_unprotect( sys_prot_t pval )\r
126 {\r
127     ( void )pval;\r
128     vPortExitCritical(  );\r
129 }\r
130 \r
131 /*\r
132  * Prints an assertion messages and aborts execution.\r
133  */\r
134 void\r
135 sys_assert( const char *msg )\r
136 {\r
137         fputs( msg, stderr );\r
138         fputs( "\n\r", stderr );\r
139     vPortEnterCritical(  );\r
140     for( ;; );\r
141 }\r
142 \r
143 void\r
144 sys_debug( const char *const fmt, ... )\r
145 {\r
146     va_list         ap;\r
147 \r
148     va_start( ap, fmt );\r
149     ( void )vprintf( fmt, ap );\r
150     ( void )putchar( '\r' );\r
151     va_end( ap );\r
152 }\r
153 \r
154 /* ------------------------ Start implementation ( Threads ) -------------- */\r
155 \r
156 sys_thread_t\r
157 sys_thread_new( void ( *thread ) ( void *arg ), void *arg, int prio )\r
158 {\r
159     return sys_arch_thread_new( thread, arg, prio, THREAD_STACK_SIZE );\r
160 }\r
161 \r
162 /*\r
163  * Starts a new thread with priority "prio" that will begin its execution in the\r
164  * function "thread()". The "arg" argument will be passed as an argument to the\r
165  * thread() function. The argument "ssize" is the requested stack size for the\r
166  * new thread. The id of the new thread is returned. Both the id and the\r
167   * priority are system dependent.\r
168  */\r
169 sys_thread_t\r
170 sys_arch_thread_new( void ( *thread ) ( void *arg ), void *arg, int prio, size_t ssize )\r
171 {\r
172     sys_thread_t    thread_hdl = SYS_THREAD_NULL;\r
173     int             i;\r
174     sys_tcb_t      *p;\r
175     char            thread_name[ configMAX_TASK_NAME_LEN ];\r
176 \r
177     /* We disable the FreeRTOS scheduler because it might be the case that the new\r
178      * tasks gets scheduled inside the xTaskCreate function. To prevent this we\r
179      * disable the scheduling. Note that this can happen although we have interrupts\r
180      * disabled because xTaskCreate contains a call to taskYIELD( ).\r
181      */\r
182     vPortEnterCritical(  );\r
183 \r
184     p = tasks;\r
185     i = 0;\r
186     /* We are called the first time. Initialize it. */\r
187     if( p == NULL )\r
188     {\r
189         p = pvPortMalloc( sizeof( sys_tcb_t ) );\r
190         if( p != NULL )\r
191         {\r
192             tasks = p;\r
193         }\r
194     }\r
195     else\r
196     {\r
197         /* First task already counter. */\r
198         i++;\r
199         /* Cycle to the end of the list. */\r
200         while( p->next != NULL )\r
201         {\r
202             i++;\r
203             p = p->next;\r
204         }\r
205         p->next = pvPortMalloc( sizeof( sys_tcb_t ) );\r
206         p = p->next;\r
207     }\r
208 \r
209     if( p != NULL )\r
210     {\r
211         /* Memory allocated. Initialize the data structure. */\r
212         THREAD_INIT( p );\r
213         ( void )snprintf( thread_name, configMAX_TASK_NAME_LEN, "lwIP%d", i );\r
214 \r
215         /* Now q points to a free element in the list. */\r
216         if( xTaskCreate( thread, thread_name, ssize, arg, prio, &p->pid ) == pdPASS )\r
217         {\r
218             thread_hdl = p;\r
219         }\r
220         else\r
221         {\r
222             vPortFree( p );\r
223         }\r
224     }\r
225 \r
226     vPortExitCritical(  );\r
227     return thread_hdl;\r
228 }\r
229 \r
230 void\r
231 sys_arch_thread_remove( sys_thread_t hdl )\r
232 {\r
233     sys_tcb_t      *current = tasks, *prev;\r
234     sys_tcb_t      *toremove = hdl;\r
235     xTaskHandle     pid = ( xTaskHandle ) 0;\r
236 \r
237     LWIP_ASSERT( "sys_arch_thread_remove: assertion hdl != NULL failed!", hdl != NULL );\r
238 \r
239     /* If we have to remove the first task we must update the global "tasks"\r
240      * variable. */\r
241     vPortEnterCritical(  );\r
242     if( hdl != NULL )\r
243     {\r
244         prev = NULL;\r
245         while( ( current != NULL ) && ( current != toremove ) )\r
246         {\r
247             prev = current;\r
248             current = current->next;\r
249         }\r
250         /* Found it. */\r
251         if( current == toremove )\r
252         {\r
253             /* Not the first entry in the list. */\r
254             if( prev != NULL )\r
255             {\r
256                 prev->next = toremove->next;\r
257             }\r
258             else\r
259             {\r
260                 tasks = toremove->next;\r
261             }\r
262             LWIP_ASSERT( "sys_arch_thread_remove: can't remove thread with timeouts!",\r
263                          toremove->timeouts.next == NULL );\r
264             pid = toremove->pid;\r
265             THREAD_INIT( toremove );\r
266             vPortFree( toremove );\r
267         }\r
268     }\r
269     /* We are done with accessing the shared datastructure. Release the \r
270      * resources.\r
271      */\r
272     vPortExitCritical(  );\r
273     if( pid != ( xTaskHandle ) 0 )\r
274     {\r
275         vTaskDelete( pid );\r
276         /* not reached. */\r
277     }\r
278 }\r
279 \r
280 /*\r
281  * Returns the thread control block for the currently active task. In case\r
282  * of an error the functions returns NULL.\r
283  */\r
284 sys_thread_t\r
285 sys_arch_thread_current( void )\r
286 {\r
287     sys_tcb_t      *p = tasks;\r
288     xTaskHandle     pid = xTaskGetCurrentTaskHandle(  );\r
289 \r
290     vPortEnterCritical(  );\r
291     while( ( p != NULL ) && ( p->pid != pid ) )\r
292     {\r
293         p = p->next;\r
294     }\r
295     vPortExitCritical(  );\r
296     return p;\r
297 }\r
298 \r
299 /*\r
300  * Returns a pointer to the per-thread sys_timeouts structure. In lwIP,\r
301  * each thread has a list of timeouts which is represented as a linked\r
302  * list of sys_timeout structures. The sys_timeouts structure holds a\r
303  * pointer to a linked list of timeouts. This function is called by\r
304  * the lwIP timeout scheduler and must not return a NULL value.\r
305  *\r
306  * In a single threaded sys_arch implementation, this function will\r
307  * simply return a pointer to a global sys_timeouts variable stored in\r
308  * the sys_arch module.\r
309  */\r
310 struct sys_timeouts *\r
311 sys_arch_timeouts( void )\r
312 {\r
313     sys_tcb_t      *ptask;\r
314 \r
315     ptask = sys_arch_thread_current(  );\r
316     LWIP_ASSERT( "sys_arch_timeouts: ptask != NULL", ptask != NULL );\r
317     return ptask != NULL ? &( ptask->timeouts ) : NULL;\r
318 }\r
319 \r
320 /* ------------------------ Start implementation ( Semaphores ) ----------- */\r
321 \r
322 /* Creates and returns a new semaphore. The "count" argument specifies\r
323  * the initial state of the semaphore.\r
324  */\r
325 sys_sem_t\r
326 sys_sem_new( u8_t count )\r
327 {\r
328     xSemaphoreHandle xSemaphore;\r
329 \r
330     vSemaphoreCreateBinary( xSemaphore );\r
331     if( xSemaphore != SYS_SEM_NULL )\r
332     {\r
333         if( count == 0 )\r
334         {\r
335             xSemaphoreTake( xSemaphore, 1 );\r
336         }\r
337 #ifdef SYS_STATS\r
338         vPortEnterCritical(  );\r
339         lwip_stats.sys.sem.used++;\r
340         if( lwip_stats.sys.sem.used > lwip_stats.sys.sem.max )\r
341         {\r
342             lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;\r
343         }\r
344         vPortExitCritical(  );\r
345 #endif\r
346     }\r
347     else\r
348     {\r
349         LWIP_ASSERT( "sys_sem_new: xSemaphore == SYS_SEM_NULL", xSemaphore != SYS_SEM_NULL );\r
350     }\r
351 \r
352     return xSemaphore;\r
353 }\r
354 \r
355 /* Deallocates a semaphore */\r
356 void\r
357 sys_sem_free( sys_sem_t sem )\r
358 {\r
359     LWIP_ASSERT( "sys_sem_free: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );\r
360     if( sem != SYS_SEM_NULL )\r
361     {\r
362 #ifdef SYS_STATS\r
363         vPortEnterCritical(  );\r
364         lwip_stats.sys.sem.used--;\r
365         vPortExitCritical(  );\r
366 #endif\r
367         vQueueDelete( sem );\r
368     }\r
369 }\r
370 \r
371 /* Signals a semaphore */\r
372 void\r
373 sys_sem_signal( sys_sem_t sem )\r
374 {\r
375     LWIP_ASSERT( "sys_sem_signal: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );\r
376     xSemaphoreGive( sem );\r
377 }\r
378 \r
379 /*\r
380  * Blocks the thread while waiting for the semaphore to be\r
381  * signaled. If the "timeout" argument is non-zero, the thread should\r
382  * only be blocked for the specified time (measured in\r
383  * milliseconds).\r
384  *\r
385  * If the timeout argument is non-zero, the return value is the number of\r
386  * milliseconds spent waiting for the semaphore to be signaled. If the\r
387  * semaphore wasn't signaled within the specified time, the return value is\r
388  * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore\r
389  * (i.e., it was already signaled), the function may return zero.\r
390  *\r
391  * Notice that lwIP implements a function with a similar name,\r
392  * sys_sem_wait(), that uses the sys_arch_sem_wait() function.\r
393  */\r
394 u32_t\r
395 sys_arch_sem_wait( sys_sem_t sem, u32_t timeout )\r
396 {\r
397     portBASE_TYPE   xStatus;\r
398     portTickType    xTicksStart, xTicksEnd, xTicksElapsed;\r
399     u32_t           timespent;\r
400 \r
401     LWIP_ASSERT( "sys_arch_sem_wait: sem != SYS_SEM_NULL", sem != SYS_SEM_NULL );\r
402     xTicksStart = xTaskGetTickCount(  );\r
403     if( timeout == 0 )\r
404     {\r
405         do\r
406         {\r
407             xStatus = xSemaphoreTake( sem, MS_TO_TICKS( 100 ) );\r
408         }\r
409         while( xStatus != pdTRUE );\r
410     }\r
411     else\r
412     {\r
413         xStatus = xSemaphoreTake( sem, MS_TO_TICKS( timeout ) );\r
414     }\r
415 \r
416     /* Semaphore was signaled. */\r
417     if( xStatus == pdTRUE )\r
418     {\r
419         xTicksEnd = xTaskGetTickCount(  );\r
420         xTicksElapsed = xTicksEnd - xTicksStart;\r
421         timespent = TICKS_TO_MS( xTicksElapsed );\r
422     }\r
423     else\r
424     {\r
425         timespent = SYS_ARCH_TIMEOUT;\r
426     }\r
427     return timespent;\r
428 }\r
429 \r
430 \r
431 /* ------------------------ Start implementation ( Mailboxes ) ------------ */\r
432 \r
433 /* Creates an empty mailbox. */\r
434 sys_mbox_t\r
435 sys_mbox_new( void )\r
436 {\r
437     xQueueHandle    mbox;\r
438 \r
439     mbox = xQueueCreate( SYS_MBOX_SIZE, sizeof( void * ) );\r
440     if( mbox != SYS_MBOX_NULL )\r
441     {\r
442 #ifdef SYS_STATS\r
443         vPortEnterCritical(  );\r
444         lwip_stats.sys.mbox.used++;\r
445         if( lwip_stats.sys.mbox.used > lwip_stats.sys.mbox.max )\r
446         {\r
447             lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;\r
448         }\r
449         vPortExitCritical(  );\r
450 #endif\r
451     }\r
452     return mbox;\r
453 }\r
454 \r
455 /*\r
456   Deallocates a mailbox. If there are messages still present in the\r
457   mailbox when the mailbox is deallocated, it is an indication of a\r
458   programming error in lwIP and the developer should be notified.\r
459 */\r
460 void\r
461 sys_mbox_free( sys_mbox_t mbox )\r
462 {\r
463     void           *msg;\r
464 \r
465     LWIP_ASSERT( "sys_mbox_free: mbox != SYS_MBOX_NULL", mbox != SYS_MBOX_NULL );\r
466     if( mbox != SYS_MBOX_NULL )\r
467     {\r
468         while( uxQueueMessagesWaiting( mbox ) != 0 )\r
469         {\r
470             if( sys_arch_mbox_fetch( mbox, &msg, 1 ) != SYS_ARCH_TIMEOUT )\r
471             {\r
472                 LWIP_ASSERT( "sys_mbox_free: memory leak (msg != NULL)", msg == NULL );\r
473             }\r
474         }\r
475         vQueueDelete( mbox );\r
476 #ifdef SYS_STATS\r
477         vPortEnterCritical(  );\r
478         lwip_stats.sys.mbox.used--;\r
479         vPortExitCritical(  );\r
480 #endif\r
481     }\r
482 }\r
483 \r
484 /*\r
485  * This function sends a message to a mailbox. It is unusual in that no error\r
486  * return is made. This is because the caller is responsible for ensuring that\r
487  * the mailbox queue will not fail. The caller does this by limiting the number\r
488  * of msg structures which exist for a given mailbox.\r
489  */\r
490 void\r
491 sys_mbox_post( sys_mbox_t mbox, void *data )\r
492 {\r
493     portBASE_TYPE   xQueueSent;\r
494 \r
495     /* Queue must not be full - Otherwise it is an error. */\r
496     xQueueSent = xQueueSend( mbox, &data, 0 );\r
497     LWIP_ASSERT( "sys_mbox_post: xQueueSent == pdPASS", xQueueSent == pdPASS );\r
498 }\r
499 \r
500 /*\r
501  * Blocks the thread until a message arrives in the mailbox, but does\r
502  * not block the thread longer than "timeout" milliseconds (similar to\r
503  * the sys_arch_sem_wait() function). The "msg" argument is a result\r
504  * parameter that is set by the function (i.e., by doing "*msg =\r
505  * ptr"). The "msg" parameter maybe NULL to indicate that the message\r
506  * should be dropped.\r
507  *\r
508  * Note that a function with a similar name, sys_mbox_fetch(), is\r
509  * implemented by lwIP.\r
510  */\r
511 u32_t\r
512 sys_arch_mbox_fetch( sys_mbox_t mbox, void **msg, u32_t timeout )\r
513 {\r
514     void           *ret_msg;\r
515     portBASE_TYPE   xStatus;\r
516     portTickType    xTicksStart, xTicksEnd, xTicksElapsed;\r
517     u32_t           timespent;\r
518 \r
519     LWIP_ASSERT( "sys_arch_mbox_fetch: mbox != SYS_MBOX_NULL", mbox != SYS_MBOX_NULL );\r
520     xTicksStart = xTaskGetTickCount(  );\r
521     if( timeout == 0 )\r
522     {\r
523         do\r
524         {\r
525             xStatus = xQueueReceive( mbox, &ret_msg, MS_TO_TICKS( 100 ) );\r
526         }\r
527         while( xStatus != pdTRUE );\r
528     }\r
529     else\r
530     {\r
531         xStatus = xQueueReceive( mbox, &ret_msg, MS_TO_TICKS( timeout ) );\r
532     }\r
533 \r
534     if( xStatus == pdTRUE )\r
535     {\r
536         if( msg )\r
537         {\r
538             *msg = ret_msg;\r
539         }\r
540         xTicksEnd = xTaskGetTickCount(  );\r
541         xTicksElapsed = xTicksEnd - xTicksStart;\r
542         timespent = TICKS_TO_MS( xTicksElapsed );\r
543     }\r
544     else\r
545     {\r
546         if( msg )\r
547         {\r
548             *msg = NULL;\r
549         }\r
550         timespent = SYS_ARCH_TIMEOUT;\r
551     }\r
552     return timespent;\r
553 }\r
554 \r
555 u32_t\r
556 sys_jiffies( void )\r
557 {\r
558     portTickType    xTicks = xTaskGetTickCount(  );\r
559 \r
560     return ( u32_t )TICKS_TO_MS( xTicks );\r
561 }\r