<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://www.ethernut.de/nutwiki/index.php?action=history&amp;feed=atom&amp;title=Documents%2FNTN-2_Events</id>
		<title>Documents/NTN-2 Events - Revision history</title>
		<link rel="self" type="application/atom+xml" href="http://www.ethernut.de/nutwiki/index.php?action=history&amp;feed=atom&amp;title=Documents%2FNTN-2_Events"/>
		<link rel="alternate" type="text/html" href="http://www.ethernut.de/nutwiki/index.php?title=Documents/NTN-2_Events&amp;action=history"/>
		<updated>2026-04-28T22:52:27Z</updated>
		<subtitle>Revision history for this page on the wiki</subtitle>
		<generator>MediaWiki 1.26.2</generator>

	<entry>
		<id>http://www.ethernut.de/nutwiki/index.php?title=Documents/NTN-2_Events&amp;diff=345&amp;oldid=prev</id>
		<title>Harald: Created page with &quot;&lt;div id=&quot;content&quot;&gt;  = Nut/OS Events =  &lt;br /&gt;  This paper provides an overview of Nut/OS event handling internals.  Basically Nut/OS thread scheduling can be understood as han...&quot;</title>
		<link rel="alternate" type="text/html" href="http://www.ethernut.de/nutwiki/index.php?title=Documents/NTN-2_Events&amp;diff=345&amp;oldid=prev"/>
				<updated>2017-07-13T07:47:56Z</updated>
		
		<summary type="html">&lt;p&gt;Created page with &amp;quot;&amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;  = Nut/OS Events =  &amp;lt;br /&amp;gt;  This paper provides an overview of Nut/OS event handling internals.  Basically Nut/OS thread scheduling can be understood as han...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Nut/OS Events =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This paper provides an overview of Nut/OS event handling internals.&lt;br /&gt;
