Milos RTOS v0.3.4a
Real Time Operating System
event.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  * event.c
00003  * (C) 2010 Ivan Meleca
00004  * Based on original code written by Ruben Meleca
00005  * www.milos.it
00006 
00007 #   This program is free software; you can redistribute it and/or modify
00008 #   it under the terms of the GNU General Public License as published by
00009 #   the Free Software Foundation; either version 2 of the License, or
00010 #   (at your option) any later version.
00011 #
00012 #   This program is distributed in the hope that it will be useful,
00013 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 #   GNU General Public License for more details.
00016 #
00017 #   You should have received a copy of the GNU General Public License
00018 #   along with this program; if not, write to the Free Software
00019 #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 
00021 ***************************************************************************/
00022 
00023 #include "event.h"
00024 #include "system.h"
00025 #include <common/thlist.h>
00026 
00061 __STATIC __VOID __eventQueueThread(__PEVENT ev, __PTHREAD th, u32 timeout)
00062 {
00063 
00064     /* This function is called with disabled interrupts */
00065 
00066     /* Suspend the thread */
00067     th->th_wait = CPU_MS_TO_TICKS(timeout);
00068     __threadSuspend(th, __THSTS_WAITING);
00069 
00070     /* Insert the thread in the list */
00071     __thlAddEvtPrio(th, &ev->ev_threads);
00072 }
00073 
00083 __STATIC __VOID __eventDequeueThread(__PEVENT ev, __PTHREAD th)
00084 {
00085     __thlRemoveEvtPrio(th, &ev->ev_threads);
00086 }
00087 
00094 __STATIC __VOID __eventSignal(__PEVENT ev, u8 val)
00095 {
00096     __PTHREAD th;
00097 
00098     /* Signal the event */
00099     ev->ev_state = val;
00100 
00101     /* wake up the thread
00102      * (if any, we can be setting an event with no one waiting for it)
00103      */
00104     if (ev->ev_threads)
00105     {
00106         /* Disable interrupts */
00107         __systemStop();
00108 
00109         /* wake up each thread, schedule if one of these threads
00110          * has a higher priority than the current (running) one.
00111          * The worst case here is when ALL threads, except the running
00112          * one are waiting for this event.
00113          */
00114 
00115         /* If the first thread of the list has a higher priority of the current
00116          * one is enough to preempt (the list is ordered by priority)
00117          */
00118         if (__threadGetCurrent())
00119         {
00120             if (__threadGetCurrent()->th_priority > ev->ev_threads->th_priority)
00121             {
00122                 /*
00123                  * Check if the current thread disabled the scheduler,
00124                  * if not, add the current thread to the ready list,
00125                  * __threadCurrent to __NULL and set scheduler.
00126                  */
00127                 if (!__systemSchedulerDisabled())
00128                 {
00129 
00130                     /* Add the current thread to the ready list */
00131                     __threadAddToReadyList(__threadGetCurrent());
00132 
00133                     /* We have no thread in execution */
00134                     __threadSetCurrent(__NULL);
00135                 }
00136 
00137                 /* Schedule context switch */
00138                 __systemScheduleThreadChange();
00139             }
00140         } else {
00141 
00142             /* No thread running
00143              * Schedule context switch anyway
00144              */
00145             __systemScheduleThreadChange();
00146         }
00147 
00148         /* Scan the event's thread list */
00149         th = ev->ev_threads;
00150         while (th)
00151         {
00152             /* Here we will check if the thread is ready.
00153              * Can happen that a READY thread that went through timeout
00154              * it is being set as READY again and removed from suspended
00155              * and REINSERTED in the ready list TWICE.
00156              */
00157             if (th->th_status == __THSTS_WAITING)
00158             {
00159                 __threadRemoveFromSuspended(th);
00160                 __threadAddToReadyList(th);
00161             }
00162 
00163             th = th->th_evnext;
00164         }
00165 
00166         __systemStart();
00167     }
00168 }
00169 
00184 u8  __eventWait(__PEVENT ev, u32 timeout)
00185 {
00186     u8 ret = 0;
00187     u32 irqs = 0;
00188     __PTHREAD th;
00189 
00190     /* Arrived here with interrupts disabled? */
00191     irqs = __systemGetIrqCount();
00192     if (!irqs)
00193     {
00194         /* Go critical */
00195         __systemStop();
00196     } else {
00197         /* Remove all pending irq enabled.
00198          * The next call to __systemStart (before switching context)
00199          * SHOULD really enable interrupts. So we save the interrupt-disabled
00200          * counter in irqs, to re-establish the __systemIrqCount counter on function
00201          * exit.
00202          */
00203         while (__systemGetIrqCount() != 1) __systemStart();
00204     }
00205 
00206     /* Check if the event is already set */
00207     if (ev->ev_state != __EV_RESET)
00208     {
00209         /*  Means the event was set before entering this function.
00210             That's why the __eventReset() function: it has to be called before waiting, because the event
00211             may be set before the call. So return the event was successfully signaled. */
00212 
00213         /* should return with disabled irq? */
00214         if (!irqs) {
00215             __systemStart();
00216         }
00217         return(__EVRET_SUCCESS);
00218     }
00219 
00220     th = __threadGetCurrent();
00221 
00222     /* Queue the current thread in the event's thread list */
00223     __eventQueueThread(ev, th, timeout);
00224 
00225     /* From now, we have no thread in execution */
00226     __threadSetCurrent(__NULL);
00227 
00228     /* Schedule context switch */
00229     __systemScheduleThreadChange();
00230 
00231     /* Enable interrupts */
00232     __systemStart();
00233 
00234     while (th->th_status != __THSTS_RUNNING);
00235     
00236     /* At this point the thread resumes. Test for state and
00237      * eventually timeout.
00238      */
00239 
00240     /* Critical again */
00241     __systemStop();
00242 
00243     /* Remove the current thread from the event's thread list */
00244     __eventDequeueThread(ev, th);
00245 
00246     /* should return with enabled irq? */
00247     if (irqs == 0) {
00248         __systemStart();
00249     } else {
00250         /* re-establish __systemIrqCount counter */
00251         while (__systemGetIrqCount() != irqs) __systemStop();
00252     }
00253 
00254     /* Check for timeout */
00255     if (timeout && !th->th_wait)
00256     {
00257         ret = __EVRET_TIMEOUT;
00258     } else
00259     {
00260         ret = __EVRET_SUCCESS;
00261     }
00262 
00263     if (ev->ev_state == __EV_ABORT)
00264     {
00265         ret = __EVRET_ABORT;
00266     }
00267 
00268     return ret;
00269 }
00270 
00280 __VOID  __eventSet(__PEVENT ev)
00281 {
00282     __eventSignal(ev, __EV_SET);
00283 }
00284 
00285 
00295 __VOID __eventSetOne(__PEVENT ev)
00296 {
00297     __systemStop();
00298 
00299     ev->ev_state = __EV_SET;
00300 
00301     /* wake up the thread
00302      * (if any, we can be setting an event with no one waiting for it)
00303      */
00304     if (ev->ev_threads)
00305     {
00306         if (__threadGetCurrent())
00307         {
00308             if (__threadGetCurrent()->th_priority > ev->ev_threads->th_priority)
00309             {
00310                 /*
00311                  * Check if the current thread disabled the scheduler,
00312                  * if not, add the current thread to the ready list,
00313                  * __threadCurrent to __NULL and set scheduler.
00314                  */
00315                 if (!__systemSchedulerDisabled())
00316                 {
00317                     __threadAddToReadyList(__threadGetCurrent());
00318                     __threadSetCurrent(__NULL);
00319                     __systemScheduleThreadChange();
00320                 }
00321             }
00322         } else {
00323             __systemScheduleThreadChange();
00324         }
00325 
00326         if (ev->ev_threads->th_status == __THSTS_WAITING)
00327         {
00328             __threadRemoveFromSuspended(ev->ev_threads);
00329             __threadAddToReadyList(ev->ev_threads);
00330         }
00331 
00332         __thlRemoveEvtPrio(ev->ev_threads, (__PTHREAD*) &ev->ev_threads);
00333     }
00334 
00335     __systemStart();
00336 }
00337 
00345 __VOID __eventReset(__PEVENT ev)
00346 {
00347     __systemStop();
00348     ev->ev_state = __EV_RESET;
00349     __systemStart();
00350 }
00351 
00364 __VOID __eventAbort(__PEVENT ev)
00365 {
00366     __eventSignal(ev, __EV_ABORT);
00367 }
00368 
00377 __PTHREAD __eventGetWaitingThreads(__PEVENT ev)
00378 {
00379     return ev->ev_threads;
00380 }
00381 
 All Data Structures Files Functions Variables Typedefs Defines