├── LICENSE ├── README.md ├── examples └── exp_protothreads │ └── exp_protothreads.ino ├── keywords.txt ├── lc-addrlabels.h ├── lc-switch.h ├── lc.h ├── pt-sem.h ├── pt-timer.h └── pt.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 P4SSER8Y (Qining Zhang) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ProtoThreads For Arduino 2 | ===================== 3 | 4 | Protothreads are extremely lightweight stackless threads designed for severely 5 | memory constrained systems, such as small embedded systems or wireless sensor 6 | network nodes. 7 | 8 | Protothreads provide linear code execution for event-driven systems 9 | implemented in C. Protothreads can be used with or without an underlying 10 | operating system to provide blocking event-handlers. 11 | 12 | Protothreads provide sequential flow of control without complex state machines 13 | or full multi-threading. 14 | 15 | 16 | Main features: 17 | 18 | * Very small RAM overhead - only two bytes per protothread and no extra stacks 19 | * Highly portable - the protothreads library is 100% pure C and no architecture 20 | specific assembly code 21 | * Can be used with or without an OS 22 | * Provides blocking wait without full multi-threading or stack-switching 23 | * Freely available under a BSD-like open source license 24 | 25 | 26 | Related links: 27 | 28 | Protothreads: 29 | http://www.sics.se/~adam/pt/index.html 30 | 31 | Download of original Protothreads on which this version is based on: 32 | http://www.sics.se/~adam/pt/download.html 33 | 34 | Publications: 35 | http://www.sics.se/~adam/pt/publications.html 36 | 37 | Documentation: 38 | http://www.sics.se/~adam/pt/pt-1.4-refman/ 39 | 40 | Protothreads has been developed by Adam Dunkels 41 | http://www.sics.se/~adam/ 42 | 43 | The original Protothreads implementation by Adam Dunkels as been adopted 44 | to the Arduino platform and is maintained by Benjamin Soelberg. 45 | 46 | The Arduino "implementation" of Protothreads is based on version 1.4 of 47 | the original Protothreads. 48 | 49 | Now, it is developed by P4SSER8Y(P4SSER8Y#outlook.com). 50 | 51 | email benjamin.soelberg@gmail.com 52 | blog http://www.kukkuk.dk 53 | www http://www.javadesign.dk 54 | 55 | -------------------------------------------------------------------------------- /examples/exp_protothreads/exp_protothreads.ino: -------------------------------------------------------------------------------- 1 | #define PT_USE_TIMER 2 | #define PT_USE_SEM 3 | 4 | #include "pt.h" 5 | static struct pt thread1,thread2; 6 | static struct pt_sem sem_LED; 7 | unsigned char i; 8 | 9 | void setup() { 10 | //Set Hardware 11 | pinMode(13,OUTPUT); 12 | Serial.begin(115200); 13 | //Initialize Semaphore 14 | PT_SEM_INIT(&sem_LED,1); 15 | //Initialize the Threads 16 | PT_INIT(&thread1); 17 | PT_INIT(&thread2); 18 | } 19 | 20 | //Blinky LED, 0.5Hz 21 | static int thread1_entry(struct pt *pt) 22 | { 23 | PT_BEGIN(pt); 24 | while (1) 25 | { 26 | PT_SEM_WAIT(pt,&sem_LED); 27 | digitalWrite(13,!digitalRead(13)); 28 | PT_TIMER_DELAY(pt,1000); 29 | PT_SEM_SIGNAL(pt,&sem_LED); 30 | PT_YIELD(pt); //Check the other events. 31 | } 32 | PT_END(pt); 33 | } 34 | 35 | //If a series of chars are sent through COM, blink LED13 quickly for 5 times 36 | static int thread2_entry(struct pt *pt) 37 | { 38 | PT_BEGIN(pt); 39 | while (1) 40 | { 41 | PT_WAIT_UNTIL(pt, Serial.available()); 42 | PT_SEM_WAIT(pt,&sem_LED); 43 | for (i=0;i<5;i++) 44 | { 45 | digitalWrite(13,HIGH); 46 | PT_TIMER_DELAY(pt,200); 47 | digitalWrite(13,LOW); 48 | PT_TIMER_DELAY(pt,200); 49 | } 50 | while (Serial.available()) 51 | Serial.read(); 52 | PT_SEM_SIGNAL(pt,&sem_LED); 53 | } 54 | PT_END(pt); 55 | } 56 | 57 | void loop() { 58 | //Check each thread by priority 59 | thread1_entry(&thread1); 60 | thread2_entry(&thread2); 61 | } 62 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Ultrasound 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | PT_WAITING KEYWORD1 9 | PT_EXITED KEYWORD1 10 | PT_ENDED KEYWORD1 11 | PT_YIELDED KEYWORD1 12 | PT_TIMER KEYWORD1 13 | 14 | ####################################### 15 | # Methods and Functions (KEYWORD2) 16 | ####################################### 17 | PT_INIT KEYWORD2 18 | PT_THREAD KEYWORD2 19 | PT_BEGIN KEYWORD2 20 | PT_END KEYWORD2 21 | PT_WAIT_UNTIL KEYWORD2 22 | PT_WAIT_WHILE KEYWORD2 23 | PT_WAIT_THREAD KEYWORD2 24 | PT_SPAWN KEYWORD2 25 | PT_EXIT KEYWORD2 26 | PT_RESTART KEYWORD2 27 | PT_SCHEDULE KEYWORD2 28 | PT_YIELD KEYWORD2 29 | PT_YIELD_UNTIL KEYWORD2 30 | PT_TIMER_DELAY KEYWORD2 31 | PT_TIMER_MICRODELAY KEYWORD2 32 | PT_TIMER_INIT KEYWORD2 33 | PT_TIMER_WAIT_TIMEOUT KEYWORD2 34 | PT_SEM_INIT KEYWORD2 35 | PT_SEM_WAIT KEYWORD2 36 | PT_SEM_SIGNAL KEYWORD2 37 | 38 | ####################################### 39 | # Constants (LITERAL1) 40 | ####################################### 41 | -------------------------------------------------------------------------------- /lc-addrlabels.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2005, Swedish Institute of Computer Science. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the Institute nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * This file is part of the Contiki operating system. 30 | * 31 | * Author: Adam Dunkels 32 | * 33 | * $Id: lc-addrlabels.h,v 1.4 2006/06/03 11:29:43 adam Exp $ 34 | */ 35 | 36 | /** 37 | * \addtogroup lc 38 | * @{ 39 | */ 40 | 41 | /** 42 | * \file 43 | * Implementation of local continuations based on the "Labels as 44 | * values" feature of gcc 45 | * \author 46 | * Adam Dunkels 47 | * 48 | * This implementation of local continuations is based on a special 49 | * feature of the GCC C compiler called "labels as values". This 50 | * feature allows assigning pointers with the address of the code 51 | * corresponding to a particular C label. 52 | * 53 | * For more information, see the GCC documentation: 54 | * http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html 55 | * 56 | */ 57 | 58 | #ifndef __LC_ADDRLABELS_H__ 59 | #define __LC_ADDRLABELS_H__ 60 | 61 | /** \hideinitializer */ 62 | typedef void * lc_t; 63 | 64 | #define LC_INIT(s) s = NULL 65 | 66 | #define LC_RESUME(s) \ 67 | do { \ 68 | if(s != NULL) { \ 69 | goto *s; \ 70 | } \ 71 | } while(0) 72 | 73 | #define LC_CONCAT2(s1, s2) s1##s2 74 | #define LC_CONCAT(s1, s2) LC_CONCAT2(s1, s2) 75 | 76 | #define LC_SET(s) \ 77 | do { \ 78 | LC_CONCAT(LC_LABEL, __LINE__): \ 79 | (s) = &&LC_CONCAT(LC_LABEL, __LINE__); \ 80 | } while(0) 81 | 82 | #define LC_END(s) 83 | 84 | #endif /* __LC_ADDRLABELS_H__ */ 85 | /** @} */ 86 | -------------------------------------------------------------------------------- /lc-switch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2005, Swedish Institute of Computer Science. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the Institute nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * This file is part of the Contiki operating system. 30 | * 31 | * Author: Adam Dunkels 32 | * 33 | * $Id: lc-switch.h,v 1.4 2006/06/03 11:29:43 adam Exp $ 34 | */ 35 | 36 | /** 37 | * \addtogroup lc 38 | * @{ 39 | */ 40 | 41 | /** 42 | * \file 43 | * Implementation of local continuations based on switch() statment 44 | * \author Adam Dunkels 45 | * 46 | * This implementation of local continuations uses the C switch() 47 | * statement to resume execution of a function somewhere inside the 48 | * function's body. The implementation is based on the fact that 49 | * switch() statements are able to jump directly into the bodies of 50 | * control structures such as if() or while() statmenets. 51 | * 52 | * This implementation borrows heavily from Simon Tatham's coroutines 53 | * implementation in C: 54 | * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html 55 | */ 56 | 57 | #ifndef __LC_SWITCH_H__ 58 | #define __LC_SWITCH_H__ 59 | 60 | /* WARNING! lc implementation using switch() does not work if an 61 | LC_SET() is done within another switch() statement! */ 62 | 63 | /** \hideinitializer */ 64 | typedef unsigned short lc_t; 65 | 66 | #define LC_INIT(s) s = 0; 67 | 68 | #define LC_RESUME(s) switch(s) { case 0: 69 | 70 | #define LC_SET(s) s = __LINE__; case __LINE__: 71 | 72 | #define LC_END(s) } 73 | 74 | #endif /* __LC_SWITCH_H__ */ 75 | 76 | /** @} */ 77 | -------------------------------------------------------------------------------- /lc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2005, Swedish Institute of Computer Science. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the Institute nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * This file is part of the protothreads library. 30 | * 31 | * Author: Adam Dunkels 32 | * 33 | * $Id: lc.h,v 1.2 2005/02/24 10:36:59 adam Exp $ 34 | */ 35 | 36 | /** 37 | * \addtogroup pt 38 | * @{ 39 | */ 40 | 41 | /** 42 | * \defgroup lc Local continuations 43 | * @{ 44 | * 45 | * Local continuations form the basis for implementing protothreads. A 46 | * local continuation can be set in a specific function to 47 | * capture the state of the function. After a local continuation has 48 | * been set can be resumed in order to restore the state of the 49 | * function at the point where the local continuation was set. 50 | * 51 | * 52 | */ 53 | 54 | /** 55 | * \file lc.h 56 | * Local continuations 57 | * \author 58 | * Adam Dunkels 59 | * 60 | */ 61 | 62 | #ifdef DOXYGEN 63 | /** 64 | * Initialize a local continuation. 65 | * 66 | * This operation initializes the local continuation, thereby 67 | * unsetting any previously set continuation state. 68 | * 69 | * \hideinitializer 70 | */ 71 | #define LC_INIT(lc) 72 | 73 | /** 74 | * Set a local continuation. 75 | * 76 | * The set operation saves the state of the function at the point 77 | * where the operation is executed. As far as the set operation is 78 | * concerned, the state of the function does not include the 79 | * call-stack or local (automatic) variables, but only the program 80 | * counter and such CPU registers that needs to be saved. 81 | * 82 | * \hideinitializer 83 | */ 84 | #define LC_SET(lc) 85 | 86 | /** 87 | * Resume a local continuation. 88 | * 89 | * The resume operation resumes a previously set local continuation, thus 90 | * restoring the state in which the function was when the local 91 | * continuation was set. If the local continuation has not been 92 | * previously set, the resume operation does nothing. 93 | * 94 | * \hideinitializer 95 | */ 96 | #define LC_RESUME(lc) 97 | 98 | /** 99 | * Mark the end of local continuation usage. 100 | * 101 | * The end operation signifies that local continuations should not be 102 | * used any more in the function. This operation is not needed for 103 | * most implementations of local continuation, but is required by a 104 | * few implementations. 105 | * 106 | * \hideinitializer 107 | */ 108 | #define LC_END(lc) 109 | 110 | /** 111 | * \var typedef lc_t; 112 | * 113 | * The local continuation type. 114 | * 115 | * \hideinitializer 116 | */ 117 | #endif /* DOXYGEN */ 118 | 119 | #ifndef __LC_H__ 120 | #define __LC_H__ 121 | 122 | #define LC_INCLUDE "lc-addrlabels.h" 123 | 124 | #ifdef LC_INCLUDE 125 | #include LC_INCLUDE 126 | #else 127 | #include "lc-switch.h" 128 | #endif /* LC_INCLUDE */ 129 | 130 | #endif /* __LC_H__ */ 131 | 132 | /** @} */ 133 | /** @} */ 134 | -------------------------------------------------------------------------------- /pt-sem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004, Swedish Institute of Computer Science. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the Institute nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * This file is part of the protothreads library. 30 | * 31 | * Author: Adam Dunkels 32 | * 33 | * $Id: pt-sem.h,v 1.2 2005/02/24 10:36:59 adam Exp $ 34 | */ 35 | 36 | /** 37 | * \addtogroup pt 38 | * @{ 39 | */ 40 | 41 | /** 42 | * \defgroup ptsem Protothread semaphores 43 | * @{ 44 | * 45 | * This module implements counting semaphores on top of 46 | * protothreads. Semaphores are a synchronization primitive that 47 | * provide two operations: "wait" and "signal". The "wait" operation 48 | * checks the semaphore counter and blocks the thread if the counter 49 | * is zero. The "signal" operation increases the semaphore counter but 50 | * does not block. If another thread has blocked waiting for the 51 | * semaphore that is signalled, the blocked thread will become 52 | * runnable again. 53 | * 54 | * Semaphores can be used to implement other, more structured, 55 | * synchronization primitives such as monitors and message 56 | * queues/bounded buffers (see below). 57 | * 58 | * The following example shows how the producer-consumer problem, also 59 | * known as the bounded buffer problem, can be solved using 60 | * protothreads and semaphores. Notes on the program follow after the 61 | * example. 62 | * 63 | \code 64 | #include "pt-sem.inc" 65 | 66 | #define NUM_ITEMS 32 67 | #define BUFSIZE 8 68 | 69 | static struct pt_sem mutex, full, empty; 70 | 71 | PT_THREAD(producer(struct pt *pt)) 72 | { 73 | static int produced; 74 | 75 | PT_BEGIN(pt); 76 | 77 | for(produced = 0; produced < NUM_ITEMS; ++produced) { 78 | 79 | PT_SEM_WAIT(pt, &full); 80 | 81 | PT_SEM_WAIT(pt, &mutex); 82 | add_to_buffer(produce_item()); 83 | PT_SEM_SIGNAL(pt, &mutex); 84 | 85 | PT_SEM_SIGNAL(pt, &empty); 86 | } 87 | 88 | PT_END(pt); 89 | } 90 | 91 | PT_THREAD(consumer(struct pt *pt)) 92 | { 93 | static int consumed; 94 | 95 | PT_BEGIN(pt); 96 | 97 | for(consumed = 0; consumed < NUM_ITEMS; ++consumed) { 98 | 99 | PT_SEM_WAIT(pt, &empty); 100 | 101 | PT_SEM_WAIT(pt, &mutex); 102 | consume_item(get_from_buffer()); 103 | PT_SEM_SIGNAL(pt, &mutex); 104 | 105 | PT_SEM_SIGNAL(pt, &full); 106 | } 107 | 108 | PT_END(pt); 109 | } 110 | 111 | PT_THREAD(driver_thread(struct pt *pt)) 112 | { 113 | static struct pt pt_producer, pt_consumer; 114 | 115 | PT_BEGIN(pt); 116 | 117 | PT_SEM_INIT(&empty, 0); 118 | PT_SEM_INIT(&full, BUFSIZE); 119 | PT_SEM_INIT(&mutex, 1); 120 | 121 | PT_INIT(&pt_producer); 122 | PT_INIT(&pt_consumer); 123 | 124 | PT_WAIT_THREAD(pt, producer(&pt_producer) & 125 | consumer(&pt_consumer)); 126 | 127 | PT_END(pt); 128 | } 129 | \endcode 130 | * 131 | * The program uses three protothreads: one protothread that 132 | * implements the consumer, one thread that implements the producer, 133 | * and one protothread that drives the two other protothreads. The 134 | * program uses three semaphores: "full", "empty" and "mutex". The 135 | * "mutex" semaphore is used to provide mutual exclusion for the 136 | * buffer, the "empty" semaphore is used to block the consumer is the 137 | * buffer is empty, and the "full" semaphore is used to block the 138 | * producer is the buffer is full. 139 | * 140 | * The "driver_thread" holds two protothread state variables, 141 | * "pt_producer" and "pt_consumer". It is important to note that both 142 | * these variables are declared as static. If the static 143 | * keyword is not used, both variables are stored on the stack. Since 144 | * protothreads do not store the stack, these variables may be 145 | * overwritten during a protothread wait operation. Similarly, both 146 | * the "consumer" and "producer" protothreads declare their local 147 | * variables as static, to avoid them being stored on the stack. 148 | * 149 | * 150 | */ 151 | 152 | /** 153 | * \file 154 | * Couting semaphores implemented on protothreads 155 | * \author 156 | * Adam Dunkels 157 | * 158 | */ 159 | 160 | #ifndef __PT_SEM_H__ 161 | #define __PT_SEM_H__ 162 | 163 | #include "pt.h" 164 | 165 | struct pt_sem { 166 | unsigned int count; 167 | }; 168 | 169 | /** 170 | * Initialize a semaphore 171 | * 172 | * This macro initializes a semaphore with a value for the 173 | * counter. Internally, the semaphores use an "unsigned int" to 174 | * represent the counter, and therefore the "count" argument should be 175 | * within range of an unsigned int. 176 | * 177 | * \param s (struct pt_sem *) A pointer to the pt_sem struct 178 | * representing the semaphore 179 | * 180 | * \param c (unsigned int) The initial count of the semaphore. 181 | * \hideinitializer 182 | */ 183 | #define PT_SEM_INIT(s, c) (s)->count = c 184 | 185 | /** 186 | * Wait for a semaphore 187 | * 188 | * This macro carries out the "wait" operation on the semaphore. The 189 | * wait operation causes the protothread to block while the counter is 190 | * zero. When the counter reaches a value larger than zero, the 191 | * protothread will continue. 192 | * 193 | * \param pt (struct pt *) A pointer to the protothread (struct pt) in 194 | * which the operation is executed. 195 | * 196 | * \param s (struct pt_sem *) A pointer to the pt_sem struct 197 | * representing the semaphore 198 | * 199 | * \hideinitializer 200 | */ 201 | #define PT_SEM_WAIT(pt, s) \ 202 | do { \ 203 | PT_WAIT_UNTIL(pt, (s)->count > 0); \ 204 | --(s)->count; \ 205 | } while(0) 206 | 207 | /** 208 | * Signal a semaphore 209 | * 210 | * This macro carries out the "signal" operation on the semaphore. The 211 | * signal operation increments the counter inside the semaphore, which 212 | * eventually will cause waiting protothreads to continue executing. 213 | * 214 | * \param pt (struct pt *) A pointer to the protothread (struct pt) in 215 | * which the operation is executed. 216 | * 217 | * \param s (struct pt_sem *) A pointer to the pt_sem struct 218 | * representing the semaphore 219 | * 220 | * \hideinitializer 221 | */ 222 | #define PT_SEM_SIGNAL(pt, s) ++(s)->count 223 | 224 | #endif /* __PT_SEM_H__ */ 225 | 226 | /** @} */ 227 | /** @} */ 228 | 229 | -------------------------------------------------------------------------------- /pt-timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Huazhong University of Science and Technology 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the Institute nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * Author: Troy Cheung 30 | * 31 | */ 32 | 33 | #ifndef __PT_TIMER__ 34 | #define __PT_TIMER__ 35 | 36 | typedef unsigned long pt_timer; 37 | 38 | /** 39 | * \name Delay for milliseconds 40 | * @{ 41 | */ 42 | 43 | /** 44 | * Delay for specific milliseconds 45 | */ 46 | #define PT_TIMER_DELAY(pt,time) \ 47 | do { \ 48 | (pt)->t = millis(); \ 49 | PT_WAIT_UNTIL((pt),((pt_timer)(millis()-(pt)->t)>=(time)));\ 50 | }while(0) 51 | 52 | /** 53 | * \name Delay for microseconds 54 | * @{ 55 | */ 56 | 57 | /** 58 | * Delay for specific microseconds 59 | */ 60 | #define PT_TIMER_MICRODELAY(pt,time)\ 61 | do { \ 62 | (pt)->t = micros(); \ 63 | PT_WAIT_UNTIL((pt),((pt_timer)(micros()-(pt)->t)>=(time)));\ 64 | }while(0) 65 | 66 | /** 67 | * \name Wait for some condition or timeout 68 | * @{ 69 | */ 70 | 71 | /** 72 | * Wait for condition's becoming true or timeout 73 | */ 74 | #define PT_TIMER_WAIT_TIMEOUT(pt,condition,time) \ 75 | do { \ 76 | (pt)->t = millis(); \ 77 | PT_WAIT_UNTIL((pt),(condition)||((pt_timer)(millis()-(pt)->t)>=(time)));\ 78 | }while(0) 79 | 80 | /** 81 | * \name Delay for specific milliseconds while condition 82 | * @{ 83 | */ 84 | 85 | /** 86 | * Delay for specific milliseconds while condition 87 | */ 88 | #define PT_TIMER_WHILE_DELAY(pt,condition,time) \ 89 | do { \ 90 | (pt)->t = millis(); \ 91 | LC_SET((pt)->lc); \ 92 | if(!(condition)) { \ 93 | PT_RESTART(pt); \ 94 | } \ 95 | if((pt_timer)(millis()-(pt)->t)<(time)) { \ 96 | return PT_WAITING; \ 97 | } \ 98 | }while(0) 99 | 100 | #endif /* __PT_TIMER__*/ 101 | -------------------------------------------------------------------------------- /pt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2006, Swedish Institute of Computer Science. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the Institute nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * Author: Adam Dunkels 30 | * 31 | * $Id: pt.h,v 1.6 2006/06/03 11:29:43 adam Exp $ 32 | */ 33 | 34 | /** 35 | * \addtogroup pt 36 | * @{ 37 | */ 38 | 39 | /** 40 | * \file 41 | * Protothreads implementation. 42 | * \author 43 | * Adam Dunkels 44 | * 45 | */ 46 | 47 | #ifndef __PT_H__ 48 | #define __PT_H__ 49 | 50 | #include "lc.h" 51 | 52 | #ifdef PT_USE_TIMER 53 | #include "pt-timer.h" 54 | #endif 55 | 56 | #ifdef PT_USE_SEM 57 | #include "pt-sem.h" 58 | #endif 59 | 60 | struct pt { 61 | lc_t lc; 62 | #ifdef PT_USE_TIMER 63 | pt_timer t; 64 | #endif 65 | }; 66 | 67 | 68 | #define PT_WAITING 0 69 | #define PT_EXITED 1 70 | #define PT_ENDED 2 71 | #define PT_YIELDED 3 72 | 73 | /** 74 | * \name Initialization 75 | * @{ 76 | */ 77 | 78 | /** 79 | * Initialize a protothread. 80 | * 81 | * Initializes a protothread. Initialization must be done prior to 82 | * starting to execute the protothread. 83 | * 84 | * \param pt A pointer to the protothread control structure. 85 | * 86 | * \sa PT_SPAWN() 87 | * 88 | * \hideinitializer 89 | */ 90 | #define PT_INIT(pt) LC_INIT((pt)->lc) 91 | 92 | /** @} */ 93 | 94 | /** 95 | * \name Declaration and definition 96 | * @{ 97 | */ 98 | 99 | /** 100 | * Declaration of a protothread function. 101 | * 102 | * This macro is used to declare a protothread function. Protothreads 103 | * function should be declared with this macro, but can also be 104 | * declared as regular C functions that return an integer value. 105 | * 106 | * \param name_args The name and arguments of the C function 107 | * implementing the protothread. 108 | * 109 | * \hideinitializer 110 | */ 111 | #define PT_THREAD(name_args) char name_args 112 | 113 | /** 114 | * Declare the start of a protothread inside the C function 115 | * implementing the protothread. 116 | * 117 | * This macro is used to declare the starting point of a 118 | * protothread. It should be placed at the start of the function in 119 | * which the protothread runs. All C statements above the PT_BEGIN() 120 | * invokation will be executed each time the protothread is scheduled. 121 | * 122 | * \param pt A pointer to the protothread control structure. 123 | * 124 | * \hideinitializer 125 | */ 126 | #define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc) 127 | 128 | /** 129 | * Declare the end of a protothread. 130 | * 131 | * This macro is used for declaring that a protothread ends. It must 132 | * always be used together with a matching PT_BEGIN() macro. 133 | * 134 | * \param pt A pointer to the protothread control structure. 135 | * 136 | * \hideinitializer 137 | */ 138 | #define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \ 139 | PT_INIT(pt); return PT_ENDED; } 140 | 141 | /** @} */ 142 | 143 | /** 144 | * \name Blocked wait 145 | * @{ 146 | */ 147 | 148 | /** 149 | * Block and wait until condition is true. 150 | * 151 | * This macro blocks the protothread until the specified condition is 152 | * true. 153 | * 154 | * \param pt A pointer to the protothread control structure. 155 | * \param condition The condition. 156 | * 157 | * \hideinitializer 158 | */ 159 | #define PT_WAIT_UNTIL(pt, condition) \ 160 | do { \ 161 | LC_SET((pt)->lc); \ 162 | if(!(condition)) { \ 163 | return PT_WAITING; \ 164 | } \ 165 | } while(0) 166 | 167 | /** 168 | * Block and wait while condition is true. 169 | * 170 | * This function blocks and waits while condition is true. See 171 | * PT_WAIT_UNTIL(). 172 | * 173 | * \param pt A pointer to the protothread control structure. 174 | * \param cond The condition. 175 | * 176 | * \hideinitializer 177 | */ 178 | #define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond)) 179 | 180 | /** @} */ 181 | 182 | /** 183 | * \name Hierarchical protothreads 184 | * @{ 185 | */ 186 | 187 | /** 188 | * Block and wait until a child protothread completes. 189 | * 190 | * This macro schedules a child protothread. The current protothread 191 | * will block until the child protothread completes. 192 | * 193 | * \note The child protothread must be manually initialized with the 194 | * PT_INIT() function before this function is used. 195 | * 196 | * \param pt A pointer to the protothread control structure. 197 | * \param thread The child protothread with arguments 198 | * 199 | * \sa PT_SPAWN() 200 | * 201 | * \hideinitializer 202 | */ 203 | #define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread)) 204 | 205 | /** 206 | * Spawn a child protothread and wait until it exits. 207 | * 208 | * This macro spawns a child protothread and waits until it exits. The 209 | * macro can only be used within a protothread. 210 | * 211 | * \param pt A pointer to the protothread control structure. 212 | * \param child A pointer to the child protothread's control structure. 213 | * \param thread The child protothread with arguments 214 | * 215 | * \hideinitializer 216 | */ 217 | #define PT_SPAWN(pt, child, thread) \ 218 | do { \ 219 | PT_INIT((child)); \ 220 | PT_WAIT_THREAD((pt), (thread)); \ 221 | } while(0) 222 | 223 | /** @} */ 224 | 225 | /** 226 | * \name Exiting and restarting 227 | * @{ 228 | */ 229 | 230 | /** 231 | * Restart the protothread. 232 | * 233 | * This macro will block and cause the running protothread to restart 234 | * its execution at the place of the PT_BEGIN() call. 235 | * 236 | * \param pt A pointer to the protothread control structure. 237 | * 238 | * \hideinitializer 239 | */ 240 | #define PT_RESTART(pt) \ 241 | do { \ 242 | PT_INIT(pt); \ 243 | return PT_WAITING; \ 244 | } while(0) 245 | 246 | /** 247 | * Exit the protothread. 248 | * 249 | * This macro causes the protothread to exit. If the protothread was 250 | * spawned by another protothread, the parent protothread will become 251 | * unblocked and can continue to run. 252 | * 253 | * \param pt A pointer to the protothread control structure. 254 | * 255 | * \hideinitializer 256 | */ 257 | #define PT_EXIT(pt) \ 258 | do { \ 259 | PT_INIT(pt); \ 260 | return PT_EXITED; \ 261 | } while(0) 262 | 263 | /** @} */ 264 | 265 | /** 266 | * \name Calling a protothread 267 | * @{ 268 | */ 269 | 270 | /** 271 | * Schedule a protothread. 272 | * 273 | * This function shedules a protothread. The return value of the 274 | * function is non-zero if the protothread is running or zero if the 275 | * protothread has exited. 276 | * 277 | * \param f The call to the C function implementing the protothread to 278 | * be scheduled 279 | * 280 | * \hideinitializer 281 | */ 282 | #define PT_SCHEDULE(f) ((f) == PT_WAITING) 283 | 284 | /** @} */ 285 | 286 | /** 287 | * \name Yielding from a protothread 288 | * @{ 289 | */ 290 | 291 | /** 292 | * Yield from the current protothread. 293 | * 294 | * This function will yield the protothread, thereby allowing other 295 | * processing to take place in the system. 296 | * 297 | * \param pt A pointer to the protothread control structure. 298 | * 299 | * \hideinitializer 300 | */ 301 | #define PT_YIELD(pt) \ 302 | do { \ 303 | PT_YIELD_FLAG = 0; \ 304 | LC_SET((pt)->lc); \ 305 | if(PT_YIELD_FLAG == 0) { \ 306 | return PT_YIELDED; \ 307 | } \ 308 | } while(0) 309 | 310 | /** 311 | * \brief Yield from the protothread until a condition occurs. 312 | * \param pt A pointer to the protothread control structure. 313 | * \param cond The condition. 314 | * 315 | * This function will yield the protothread, until the 316 | * specified condition evaluates to true. 317 | * 318 | * 319 | * \hideinitializer 320 | */ 321 | #define PT_YIELD_UNTIL(pt, cond) \ 322 | do { \ 323 | PT_YIELD_FLAG = 0; \ 324 | LC_SET((pt)->lc); \ 325 | if((PT_YIELD_FLAG == 0) || !(cond)) { \ 326 | return PT_YIELDED; \ 327 | } \ 328 | } while(0) 329 | 330 | /** @} */ 331 | 332 | #endif /* __PT_H__ */ 333 | 334 | /** @} */ 335 | --------------------------------------------------------------------------------