&lt;br /&gt;
Basically Nut/OS thread scheduling can be understood as handling events by moving threads among queues. A thread waiting for an event is blocked by moving it from a global ready-to-run queue to a queue, that is expected to receive this event.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Linked Lists of Threads ==&lt;br /&gt;
&lt;br /&gt;
During system initialization, the idle thread is created first, which in turn creates the main application thread. Depending on the Nut/OS components used by the application, the system may create additional threads like the DHCP client or the Ethernet receiver thread. Applications can create more threads by calling&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  HANDLE NutThreadCreate(u_char * name, void (*fn) (void *), void *arg, size_t stackSize);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
The first parameter, the thread's name, does not have any other purpose than providing a symbolic name. The second parameter specifies the name of the routine, which will be started as a thread and the third parameter is passed to this routine. Each thread gets its own stack and the size of this stack is specified by the fourth parameter.&lt;br /&gt;
When successful, &amp;lt;code&amp;gt;NutThreadCreate&amp;lt;/code&amp;gt; returns a handle, in fact a pointer to the &amp;lt;code&amp;gt;NUTTHREADINFO&amp;lt;/code&amp;gt; structure of the new thread.&lt;br /&gt;
&lt;br /&gt;
[[File:../../img/nutevents00a.png|713x532px|Thread Structure]]&lt;br /&gt;
Each time, when Nut/OS creates a new thread, a &amp;lt;code&amp;gt;NUTTHREADINFO&amp;lt;/code&amp;gt; structure is allocated from heap memory and and added in front of a linked list containing all existing threads. The global pointer &amp;lt;code&amp;gt;nutThreadList&amp;lt;/code&amp;gt; points to the first entry.&lt;br /&gt;
&lt;br /&gt;
To keep things simple, the following diagrams will show the relevant structure members only. Furthermore, let's assume, that only three threads have been created, the idle thread, the main application thread and an additional thread created by the application. This will result in the following list of threads.&lt;br /&gt;
&lt;br /&gt;
[[File:../../img/nutevents01a.png|923x297px|Events 1]]&lt;br /&gt;
The pointer &amp;lt;code&amp;gt;nutThreadList&amp;lt;/code&amp;gt; points to a list, which contains all three threads. This list is linked by the structure element &amp;lt;code&amp;gt;td_next&amp;lt;/code&amp;gt; (red colored links). The last &amp;lt;code&amp;gt;NUTTHREADINFO&amp;lt;/code&amp;gt; structure is always the one of the idle thread.&lt;br /&gt;
&lt;br /&gt;
We notice, that there are more lists. The global pointer &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt; points to the list of all threads, which are ready to run and linked by &amp;lt;code&amp;gt;td_qnxt&amp;lt;/code&amp;gt; (blue colored links). In opposite to &amp;lt;code&amp;gt;nutThreadList&amp;lt;/code&amp;gt;, new entries are not simply added to the front. This list is always sorted by the value of &amp;lt;code&amp;gt;td_priority&amp;lt;/code&amp;gt;. In Nut/OS, low values mean high priority. The idle thread is running at lowest priority 254. Again to keep the follwing diagrams simple, the priority order is the same as the list of all threads. In reality this is usually not the case.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Waiting for an Event ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt; does not always contain all existing threads, but only those which are ready to run. One of its entries must have the state &amp;lt;code&amp;gt;TDS_RUNNING&amp;lt;/code&amp;gt; and all remaining entries in this queue are in state &amp;lt;code&amp;gt;TDS_READY&amp;lt;/code&amp;gt;. Threads with state &amp;lt;code&amp;gt;TDS_SLEEP&amp;lt;/code&amp;gt; will never be part of the &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a thread directly or indirectly calls&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  int NutEventWait(HANDLE * qhp, u_long ms);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
then the related &amp;lt;code&amp;gt;NUTTHREADINFO&amp;lt;/code&amp;gt; structure will be removed from this list of ready-to-run threads.&lt;br /&gt;
The first parameter of &amp;lt;code&amp;gt;NutEventWait&amp;lt;/code&amp;gt; is a pointer to a pointer to a linked list (HANDLE is defined as a void pointer). This parameter is used in a similar way as &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt;, but instead of listing all ready-to-run threads, it contains a list of threads waiting for a specific event. In our example the thread with the highest priority called&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  HANDLE eventqueue = 0;&lt;br /&gt;
  NutEventWait(&amp;amp;amp;eventQueue, 1000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
and thus had been removed from &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt; and added to &amp;lt;code&amp;gt;eventQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
Internally, &amp;lt;code&amp;gt;NutEventWait&amp;lt;/code&amp;gt; executes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  NutThreadRemoveQueue(runningThread, &amp;amp;amp;runQueue);&lt;br /&gt;
  runningThread-&amp;amp;gt;td_state = TDS_SLEEP;&lt;br /&gt;
  NutThreadAddPriQueue(runningThread, (NUTTHREADINFO **) qhp);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
to remove the currently running thread from the &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt;, change its state from &amp;lt;code&amp;gt;TD_RUNNING&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;TDS_SLEEP&amp;lt;/code&amp;gt; and to add it to the &amp;lt;code&amp;gt;eventQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
The second parameter of &amp;lt;code&amp;gt;NutEventWait&amp;lt;/code&amp;gt; specifies the maximum time the thread is willing to wait for an event posted to the queue. If this parameter is zero, the thread will wait without time limit. Otherwise it is interpreted as the number of milliseconds to wait and Nut/OS will create a timer in this case.&lt;br /&gt;
&lt;br /&gt;
Like threads, timers are created by allocating a &amp;lt;code&amp;gt;NUTTIMERINFO&amp;lt;/code&amp;gt; from heap memory and adding it to a linked list. The global pointer &amp;lt;code&amp;gt;nutTimerList&amp;lt;/code&amp;gt; points to the first entry and following entries are linked by the pointer &amp;lt;code&amp;gt;tn_next&amp;lt;/code&amp;gt;, which is a member of &amp;lt;code&amp;gt;NUTTIMERINFO&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If a timeout is specified, &amp;lt;code&amp;gt;NutEventWait&amp;lt;/code&amp;gt; calls&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  HANDLE NutTimerStart(u_long ms, void (*callback) (HANDLE, void *), void *arg, u_char flags);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
which creates the &amp;lt;code&amp;gt;NUTTIMERINFO&amp;lt;/code&amp;gt; structure and adds it to &amp;lt;code&amp;gt;nutTimerList&amp;lt;/code&amp;gt;. We will discuss the situation in case of a time out later in more detail.&lt;br /&gt;
Finally, &amp;lt;code&amp;gt;NutEventWait&amp;lt;/code&amp;gt; calls&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  NutThreadSwitch();&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
which pushes the CPU registers on the stack, changes the state of the thread in front of the &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;TD_READY&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;TD_RUNNING&amp;lt;/code&amp;gt; and loads the CPU registers for the stack of this thread.&lt;br /&gt;
In this document I will not describe in detail, how Nut/OS switches from one to another thread. In fact, &amp;lt;code&amp;gt;NutEventWait&amp;lt;/code&amp;gt; will not return immediately, because the CPU starts execution of the second thread.&lt;br /&gt;
&lt;br /&gt;
[[File:../../img/nutevents02a.png|923x486px|Events 2]]&lt;br /&gt;
Let's assume, that our second thread directly or indirectly calls &amp;lt;code&amp;gt;NutEventWait&amp;lt;/code&amp;gt; too on the same &amp;lt;code&amp;gt;eventQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  NutEventWait(&amp;amp;amp;eventQueue, 1000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
Again a timeout value has been given and Nut/OS moves the related &amp;lt;code&amp;gt;NUTTHREADINFO&amp;lt;/code&amp;gt; structure from the &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt; to this &amp;lt;code&amp;gt;eventQueue&amp;lt;/code&amp;gt;, does the required updates of &amp;lt;code&amp;gt;td_state&amp;lt;/code&amp;gt;, creates another timer and finally passes control to the last thread.&lt;br /&gt;
[[File:../../img/nutevents03a.png|923x553px|Events 3]]&lt;br /&gt;
As described above, the last thread is the idle thread, which will never be removed from the &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt;. It serves as a placeholder during times, when all worker threads are sleeping. It keeps the CPU busy by calling &amp;lt;code&amp;gt;NutThreadYield&amp;lt;/code&amp;gt; in an endless loop. As soon as another thread becomes ready to run, the idle thread will lose CPU control. In our case, this may happen as soon as an event is posted to the &amp;lt;code&amp;gt;eventQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Posting an Event ==&lt;br /&gt;
&lt;br /&gt;
In order to wake up a thread waiting in an event queue, a thread calls&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  int NutEventPost(HANDLE volatile *qhp);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This will remove the &amp;lt;code&amp;gt;NUTTHREADINFO&amp;lt;/code&amp;gt; structure in front of this priority ordered linked list to the &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt;. As we already know, the &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt; is also ordered by priority. If the thread, which called &amp;lt;code&amp;gt;NutEventPost&amp;lt;/code&amp;gt;, has a lower priority than the woken up thread, CPU control is passed to the latter.&lt;br /&gt;
Alternatively a thread may call&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  int NutEventBroadcast(HANDLE * qhp);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
in which moves all threads in the specified queue to the &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
In our given example, only the idle thread is left. When the idle thread is doing nothing except calling &amp;lt;code&amp;gt;NutThreadYield&amp;lt;/code&amp;gt; in a loop, who is posting an event while both worker threads are sleeping? Well, there are two special calls, which can be called from within interrupt routines.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  int NutEventPostAsync(HANDLE volatile *qhp);&lt;br /&gt;
  int NutEventBroadcastAsync(HANDLE * qhp);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
The main difference to &amp;lt;code&amp;gt;NutEventPost&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;NutEventPostAsync&amp;lt;/code&amp;gt; is, that Nut/OS will move the &amp;lt;code&amp;gt;NUTTHREADINFO&amp;lt;/code&amp;gt; structures and update the &amp;lt;code&amp;gt;td_state&amp;lt;/code&amp;gt; values, but will not switch the CPU control. This is actually done when the idle thread calls &amp;lt;code&amp;gt;NutThreadYield&amp;lt;/code&amp;gt;. Nut/OS provides cooperative multithreading, which means, that a thread can rely on not losing CPU control without calling specific system function which may change its state. However, interrupts are preemptive in any case. By delaying the context switch, Nut/OS ensures, that cooperative multithreading is maintained even when interrupts are able to wake up sleeping threads.&lt;br /&gt;
So far let's assume, that in our example some kind of smart interrupt routine posts an event to &amp;lt;code&amp;gt;eventQueue&amp;lt;/code&amp;gt; by calling&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  NutEventPostAsync(&amp;amp;amp;eventQueue);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
and that our high priority thread is back in the &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
[[File:../../img/nutevents04a.png|923x556px|Events 4]]&lt;br /&gt;
If an event is posted to the &amp;lt;code&amp;gt;eventQueue&amp;lt;/code&amp;gt; before the timer elapses, then the &amp;lt;code&amp;gt;NUTTIMERINFO&amp;lt;/code&amp;gt; will be removed from the &amp;lt;code&amp;gt;nutTimerList&amp;lt;/code&amp;gt; by a call to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  NutTimerStopAsync(td-&amp;amp;gt;td_timer);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
The second thread is still waiting for an event and we assume, that a time out will occur.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Event Timeout ==&lt;br /&gt;
&lt;br /&gt;
In detail, &amp;lt;code&amp;gt;NutEventWait&amp;lt;/code&amp;gt; calls&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  td_timer = NutTimerStart(ms, NutEventTimeout, (void *) qhp, TM_ONESHOT);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
when a timeout value other than zero has been specified. Further details of Nut/OS timer handling are not described in this document, but let's look at least to the parameters. The first one contains the number of milliseconds the thread is willing to wait for an event. The second parameter points to a functions, which will be called when the timer elapses. The third parameter will be passed to this function, it points to the event queue. The last parameter puts the timer in oneshot mode. This means, that it is automatically removed from &amp;lt;code&amp;gt;nutTimerList&amp;lt;/code&amp;gt; after the timer elapsed.&lt;br /&gt;
Obviously the most interesting parameter is the callback routine&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;coding&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;  void NutEventTimeout(HANDLE timer, void *arg);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
This procedure is part of the Nut/OS event handling module and directly called by the timer interrupt routine when a timer elapses. As explained above, a pointer to the related queue is passed to this routine along with the handle of the timer (actually a pointer to &amp;lt;code&amp;gt;NUTTIMERINFO&amp;lt;/code&amp;gt;). In our example, the timer handle is the same, that had been previously stored in &amp;lt;code&amp;gt;td_timer&amp;lt;/code&amp;gt; and the &amp;lt;code&amp;gt;arg&amp;lt;/code&amp;gt; points to &amp;lt;code&amp;gt;                     eventQueue&amp;lt;/code&amp;gt;.&lt;br /&gt;
The &amp;lt;code&amp;gt;NutEventTimeout&amp;lt;/code&amp;gt; will walk through this queue, searching for the &amp;lt;code&amp;gt;NUTTHREADINFO&amp;lt;/code&amp;gt; structure that contains a &amp;lt;code&amp;gt;td_timer&amp;lt;/code&amp;gt; with the same timer handle. If it is not found, the routine doesn't care. It simply means, that an event already removed the thread from the queue. Nothing else can be done, because the Nut/OS timer handling will automatically remove oneshot timers.&lt;br /&gt;
&lt;br /&gt;
If it is found, &amp;lt;code&amp;gt;td_timer&amp;lt;/code&amp;gt; will be cleared and the &amp;lt;code&amp;gt;NUTTHREADINFO&amp;lt;/code&amp;gt; structure will be moved to the &amp;lt;code&amp;gt;runQueue&amp;lt;/code&amp;gt;. Remember, that &amp;lt;code&amp;gt;NutEventTimeout&amp;lt;/code&amp;gt; is running in interrupt context. So it will not perform any thread switching. As soon as the running thread calls any such function, a thread switch may occur. In our example, this will not happen, because the currently running thread got a higher priority.&lt;br /&gt;
&lt;br /&gt;
[[File:../../img/nutevents01a.png|923x297px|Events 1]]&lt;br /&gt;
Later on, CPU control will be (hopefully) passed to the second thread, which then continous to execute &amp;lt;code&amp;gt;NutEventWait&amp;lt;/code&amp;gt;. This routine will check whether it had been called with a timeout value and &amp;lt;code&amp;gt;td_timer&amp;lt;/code&amp;gt; had been cleared to zero. In this case it returns -1 to inform the caller, that a time out occured. Otherwise zero will be returned.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Problem Discussion ==&lt;br /&gt;
&lt;br /&gt;
At the time of this writing, Nut/OS is at version 3.9.2.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Problem 1: &amp;lt;/code&amp;gt;Not yet verfied, but it looks like events are sometimes lost when a timeout value has been specified. With most applications this is no real problem, because the timeout will avoid complete blocking of the thread.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Problem 2: &amp;lt;/code&amp;gt;Several variables and parameters are marked volatile. However, cooperative multithreading requires a volatile attribute for variables only, if they are modified in interrupt routines.&lt;br /&gt;
&lt;br /&gt;
Harald Kipp&amp;lt;br /&amp;gt;&lt;br /&gt;
Herne, October 9th, 2004.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Harald</name></author>	</entry>

	</feed>