- Main Page
- Data Structures
- Files

# sys_arch.c

Go to the documentation of this file.

    00001 /*This file has been prepared for Doxygen automatic documentation generation.*/
    00015 /* Copyright (c) 2009 Atmel Corporation. All rights reserved.
    00016  *
    00017  * Redistribution and use in source and binary forms, with or without
    00018  * modification, are permitted provided that the following conditions are met:
    00019  *
    00020  * 1. Redistributions of source code must retain the above copyright notice, this
    00021  * list of conditions and the following disclaimer.
    00022  *
    00023  * 2. Redistributions in binary form must reproduce the above copyright notice,
    00024  * this list of conditions and the following disclaimer in the documentation
    00025  * and/or other materials provided with the distribution.
    00026  *
    00027  * 3. The name of Atmel may not be used to endorse or promote products derived
    00028  * from this software without specific prior written permission.
    00029  *
    00030  * 4. This software may only be redistributed and used in connection with an Atmel
    00031  * AVR product.
    00032  *
    00033  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
    00034  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    00035  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
    00036  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
    00037  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    00038  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    00039  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    00040  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    00041  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    00042  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
    00043  *
    00044  */
    00045 #include "lwip/debug.h"
    00046 #include "lwip/sys.h"
    00047 #include "lwip/opt.h"
    00048 #include "lwip/stats.h"
    00049
    00050
    00051 #define SYS_ARCH_BLOCKING_TICKTIMEOUT    ((portTickType)10000)
    00052
    00053
    00054 // Structure associating a thread to a struct sys_timeouts
    00055 struct TimeoutlistPerThread
    00056 {
    00057   struct sys_timeouts timeouts;  // holds a pointer to a linked list of timeouts
    00058   sys_thread_t        pid;       // The thread id.
    00059 };
    00060
    00061 // Thread & struct sys_timeouts association statically allocated per thread.
    00062 // Note: SYS_THREAD_MAX is the max number of thread created by sys_thread_new()
    00063 // that can run simultaneously; it is defined in conf_lwip_threads.h.
    00064 static struct TimeoutlistPerThread Threads_TimeoutsList[SYS_THREAD_MAX];
    00065
    00066 // Number of active threads.
    00067 static u16_t NbActiveThreads = 0;
    00068
    00069 //----------- INIT -------------------------------------------------------------
    00070
    00071 // Initialize the sys_arch layer.
    00072 void sys_init(void)
    00073 {
    00074   int i;
    00075
    00076
    00077   // Initialize the the per-thread sys_timeouts structures
    00078   // make sure there are no valid pids in the list
    00079   for(i = 0; i < SYS_THREAD_MAX; i++)
    00080   {
    00081     Threads_TimeoutsList[i].pid = 0;
    00082     Threads_TimeoutsList[i].timeouts.next = NULL;
    00083   }
    00084
    00085   // keep track of how many threads have been created
    00086   NbActiveThreads = 0;
    00087 }
    00088
    00089
    00090
    00091 //----------- SEMAPHORES -------------------------------------------------------
    00092
    00093 // Creates and returns a new semaphore. The "count" argument specifies the
    00094 // initial state of the semaphore.
    00095 sys_sem_t sys_sem_new(u8_t count)
    00096 {
    00097   sys_sem_t  xSemaphore = SYS_SEM_NULL;
    00098
    00099   portENTER_CRITICAL();
    00100
    00101   vSemaphoreCreateBinary( xSemaphore );
    00102   if( xSemaphore != SYS_SEM_NULL )
    00103   {
    00104 #if SYS_STATS
    00105     lwip_stats.sys.sem.used++;
    00106     if (lwip_stats.sys.sem.used > lwip_stats.sys.sem.max) {
    00107       lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
    00108     }
    00109 #endif /* SYS_STATS */
    00110
    00111     if( 0 == count )  // Means we want the sem to be unavailable at init state.
    00112     {
    00113       xSemaphoreTake( xSemaphore, 1);
    00114     }
    00115   }
    00116
    00117   portEXIT_CRITICAL();
    00118
    00119   return xSemaphore;
    00120 }
    00121
    00122
    00123 // Frees a semaphore created by sys_sem_new.
    00124 void sys_sem_free(sys_sem_t sem)
    00125 {
    00126   if( SYS_SEM_NULL != sem )
    00127   {
    00128 #ifdef SYS_STATS
    00129     lwip_stats.sys.sem.used--;
    00130 #endif /* SYS_STATS */
    00131     vQueueDelete( sem );
    00132   }
    00133 }
    00134
    00135
    00136 // Signals (or releases) a semaphore.
    00137 void sys_sem_signal(sys_sem_t sem)
    00138 {
    00139   xSemaphoreGive( sem );
    00140 }
    00141
    00142 // Blocks the thread while waiting for the semaphore to be signaled. The timeout
    00143 // parameter specifies how many milliseconds the function should block before
    00144 // returning; if the function times out, it should return SYS_ARCH_TIMEOUT.
    00145 // If timeout=0, then the function should block indefinitely.
    00146 // If the function acquires the semaphore, it should return how many milliseconds
    00147 // expired while waiting for the semaphore. The function may return 0 if the
    00148 // semaphore was immediately available.
    00149 //
    00150 // Note that there is another function sys_sem_wait in sys.c, but it is a wrapper
    00151 // for the sys_arch_sem_wait function. Please note that it is important for the
    00152 // semaphores to return an accurate count of elapsed milliseconds, since they are
    00153 // used to schedule timers in lwIP.
    00154 u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
    00155 {
    00156   portTickType TickStart;
    00157   portTickType TickStop;
    00158   portTickType TickElapsed = (portTickType)(timeout*portTICK_RATE_MS); // Express the timeout in OS tick.
    00159
    00160
    00161   // NOTE: we assume sem != SYS_SEM_NULL; iow, we assume the calling function
    00162   // takes care of checking the sem validity before calling this function.
    00163
    00164   // NOTE: INCLUDE_xTaskGetSchedulerState must be set to 1 in FreeRTOSConfig.h
    00165   // for xTaskGetTickCount() to be available.
    00166   if( 0 == TickElapsed )
    00167   {
    00168     TickStart = xTaskGetTickCount();
    00169     // If timeout=0, then the function should block indefinitely.
    00170     while( pdFALSE == xSemaphoreTake( sem, SYS_ARCH_BLOCKING_TICKTIMEOUT ) );
    00171   }
    00172   else
    00173   {
    00174     TickStart = xTaskGetTickCount();
    00175     if( pdFALSE == xSemaphoreTake( sem, TickElapsed ) )
    00176       // if the function times out, it should return SYS_ARCH_TIMEOUT.
    00177       return( SYS_ARCH_TIMEOUT );
    00178   }
    00179   // If the function acquires the semaphore, it should return how many milliseconds
    00180   // expired while waiting for the semaphore.
    00181   TickStop = xTaskGetTickCount();
    00182   // Take care of wrap-around.
    00183   if( TickStop >= TickStart )
    00184     TickElapsed = TickStop - TickStart;
    00185   else
    00186     TickElapsed = portMAX_DELAY - TickStart + TickStop ;
    00187   return( TASK_DELAY_MS( TickElapsed ) );
    00188 }
    00189
    00190
    00191
    00192 //----------- MAILBOXES --------------------------------------------------------
    00193
    00194 // Creates an empty mailbox for maximum "size" elements. Elements stored in
    00195 // mailboxes are pointers.
    00196 // Return a new mailbox, or SYS_MBOX_NULL on error.
    00197 sys_mbox_t sys_mbox_new( int size )
    00198 {
    00199   sys_mbox_t mBoxNew;
    00200
    00201
    00202   mBoxNew = xQueueCreate( size, sizeof( void * ) );
    00203 #if SYS_STATS
    00204   if( SYS_MBOX_NULL != mBoxNew )
    00205   {
    00206     lwip_stats.sys.mbox.used++;
    00207     if (lwip_stats.sys.mbox.used > lwip_stats.sys.mbox.max)
    00208     {
    00209       lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
    00210     }
    00211   }
    00212 #endif /* SYS_STATS */
    00213   return( mBoxNew );
    00214 }
    00215
    00216
    00217 // Deallocates a mailbox.
    00218 // If there are messages still present in the mailbox when the mailbox is
    00219 // deallocated, it is an indication of a programming error in lwIP and the
    00220 // developer should be notified.
    00221 void sys_mbox_free(sys_mbox_t mbox)
    00222 {
    00223   if( SYS_MBOX_NULL != mbox )
    00224   {
    00225 #ifdef SYS_STATS
    00226     lwip_stats.sys.mbox.used--;
    00227 #endif /* SYS_STATS */
    00228     vQueueDelete( mbox );
    00229   }
    00230 }
    00231
    00232
    00233 // Posts the "msg" to the mailbox. This function have to block until the "msg"
    00234 // is really posted.
    00235 void sys_mbox_post(sys_mbox_t mbox, void *msg)
    00236 {
    00237   // NOTE: we assume mbox != SYS_MBOX_NULL; iow, we assume the calling function
    00238   // takes care of checking the mbox validity before calling this function.
    00239   while( pdTRUE != xQueueSend( mbox, &msg, SYS_ARCH_BLOCKING_TICKTIMEOUT ) );
    00240 }
    00241
    00242
    00243 // Try to post the "msg" to the mailbox.
    00244 // Returns ERR_MEM if the mailbox is full,
    00245 // else, ERR_OK if the "msg" is posted.
    00246 err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
    00247 {
    00248   if( errQUEUE_FULL == xQueueSend( mbox, &msg, 0 ) )
    00249     return( ERR_MEM );
    00250   else
    00251     return( ERR_OK );
    00252 }
    00253
    00254
    00255 // Blocks the thread until a message arrives in the mailbox, but does not block
    00256 // the thread longer than "timeout" milliseconds (similar to the sys_arch_sem_wait()
    00257 // function).
    00258 // If "timeout" is 0, the thread should be blocked until a message arrives.
    00259 // The "msg" argument is a result parameter that is set by the function (i.e., by
    00260 // doing "*msg = ptr"). The "msg" parameter maybe NULL to indicate that the message
    00261 // should be dropped.
    00262 //
    00263 // The return values are the same as for the sys_arch_sem_wait() function:
    00264 // Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a timeout.
    00265 //
    00266 // Note that a function with a similar name, sys_mbox_fetch(), is implemented by lwIP.
    00267 u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
    00268 {
    00269   portTickType TickStart;
    00270   portTickType TickStop;
    00271   portTickType TickElapsed = (portTickType)(timeout*portTICK_RATE_MS); // Express the timeout in OS tick.
    00272   void         *tempoptr;
    00273
    00274
    00275   // NOTE: we assume mbox != SYS_MBOX_NULL; iow, we assume the calling function
    00276   // takes care of checking the mbox validity before calling this function.
    00277
    00278   if(msg == NULL)
    00279   {
    00280       msg = &tempoptr;
    00281   }
    00282
    00283   // NOTE: INCLUDE_xTaskGetSchedulerState must be set to 1 in FreeRTOSConfig.h
    00284   // for xTaskGetTickCount() to be available.
    00285   if( 0 == TickElapsed )
    00286   {
    00287     TickStart = xTaskGetTickCount();
    00288     // If "timeout" is 0, the thread should be blocked until a message arrives.
    00289     while( pdFALSE == xQueueReceive( mbox, &(*msg), SYS_ARCH_BLOCKING_TICKTIMEOUT ) );
    00290   }
    00291   else
    00292   {
    00293     TickStart = xTaskGetTickCount();
    00294     if( pdFALSE == xQueueReceive( mbox, &(*msg), TickElapsed ) )
    00295     {
    00296       *msg = NULL;
    00297       // if the function times out, it should return SYS_ARCH_TIMEOUT.
    00298       return( SYS_ARCH_TIMEOUT );
    00299     }
    00300   }
    00301   // If the function gets a msg, it should return the number of ms spent waiting.
    00302   TickStop = xTaskGetTickCount();
    00303   // Take care of wrap-around.
    00304   if( TickStop >= TickStart )
    00305     TickElapsed = TickStop - TickStart;
    00306   else
    00307     TickElapsed = portMAX_DELAY - TickStart + TickStop ;
    00308   return( TASK_DELAY_MS( TickElapsed ) );
    00309 }
    00310
    00311
    00312 // This is similar to sys_arch_mbox_fetch, however if a message is not present
    00313 // in the mailbox, it immediately returns with the code SYS_MBOX_EMPTY.
    00314 // On success 0 is returned.
    00315 //
    00316 u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
    00317 {
    00318   void  *tempoptr;
    00319
    00320
    00321   if(msg == NULL)
    00322   {
    00323     msg = &tempoptr;
    00324   }
    00325   if( pdFALSE == xQueueReceive( mbox, &(*msg), 0 ) )
    00326     // if a message is not present in the mailbox, it immediately returns with
    00327     // the code SYS_MBOX_EMPTY.
    00328     return( SYS_MBOX_EMPTY );
    00329   // On success 0 is returned.
    00330   return( 0 );
    00331 }
    00332
    00333
    00334
    00335 //----------- LWIP TIMEOUTS ----------------------------------------------------
    00336
    00337 // Returns a pointer to the per-thread sys_timeouts structure.
    00338 // In lwIP, each thread has a list of timeouts which is repressented as a linked
    00339 // list of sys_timeout structures. The sys_timeouts structure holds a pointer to
    00340 // a linked list of timeouts. This function is called by the lwIP timeout
    00341 // scheduler and must not return a NULL value.
    00342 struct sys_timeouts *sys_arch_timeouts(void)
    00343 {
    00344   int                         i;
    00345   sys_thread_t                pid;
    00346   struct TimeoutlistPerThread *tl;
    00347
    00348
    00349   // Get the current thread id.
    00350   // Note: INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 in FreeRTOSConfig.h
    00351   // for xTaskGetCurrentTaskHandle() to be available.
    00352   pid = xTaskGetCurrentTaskHandle( );
    00353
    00354   for(i = 0; i < NbActiveThreads; i++)
    00355   {
    00356     tl = &(Threads_TimeoutsList[i]);
    00357     if(tl->pid == pid)
    00358     {
    00359       return &(tl->timeouts);
    00360     }
    00361   }
    00362
    00363   // If we're here, this means the scheduler gave the focus to the task as it was
    00364   // being created(because of a higher priority). Since Threads_TimeoutsList[]
    00365   // update is done just after the task creation, the array is not up-to-date.
    00366   // => the last array entry must be the one of the current task.
    00367   return( &(Threads_TimeoutsList[NbActiveThreads].timeouts) );
    00368 }
    00369
    00370
    00371 // Used to instantiate a thread for lwIP.
    00372 // Starts a new thread named "name" with priority "prio" that will begin its
    00373 // execution in the function "thread()". The "arg" argument will be passed as an
    00374 // argument to the thread() function. The stack size to used for this thread is
    00375 // the "stacksize" parameter. The id of the new thread is returned. Both the id
    00376 // and the priority are system dependent.
    00377
    00378 sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
    00379 {
    00380   sys_thread_t    newthread;
    00381   portBASE_TYPE   result;
    00382   SYS_ARCH_DECL_PROTECT(protectionLevel);
    00383
    00384   result = xTaskCreate( thread, (signed portCHAR *)name, stacksize, arg, prio, &newthread );
    00385
    00386   // Need to protect this -- preemption here could be a problem!
    00387   SYS_ARCH_PROTECT(protectionLevel);
    00388   if( pdPASS == result )
    00389   {
    00390     // For each task created, store the task handle (pid) in the timers array.
    00391     // This scheme doesn't allow for threads to be deleted
    00392     Threads_TimeoutsList[NbActiveThreads++].pid = newthread;
    00393   }
    00394   else
    00395   {
    00396     newthread = NULL;
    00397   }
    00398   SYS_ARCH_UNPROTECT(protectionLevel);
    00399
    00400   return( newthread );
    00401 }
    00402
    00403
    00404
    00405 //----------- PREEMPTION PROTECTION --------------------------------------------
    00406
    00407 // This optional function does a "fast" critical region protection and returns
    00408 // the previous protection level. This function is only called during very short
    00409 // critical regions. An embedded system which supports ISR-based drivers might
    00410 // want to implement this function by disabling interrupts. Task-based systems
    00411 // might want to implement this by using a mutex or disabling tasking. This
    00412 // function should support recursive calls from the same task or interrupt. In
    00413 // other words, sys_arch_protect() could be called while already protected. In
    00414 // that case the return value indicates that it is already protected.
    00415 extern volatile unsigned portLONG ulCriticalNesting;
    00416 sys_prot_t sys_arch_protect(void)
    00417 {
    00418   vPortEnterCritical();
    00419   return 1; // Not used
    00420 }
    00421
    00422
    00423 // This optional function does a "fast" set of critical region protection to the
    00424 // value specified by pval.
    00425 void sys_arch_unprotect(sys_prot_t pval)
    00426 {
    00427   vPortExitCritical();
    00428 }