protothread/doc/html/a00015.html

712 lines
40 KiB
HTML
Raw Normal View History

2022-11-22 01:59:34 +00:00
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
<title>The Protothreads Library 1.4: Examples</title>
<link href="doxygen.css" rel="stylesheet" type="text/css">
<link href="tabs.css" rel="stylesheet" type="text/css">
</head><body>
<!-- Generated by Doxygen 1.4.6 -->
<div class="tabs">
<ul>
<li><a href="main.html"><span>Main&nbsp;Page</span></a></li>
<li><a href="modules.html"><span>Modules</span></a></li>
<li><a href="annotated.html"><span>Data&nbsp;Structures</span></a></li>
<li><a href="files.html"><span>Files</span></a></li>
</ul></div>
<h1>Examples</h1><h2><a class="anchor" name="example-small">
A small example</a></h2>
This first example shows a very simple program: two protothreads waiting for each other to toggle two flags. The code illustrates how to write protothreads code, how to initialize protothreads, and how to schedule them.<p>
<div class="fragment"><pre class="fragment"><span class="comment">/**</span>
<span class="comment"> * This is a very small example that shows how to use</span>
<span class="comment"> * protothreads. The program consists of two protothreads that wait</span>
<span class="comment"> * for each other to toggle a variable.</span>
<span class="comment"> */</span>
<span class="comment">/* We must always include pt.h in our protothreads code. */</span>
<span class="preprocessor">#include "<a class="code" href="a00013.html">pt.h</a>"</span>
<span class="preprocessor">#include &lt;stdio.h&gt;</span> <span class="comment">/* For printf(). */</span>
<span class="comment">/* Two flags that the two protothread functions use. */</span>
<span class="keyword">static</span> <span class="keywordtype">int</span> protothread1_flag, protothread2_flag;
<span class="comment"></span>
<span class="comment">/**</span>
<span class="comment"> * The first protothread function. A protothread function must always</span>
<span class="comment"> * return an integer, but must never explicitly return - returning is</span>
<span class="comment"> * performed inside the protothread statements.</span>
<span class="comment"> *</span>
<span class="comment"> * The protothread function is driven by the main loop further down in</span>
<span class="comment"> * the code.</span>
<span class="comment"> */</span>
<span class="keyword">static</span> <span class="keywordtype">int</span>
protothread1(<span class="keyword">struct</span> <a class="code" href="a00005.html">pt</a> *<a class="code" href="a00005.html">pt</a>)
{
<span class="comment">/* A protothread function must begin with PT_BEGIN() which takes a</span>
<span class="comment"> pointer to a struct pt. */</span>
<a class="code" href="a00014.html#g2ffbb9e554e08a343ae2f9de4bedfdfc">PT_BEGIN</a>(pt);
<span class="comment">/* We loop forever here. */</span>
<span class="keywordflow">while</span>(1) {
<span class="comment">/* Wait until the other protothread has set its flag. */</span>
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, protothread2_flag != 0);
printf(<span class="stringliteral">"Protothread 1 running\n"</span>);
<span class="comment">/* We then reset the other protothread's flag, and set our own</span>
<span class="comment"> flag so that the other protothread can run. */</span>
protothread2_flag = 0;
protothread1_flag = 1;
<span class="comment">/* And we loop. */</span>
}
<span class="comment">/* All protothread functions must end with PT_END() which takes a</span>
<span class="comment"> pointer to a struct pt. */</span>
<a class="code" href="a00014.html#g7b04a0035bef29d905496c23bae066d2">PT_END</a>(pt);
}
<span class="comment"></span>
<span class="comment">/**</span>
<span class="comment"> * The second protothread function. This is almost the same as the</span>
<span class="comment"> * first one.</span>
<span class="comment"> */</span>
<span class="keyword">static</span> <span class="keywordtype">int</span>
protothread2(<span class="keyword">struct</span> pt *pt)
{
<a class="code" href="a00014.html#g2ffbb9e554e08a343ae2f9de4bedfdfc">PT_BEGIN</a>(pt);
<span class="keywordflow">while</span>(1) {
<span class="comment">/* Let the other protothread run. */</span>
protothread2_flag = 1;
<span class="comment">/* Wait until the other protothread has set its flag. */</span>
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, protothread1_flag != 0);
printf(<span class="stringliteral">"Protothread 2 running\n"</span>);
<span class="comment">/* We then reset the other protothread's flag. */</span>
protothread1_flag = 0;
<span class="comment">/* And we loop. */</span>
}
<a class="code" href="a00014.html#g7b04a0035bef29d905496c23bae066d2">PT_END</a>(pt);
}
<span class="comment"></span>
<span class="comment">/**</span>
<span class="comment"> * Finally, we have the main loop. Here is where the protothreads are</span>
<span class="comment"> * initialized and scheduled. First, however, we define the</span>
<span class="comment"> * protothread state variables pt1 and pt2, which hold the state of</span>
<span class="comment"> * the two protothreads.</span>
<span class="comment"> */</span>
<span class="keyword">static</span> <span class="keyword">struct </span>pt pt1, pt2;
<span class="keywordtype">int</span>
main(<span class="keywordtype">void</span>)
{
<span class="comment">/* Initialize the protothread state variables with PT_INIT(). */</span>
<a class="code" href="a00014.html#ge6bae7dc0225468c8a5ac269df549892">PT_INIT</a>(&amp;pt1);
<a class="code" href="a00014.html#ge6bae7dc0225468c8a5ac269df549892">PT_INIT</a>(&amp;pt2);
<span class="comment">/*</span>
<span class="comment"> * Then we schedule the two protothreads by repeatedly calling their</span>
<span class="comment"> * protothread functions and passing a pointer to the protothread</span>
<span class="comment"> * state variables as arguments.</span>
<span class="comment"> */</span>
<span class="keywordflow">while</span>(1) {
protothread1(&amp;pt1);
protothread2(&amp;pt2);
}
}
</pre></div><h2><a class="anchor" name="example-code-lock">
A code-lock</a></h2>
This example shows how to implement a simple code lock - the kind of device that is placed next to doors and that you have to push a four digit number into in order to unlock the door.<p>
The code lock waits for key presses from a numeric keyboard and if the correct code is entered, the lock is unlocked. There is a maximum time of one second between each key press, and after the correct code has been entered, no more keys must be pressed for 0.5 seconds before the lock is opened.<p>
<div class="fragment"><pre class="fragment"><span class="comment">/*</span>
<span class="comment"> * Copyright (c) 2004-2005, Swedish Institute of Computer Science.</span>
<span class="comment"> * All rights reserved. </span>
<span class="comment"> *</span>
<span class="comment"> * Redistribution and use in source and binary forms, with or without </span>
<span class="comment"> * modification, are permitted provided that the following conditions </span>
<span class="comment"> * are met: </span>
<span class="comment"> * 1. Redistributions of source code must retain the above copyright </span>
<span class="comment"> * notice, this list of conditions and the following disclaimer. </span>
<span class="comment"> * 2. Redistributions in binary form must reproduce the above copyright </span>
<span class="comment"> * notice, this list of conditions and the following disclaimer in the </span>
<span class="comment"> * documentation and/or other materials provided with the distribution. </span>
<span class="comment"> * 3. Neither the name of the Institute nor the names of its contributors </span>
<span class="comment"> * may be used to endorse or promote products derived from this software </span>
<span class="comment"> * without specific prior written permission. </span>
<span class="comment"> *</span>
<span class="comment"> * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND </span>
<span class="comment"> * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE </span>
<span class="comment"> * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE </span>
<span class="comment"> * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE </span>
<span class="comment"> * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL </span>
<span class="comment"> * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS </span>
<span class="comment"> * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) </span>
<span class="comment"> * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT </span>
<span class="comment"> * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY </span>
<span class="comment"> * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF </span>
<span class="comment"> * SUCH DAMAGE. </span>
<span class="comment"> *</span>
<span class="comment"> * This file is part of the protothreads library.</span>
<span class="comment"> *</span>
<span class="comment"> * Author: Adam Dunkels &lt;adam@sics.se&gt;</span>
<span class="comment"> *</span>
<span class="comment"> * $Id: example-codelock.c,v 1.5 2005/10/06 07:57:08 adam Exp $</span>
<span class="comment"> */</span>
<span class="comment">/*</span>
<span class="comment"> *</span>
<span class="comment"> * This example shows how to implement a simple code lock. The code</span>
<span class="comment"> * lock waits for key presses from a numeric keyboard and if the</span>
<span class="comment"> * correct code is entered, the lock is unlocked. There is a maximum</span>
<span class="comment"> * time of one second between each key press, and after the correct</span>
<span class="comment"> * code has been entered, no more keys must be pressed for 0.5 seconds</span>
<span class="comment"> * before the lock is opened.</span>
<span class="comment"> *</span>
<span class="comment"> * This is an example that shows two things:</span>
<span class="comment"> * - how to implement a code lock key input mechanism, and</span>
<span class="comment"> * - how to implement a sequential timed routine.</span>
<span class="comment"> *</span>
<span class="comment"> * The program consists of two protothreads, one that implements the</span>
<span class="comment"> * code lock reader and one that implements simulated keyboard input.</span>
<span class="comment"> *</span>
<span class="comment"> *</span>
<span class="comment"> */</span>
<span class="preprocessor">#ifdef _WIN32</span>
<span class="preprocessor"></span><span class="preprocessor">#include &lt;windows.h&gt;</span>
<span class="preprocessor">#else</span>
<span class="preprocessor"></span><span class="preprocessor">#include &lt;unistd.h&gt;</span>
<span class="preprocessor">#include &lt;sys/time.h&gt;</span>
<span class="preprocessor">#endif</span>
<span class="preprocessor"></span><span class="preprocessor">#include &lt;stdio.h&gt;</span>
<span class="preprocessor">#include "<a class="code" href="a00013.html">pt.h</a>"</span>
<span class="comment">/*---------------------------------------------------------------------------*/</span>
<span class="comment">/*</span>
<span class="comment"> * The following definitions are just for the simple timer library</span>
<span class="comment"> * used in this example. The actual implementation of the functions</span>
<span class="comment"> * can be found at the end of this file.</span>
<span class="comment"> */</span>
<span class="keyword">struct </span>timer { <span class="keywordtype">int</span> start, interval; };
<span class="keyword">static</span> <span class="keywordtype">int</span> timer_expired(<span class="keyword">struct</span> timer *t);
<span class="keyword">static</span> <span class="keywordtype">void</span> timer_set(<span class="keyword">struct</span> timer *t, <span class="keywordtype">int</span> usecs);
<span class="comment">/*---------------------------------------------------------------------------*/</span>
<span class="comment">/*</span>
<span class="comment"> * This example uses two timers: one for the code lock protothread and</span>
<span class="comment"> * one for the simulated key input protothread.</span>
<span class="comment"> */</span>
<span class="keyword">static</span> <span class="keyword">struct </span>timer codelock_timer, input_timer;
<span class="comment">/*---------------------------------------------------------------------------*/</span>
<span class="comment">/*</span>
<span class="comment"> * This is the code that has to be entered.</span>
<span class="comment"> */</span>
<span class="keyword">static</span> <span class="keyword">const</span> <span class="keywordtype">char</span> code[4] = {<span class="charliteral">'1'</span>, <span class="charliteral">'4'</span>, <span class="charliteral">'2'</span>, <span class="charliteral">'3'</span>};
<span class="comment">/*---------------------------------------------------------------------------*/</span>
<span class="comment">/*</span>
<span class="comment"> * This example has two protothread and therefor has two protothread</span>
<span class="comment"> * control structures of type struct pt. These are initialized with</span>
<span class="comment"> * PT_INIT() in the main() function below.</span>
<span class="comment"> */</span>
<span class="keyword">static</span> <span class="keyword">struct </span>pt codelock_pt, input_pt;
<span class="comment">/*---------------------------------------------------------------------------*/</span>
<span class="comment">/*</span>
<span class="comment"> * The following code implements a simple key input. Input is made</span>
<span class="comment"> * with the press_key() function, and the function key_pressed()</span>
<span class="comment"> * checks if a key has been pressed. The variable "key" holds the</span>
<span class="comment"> * latest key that was pressed. The variable "key_pressed_flag" is set</span>
<span class="comment"> * when a key is pressed and cleared when a key press is checked.</span>
<span class="comment"> */</span>
<span class="keyword">static</span> <span class="keywordtype">char</span> key, key_pressed_flag;
<span class="keyword">static</span> <span class="keywordtype">void</span>
press_key(<span class="keywordtype">char</span> k)
{
printf(<span class="stringliteral">"--- Key '%c' pressed\n"</span>, k);
key = k;
key_pressed_flag = 1;
}
<span class="keyword">static</span> <span class="keywordtype">int</span>
key_pressed(<span class="keywordtype">void</span>)
{
<span class="keywordflow">if</span>(key_pressed_flag != 0) {
key_pressed_flag = 0;
<span class="keywordflow">return</span> 1;
}
<span class="keywordflow">return</span> 0;
}
<span class="comment">/*---------------------------------------------------------------------------*/</span>
<span class="comment">/*</span>
<span class="comment"> * Declaration of the protothread function implementing the code lock</span>
<span class="comment"> * logic. The protothread function is declared using the PT_THREAD()</span>
<span class="comment"> * macro. The function is declared with the "static" keyword since it</span>
<span class="comment"> * is local to this file. The name of the function is codelock_thread</span>
<span class="comment"> * and it takes one argument, pt, of the type struct pt.</span>
<span class="comment"> *</span>
<span class="comment"> */</span>
<span class="keyword">static</span>
<a class="code" href="a00014.html#g3d4c8bd4aada659eb34f5d2ffd3e7901">PT_THREAD</a>(codelock_thread(<span class="keyword">struct</span> pt *pt))
{
<span class="comment">/* This is a local variable that holds the number of keys that have</span>
<span class="comment"> * been pressed. Note that it is declared with the "static" keyword</span>
<span class="comment"> * to make sure that the variable is *not* allocated on the stack.</span>
<span class="comment"> */</span>
<span class="keyword">static</span> <span class="keywordtype">int</span> keys;
<span class="comment">/*</span>
<span class="comment"> * Declare the beginning of the protothread.</span>
<span class="comment"> */</span>
<a class="code" href="a00014.html#g2ffbb9e554e08a343ae2f9de4bedfdfc">PT_BEGIN</a>(pt);
<span class="comment">/*</span>
<span class="comment"> * We'll let the protothread loop until the protothread is</span>
<span class="comment"> * expliticly exited with PT_EXIT().</span>
<span class="comment"> */</span>
<span class="keywordflow">while</span>(1) {
<span class="comment">/*</span>
<span class="comment"> * We'll be reading key presses until we get the right amount of</span>
<span class="comment"> * correct keys.</span>
<span class="comment"> */</span>
<span class="keywordflow">for</span>(keys = 0; keys &lt; <span class="keyword">sizeof</span>(code); ++keys) {
<span class="comment">/*</span>
<span class="comment"> * If we haven't gotten any keypresses, we'll simply wait for one.</span>
<span class="comment"> */</span>
<span class="keywordflow">if</span>(keys == 0) {
<span class="comment">/*</span>
<span class="comment"> * The PT_WAIT_UNTIL() function will block until the condition</span>
<span class="comment"> * key_pressed() is true.</span>
<span class="comment"> */</span>
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, key_pressed());
} <span class="keywordflow">else</span> {
<span class="comment">/*</span>
<span class="comment"> * If the "key" variable was larger than zero, we have already</span>
<span class="comment"> * gotten at least one correct key press. If so, we'll not</span>
<span class="comment"> * only wait for the next key, but we'll also set a timer that</span>
<span class="comment"> * expires in one second. This gives the person pressing the</span>
<span class="comment"> * keys one second to press the next key in the code.</span>
<span class="comment"> */</span>
timer_set(&amp;codelock_timer, 1000);
<span class="comment">/*</span>
<span class="comment"> * The following statement shows how complex blocking</span>
<span class="comment"> * conditions can be easily expressed with protothreads and</span>
<span class="comment"> * the PT_WAIT_UNTIL() function.</span>
<span class="comment"> */</span>
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, key_pressed() || timer_expired(&amp;codelock_timer));
<span class="comment">/*</span>
<span class="comment"> * If the timer expired, we should break out of the for() loop</span>
<span class="comment"> * and start reading keys from the beginning of the while(1)</span>
<span class="comment"> * loop instead.</span>
<span class="comment"> */</span>
<span class="keywordflow">if</span>(timer_expired(&amp;codelock_timer)) {
printf(<span class="stringliteral">"Code lock timer expired.\n"</span>);
<span class="comment">/*</span>
<span class="comment"> * Break out from the for() loop and start from the</span>
<span class="comment"> * beginning of the while(1) loop.</span>
<span class="comment"> */</span>
<span class="keywordflow">break</span>;
}
}
<span class="comment">/*</span>
<span class="comment"> * Check if the pressed key was correct.</span>
<span class="comment"> */</span>
<span class="keywordflow">if</span>(key != code[keys]) {
printf(<span class="stringliteral">"Incorrect key '%c' found\n"</span>, key);
<span class="comment">/*</span>
<span class="comment"> * Break out of the for() loop since the key was incorrect.</span>
<span class="comment"> */</span>
<span class="keywordflow">break</span>;
} <span class="keywordflow">else</span> {
printf(<span class="stringliteral">"Correct key '%c' found\n"</span>, key);
}
}
<span class="comment">/*</span>
<span class="comment"> * Check if we have gotten all keys.</span>
<span class="comment"> */</span>
<span class="keywordflow">if</span>(keys == <span class="keyword">sizeof</span>(code)) {
printf(<span class="stringliteral">"Correct code entered, waiting for 500 ms before unlocking.\n"</span>);
<span class="comment">/*</span>
<span class="comment"> * Ok, we got the correct code. But to make sure that the code</span>
<span class="comment"> * was not just a fluke of luck by an intruder, but the correct</span>
<span class="comment"> * code entered by a person that knows the correct code, we'll</span>
<span class="comment"> * wait for half a second before opening the lock. If another</span>
<span class="comment"> * key is pressed during this time, we'll assume that it was a</span>
<span class="comment"> * fluke of luck that the correct code was entered the first</span>
<span class="comment"> * time.</span>
<span class="comment"> */</span>
timer_set(&amp;codelock_timer, 500);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, key_pressed() || timer_expired(&amp;codelock_timer));
<span class="comment">/*</span>
<span class="comment"> * If we continued from the PT_WAIT_UNTIL() statement without</span>
<span class="comment"> * the timer expired, we don't open the lock.</span>
<span class="comment"> */</span>
<span class="keywordflow">if</span>(!timer_expired(&amp;codelock_timer)) {
printf(<span class="stringliteral">"Key pressed during final wait, code lock locked again.\n"</span>);
} <span class="keywordflow">else</span> {
<span class="comment">/*</span>
<span class="comment"> * If the timer expired, we'll open the lock and exit from the</span>
<span class="comment"> * protothread.</span>
<span class="comment"> */</span>
printf(<span class="stringliteral">"Code lock unlocked.\n"</span>);
<a class="code" href="a00014.html#g905451249dca72ce0385bf2a9ff178ee">PT_EXIT</a>(pt);
}
}
}
<span class="comment">/*</span>
<span class="comment"> * Finally, we'll mark the end of the protothread.</span>
<span class="comment"> */</span>
<a class="code" href="a00014.html#g7b04a0035bef29d905496c23bae066d2">PT_END</a>(pt);
}
<span class="comment">/*---------------------------------------------------------------------------*/</span>
<span class="comment">/*</span>
<span class="comment"> * This is the second protothread in this example. It implements a</span>
<span class="comment"> * simulated user pressing the keys. This illustrates how a linear</span>
<span class="comment"> * sequence of timed instructions can be implemented with</span>
<span class="comment"> * protothreads.</span>
<span class="comment"> */</span>
<span class="keyword">static</span>
<a class="code" href="a00014.html#g3d4c8bd4aada659eb34f5d2ffd3e7901">PT_THREAD</a>(input_thread(<span class="keyword">struct</span> pt *pt))
{
<a class="code" href="a00014.html#g2ffbb9e554e08a343ae2f9de4bedfdfc">PT_BEGIN</a>(pt);
printf(<span class="stringliteral">"Waiting 1 second before entering first key.\n"</span>);
timer_set(&amp;input_timer, 1000);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'1'</span>);
timer_set(&amp;input_timer, 100);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'2'</span>);
timer_set(&amp;input_timer, 100);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'3'</span>);
timer_set(&amp;input_timer, 2000);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'1'</span>);
timer_set(&amp;input_timer, 200);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'4'</span>);
timer_set(&amp;input_timer, 200);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'2'</span>);
timer_set(&amp;input_timer, 2000);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'3'</span>);
timer_set(&amp;input_timer, 200);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'1'</span>);
timer_set(&amp;input_timer, 200);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'4'</span>);
timer_set(&amp;input_timer, 200);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'2'</span>);
timer_set(&amp;input_timer, 100);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'3'</span>);
timer_set(&amp;input_timer, 100);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'4'</span>);
timer_set(&amp;input_timer, 1500);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'1'</span>);
timer_set(&amp;input_timer, 300);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'4'</span>);
timer_set(&amp;input_timer, 400);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'2'</span>);
timer_set(&amp;input_timer, 500);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
press_key(<span class="charliteral">'3'</span>);
timer_set(&amp;input_timer, 2000);
<a class="code" href="a00014.html#g99e43010ec61327164466aa2d902de45">PT_WAIT_UNTIL</a>(pt, timer_expired(&amp;input_timer));
<a class="code" href="a00014.html#g7b04a0035bef29d905496c23bae066d2">PT_END</a>(pt);
}
<span class="comment">/*---------------------------------------------------------------------------*/</span>
<span class="comment">/*</span>
<span class="comment"> * This is the main function. It initializes the two protothread</span>
<span class="comment"> * control structures and schedules the two protothreads. The main</span>
<span class="comment"> * function returns when the protothread the runs the code lock exits.</span>
<span class="comment"> */</span>
<span class="keywordtype">int</span>
main(<span class="keywordtype">void</span>)
{
<span class="comment">/*</span>
<span class="comment"> * Initialize the two protothread control structures.</span>
<span class="comment"> */</span>
<a class="code" href="a00014.html#ge6bae7dc0225468c8a5ac269df549892">PT_INIT</a>(&amp;input_pt);
<a class="code" href="a00014.html#ge6bae7dc0225468c8a5ac269df549892">PT_INIT</a>(&amp;codelock_pt);
<span class="comment">/*</span>
<span class="comment"> * Schedule the two protothreads until the codelock_thread() exits.</span>
<span class="comment"> */</span>
<span class="keywordflow">while</span>(<a class="code" href="a00014.html#gfa82b860a64b67d25ab3abc21811896f">PT_SCHEDULE</a>(codelock_thread(&amp;codelock_pt))) {
<a class="code" href="a00014.html#gfa82b860a64b67d25ab3abc21811896f">PT_SCHEDULE</a>(input_thread(&amp;input_pt));
<span class="comment">/*</span>
<span class="comment"> * When running this example on a multitasking system, we must</span>
<span class="comment"> * give other processes a chance to run too and therefore we call</span>
<span class="comment"> * usleep() resp. Sleep() here. On a dedicated embedded system,</span>
<span class="comment"> * we usually do not need to do this.</span>
<span class="comment"> */</span>
<span class="preprocessor">#ifdef _WIN32</span>
<span class="preprocessor"></span> Sleep(0);
<span class="preprocessor">#else</span>
<span class="preprocessor"></span> usleep(10);
<span class="preprocessor">#endif</span>
<span class="preprocessor"></span> }
<span class="keywordflow">return</span> 0;
}
<span class="comment">/*---------------------------------------------------------------------------*/</span>
<span class="comment">/*</span>
<span class="comment"> * Finally, the implementation of the simple timer library follows.</span>
<span class="comment"> */</span>
<span class="preprocessor">#ifdef _WIN32</span>
<span class="preprocessor"></span>
<span class="keyword">static</span> <span class="keywordtype">int</span> clock_time(<span class="keywordtype">void</span>)
{ <span class="keywordflow">return</span> (<span class="keywordtype">int</span>)GetTickCount(); }
<span class="preprocessor">#else </span><span class="comment">/* _WIN32 */</span>
<span class="keyword">static</span> <span class="keywordtype">int</span> clock_time(<span class="keywordtype">void</span>)
{
<span class="keyword">struct </span>timeval tv;
<span class="keyword">struct </span>timezone tz;
gettimeofday(&amp;tv, &amp;tz);
<span class="keywordflow">return</span> tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
<span class="preprocessor">#endif </span><span class="comment">/* _WIN32 */</span>
<span class="keyword">static</span> <span class="keywordtype">int</span> timer_expired(<span class="keyword">struct</span> timer *t)
{ <span class="keywordflow">return</span> (<span class="keywordtype">int</span>)(clock_time() - t-&gt;start) &gt;= (<span class="keywordtype">int</span>)t-&gt;interval; }
<span class="keyword">static</span> <span class="keywordtype">void</span> timer_set(<span class="keyword">struct</span> timer *t, <span class="keywordtype">int</span> interval)
{ t-&gt;interval = interval; t-&gt;start = clock_time(); }
<span class="comment">/*---------------------------------------------------------------------------*/</span>
</pre></div><h2><a class="anchor" name="example-buffer">
The bounded buffer with protothread semaphores</a></h2>
The following example shows how to implement the bounded buffer problem using the protothreads semaphore library. The example uses three protothreads: one producer() protothread that produces items, one consumer() protothread that consumes items, and one driver_thread() that schedules the producer and consumer protothreads.<p>
Note that there is no need for a mutex to guard the add_to_buffer() and get_from_buffer() functions because of the implicit locking semantics of protothreads - a protothread will never be preempted and will never block except in an explicit PT_WAIT statement.<p>
<div class="fragment"><pre class="fragment"><span class="comment">/*</span>
<span class="comment"> * Copyright (c) 2004-2005, Swedish Institute of Computer Science.</span>
<span class="comment"> * All rights reserved. </span>
<span class="comment"> *</span>
<span class="comment"> * Redistribution and use in source and binary forms, with or without </span>
<span class="comment"> * modification, are permitted provided that the following conditions </span>
<span class="comment"> * are met: </span>
<span class="comment"> * 1. Redistributions of source code must retain the above copyright </span>
<span class="comment"> * notice, this list of conditions and the following disclaimer. </span>
<span class="comment"> * 2. Redistributions in binary form must reproduce the above copyright </span>
<span class="comment"> * notice, this list of conditions and the following disclaimer in the </span>
<span class="comment"> * documentation and/or other materials provided with the distribution. </span>
<span class="comment"> * 3. Neither the name of the Institute nor the names of its contributors </span>
<span class="comment"> * may be used to endorse or promote products derived from this software </span>
<span class="comment"> * without specific prior written permission. </span>
<span class="comment"> *</span>
<span class="comment"> * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND </span>
<span class="comment"> * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE </span>
<span class="comment"> * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE </span>
<span class="comment"> * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE </span>
<span class="comment"> * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL </span>
<span class="comment"> * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS </span>
<span class="comment"> * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) </span>
<span class="comment"> * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT </span>
<span class="comment"> * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY </span>
<span class="comment"> * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF </span>
<span class="comment"> * SUCH DAMAGE. </span>
<span class="comment"> *</span>
<span class="comment"> * This file is part of the protothreads library.</span>
<span class="comment"> *</span>
<span class="comment"> * Author: Adam Dunkels &lt;adam@sics.se&gt;</span>
<span class="comment"> *</span>
<span class="comment"> * $Id: example-buffer.c,v 1.5 2005/10/07 05:21:33 adam Exp $</span>
<span class="comment"> */</span>
<span class="preprocessor">#ifdef _WIN32</span>
<span class="preprocessor"></span><span class="preprocessor">#include &lt;windows.h&gt;</span>
<span class="preprocessor">#else</span>
<span class="preprocessor"></span><span class="preprocessor">#include &lt;unistd.h&gt;</span>
<span class="preprocessor">#endif</span>
<span class="preprocessor"></span><span class="preprocessor">#include &lt;stdio.h&gt;</span>
<span class="preprocessor">#include "<a class="code" href="a00012.html">pt-sem.h</a>"</span>
<span class="preprocessor">#define NUM_ITEMS 32</span>
<span class="preprocessor"></span><span class="preprocessor">#define BUFSIZE 8</span>
<span class="preprocessor"></span>
<span class="keyword">static</span> <span class="keywordtype">int</span> buffer[BUFSIZE];
<span class="keyword">static</span> <span class="keywordtype">int</span> bufptr;
<span class="keyword">static</span> <span class="keywordtype">void</span>
add_to_buffer(<span class="keywordtype">int</span> item)
{
printf(<span class="stringliteral">"Item %d added to buffer at place %d\n"</span>, item, bufptr);
buffer[bufptr] = item;
bufptr = (bufptr + 1) % BUFSIZE;
}
<span class="keyword">static</span> <span class="keywordtype">int</span>
get_from_buffer(<span class="keywordtype">void</span>)
{
<span class="keywordtype">int</span> item;
item = buffer[bufptr];
printf(<span class="stringliteral">"Item %d retrieved from buffer at place %d\n"</span>,
item, bufptr);
bufptr = (bufptr + 1) % BUFSIZE;
<span class="keywordflow">return</span> item;
}
<span class="keyword">static</span> <span class="keywordtype">int</span>
produce_item(<span class="keywordtype">void</span>)
{
<span class="keyword">static</span> <span class="keywordtype">int</span> item = 0;
printf(<span class="stringliteral">"Item %d produced\n"</span>, item);
<span class="keywordflow">return</span> item++;
}
<span class="keyword">static</span> <span class="keywordtype">void</span>
consume_item(<span class="keywordtype">int</span> item)
{
printf(<span class="stringliteral">"Item %d consumed\n"</span>, item);
}
<span class="keyword">static</span> <span class="keyword">struct </span><a class="code" href="a00006.html">pt_sem</a> full, empty;
<span class="keyword">static</span>
<a class="code" href="a00014.html#g3d4c8bd4aada659eb34f5d2ffd3e7901">PT_THREAD</a>(producer(<span class="keyword">struct</span> pt *pt))
{
<span class="keyword">static</span> <span class="keywordtype">int</span> produced;
<a class="code" href="a00014.html#g2ffbb9e554e08a343ae2f9de4bedfdfc">PT_BEGIN</a>(pt);
<span class="keywordflow">for</span>(produced = 0; produced &lt; NUM_ITEMS; ++produced) {
<a class="code" href="a00016.html#g386ff87a52a840512906f2940e229e2e">PT_SEM_WAIT</a>(pt, &amp;full);
add_to_buffer(produce_item());
<a class="code" href="a00016.html#g1eaaf4d9d75e24582acc6440d7085f19">PT_SEM_SIGNAL</a>(pt, &amp;empty);
}
<a class="code" href="a00014.html#g7b04a0035bef29d905496c23bae066d2">PT_END</a>(pt);
}
<span class="keyword">static</span>
<a class="code" href="a00014.html#g3d4c8bd4aada659eb34f5d2ffd3e7901">PT_THREAD</a>(consumer(<span class="keyword">struct</span> pt *pt))
{
<span class="keyword">static</span> <span class="keywordtype">int</span> consumed;
<a class="code" href="a00014.html#g2ffbb9e554e08a343ae2f9de4bedfdfc">PT_BEGIN</a>(pt);
<span class="keywordflow">for</span>(consumed = 0; consumed &lt; NUM_ITEMS; ++consumed) {
<a class="code" href="a00016.html#g386ff87a52a840512906f2940e229e2e">PT_SEM_WAIT</a>(pt, &amp;empty);
consume_item(get_from_buffer());
<a class="code" href="a00016.html#g1eaaf4d9d75e24582acc6440d7085f19">PT_SEM_SIGNAL</a>(pt, &amp;full);
}
<a class="code" href="a00014.html#g7b04a0035bef29d905496c23bae066d2">PT_END</a>(pt);
}
<span class="keyword">static</span>
<a class="code" href="a00014.html#g3d4c8bd4aada659eb34f5d2ffd3e7901">PT_THREAD</a>(driver_thread(<span class="keyword">struct</span> pt *pt))
{
<span class="keyword">static</span> <span class="keyword">struct </span>pt pt_producer, pt_consumer;
<a class="code" href="a00014.html#g2ffbb9e554e08a343ae2f9de4bedfdfc">PT_BEGIN</a>(pt);
<a class="code" href="a00016.html#gd7089c5dc86f12019f0361d82a75b04b">PT_SEM_INIT</a>(&amp;empty, 0);
<a class="code" href="a00016.html#gd7089c5dc86f12019f0361d82a75b04b">PT_SEM_INIT</a>(&amp;full, BUFSIZE);
<a class="code" href="a00014.html#ge6bae7dc0225468c8a5ac269df549892">PT_INIT</a>(&amp;pt_producer);
<a class="code" href="a00014.html#ge6bae7dc0225468c8a5ac269df549892">PT_INIT</a>(&amp;pt_consumer);
<a class="code" href="a00014.html#g2f8f70c30b9ee08a103fbd69a4365c4c">PT_WAIT_THREAD</a>(pt, producer(&amp;pt_producer) &amp;
consumer(&amp;pt_consumer));
<a class="code" href="a00014.html#g7b04a0035bef29d905496c23bae066d2">PT_END</a>(pt);
}
<span class="keywordtype">int</span>
main(<span class="keywordtype">void</span>)
{
<span class="keyword">struct </span>pt driver_pt;
<a class="code" href="a00014.html#ge6bae7dc0225468c8a5ac269df549892">PT_INIT</a>(&amp;driver_pt);
<span class="keywordflow">while</span>(<a class="code" href="a00014.html#gfa82b860a64b67d25ab3abc21811896f">PT_SCHEDULE</a>(driver_thread(&amp;driver_pt))) {
<span class="comment">/*</span>
<span class="comment"> * When running this example on a multitasking system, we must</span>
<span class="comment"> * give other processes a chance to run too and therefore we call</span>
<span class="comment"> * usleep() resp. Sleep() here. On a dedicated embedded system,</span>
<span class="comment"> * we usually do not need to do this.</span>
<span class="comment"> */</span>
<span class="preprocessor">#ifdef _WIN32</span>
<span class="preprocessor"></span> Sleep(0);
<span class="preprocessor">#else</span>
<span class="preprocessor"></span> usleep(10);
<span class="preprocessor">#endif</span>
<span class="preprocessor"></span> }
<span class="keywordflow">return</span> 0;
}
</pre></div>
<p>
<table border="0" cellpadding="0" cellspacing="0">
<tr><td></td></tr>
</table>
<hr size="1"><address style="align: right;"><small>Generated on Mon Oct 2 10:06:29 2006 for The Protothreads Library 1.4 by&nbsp;
<a href="http://www.doxygen.org/index.html">
<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.4.6 </small></address>
</body>
</html>