Robert Sochuliak
/
Vytah
test
Protothread.h@0:e541909ea6b0, 2019-01-24 (annotated)
- Committer:
- hodgins
- Date:
- Thu Jan 24 06:35:38 2019 +0000
- Revision:
- 0:e541909ea6b0
test
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hodgins | 0:e541909ea6b0 | 1 | // Protothread class and macros for lightweight, stackless threads in C++. |
hodgins | 0:e541909ea6b0 | 2 | // |
hodgins | 0:e541909ea6b0 | 3 | // This was "ported" to C++ from Adam Dunkels' protothreads C library at: |
hodgins | 0:e541909ea6b0 | 4 | // http://www.sics.se/~adam/pt/ |
hodgins | 0:e541909ea6b0 | 5 | // |
hodgins | 0:e541909ea6b0 | 6 | // Originally ported for use by Hamilton Jet (www.hamiltonjet.co.nz) by |
hodgins | 0:e541909ea6b0 | 7 | // Ben Hoyt, but stripped down for public release. See his blog entry about |
hodgins | 0:e541909ea6b0 | 8 | // it for more information: |
hodgins | 0:e541909ea6b0 | 9 | // http://blog.brush.co.nz/2008/07/protothreads/ |
hodgins | 0:e541909ea6b0 | 10 | // |
hodgins | 0:e541909ea6b0 | 11 | // Visual Studio users: There's a quirk with VS where it defines __LINE__ |
hodgins | 0:e541909ea6b0 | 12 | // as a non-constant when you've got a project's Debug Information Format |
hodgins | 0:e541909ea6b0 | 13 | // set to "Program Database for Edit and Continue (/ZI)" -- the default. |
hodgins | 0:e541909ea6b0 | 14 | // To fix, just go to the project's Properties, Configuration Properties, |
hodgins | 0:e541909ea6b0 | 15 | // C/C++, General, Debug Information Format, and change it to "Program |
hodgins | 0:e541909ea6b0 | 16 | // Database (/Zi)". |
hodgins | 0:e541909ea6b0 | 17 | // |
hodgins | 0:e541909ea6b0 | 18 | // -------------------------- |
hodgins | 0:e541909ea6b0 | 19 | // Original BSD-style license |
hodgins | 0:e541909ea6b0 | 20 | // -------------------------- |
hodgins | 0:e541909ea6b0 | 21 | // Copyright (c) 2004-2005, Swedish Institute of Computer Science. |
hodgins | 0:e541909ea6b0 | 22 | // All rights reserved. |
hodgins | 0:e541909ea6b0 | 23 | // |
hodgins | 0:e541909ea6b0 | 24 | // Redistribution and use in source and binary forms, with or without |
hodgins | 0:e541909ea6b0 | 25 | // modification, are permitted provided that the following conditions |
hodgins | 0:e541909ea6b0 | 26 | // are met: |
hodgins | 0:e541909ea6b0 | 27 | // |
hodgins | 0:e541909ea6b0 | 28 | // 1. Redistributions of source code must retain the above copyright |
hodgins | 0:e541909ea6b0 | 29 | // notice, this list of conditions and the following disclaimer. |
hodgins | 0:e541909ea6b0 | 30 | // 2. Redistributions in binary form must reproduce the above copyright |
hodgins | 0:e541909ea6b0 | 31 | // notice, this list of conditions and the following disclaimer in the |
hodgins | 0:e541909ea6b0 | 32 | // documentation and/or other materials provided with the distribution. |
hodgins | 0:e541909ea6b0 | 33 | // 3. Neither the name of the Institute nor the names of its contributors |
hodgins | 0:e541909ea6b0 | 34 | // may be used to endorse or promote products derived from this software |
hodgins | 0:e541909ea6b0 | 35 | // without specific prior written permission. |
hodgins | 0:e541909ea6b0 | 36 | // |
hodgins | 0:e541909ea6b0 | 37 | // This software is provided by the Institute and contributors "as is" and |
hodgins | 0:e541909ea6b0 | 38 | // any express or implied warranties, including, but not limited to, the |
hodgins | 0:e541909ea6b0 | 39 | // implied warranties of merchantability and fitness for a particular purpose |
hodgins | 0:e541909ea6b0 | 40 | // are disclaimed. In no event shall the Institute or contributors be liable |
hodgins | 0:e541909ea6b0 | 41 | // for any direct, indirect, incidental, special, exemplary, or consequential |
hodgins | 0:e541909ea6b0 | 42 | // damages (including, but not limited to, procurement of substitute goods |
hodgins | 0:e541909ea6b0 | 43 | // or services; loss of use, data, or profits; or business interruption) |
hodgins | 0:e541909ea6b0 | 44 | // however caused and on any theory of liability, whether in contract, strict |
hodgins | 0:e541909ea6b0 | 45 | // liability, or tort (including negligence or otherwise) arising in any way |
hodgins | 0:e541909ea6b0 | 46 | // out of the use of this software, even if advised of the possibility of |
hodgins | 0:e541909ea6b0 | 47 | // such damage. |
hodgins | 0:e541909ea6b0 | 48 | // |
hodgins | 0:e541909ea6b0 | 49 | |
hodgins | 0:e541909ea6b0 | 50 | #ifndef __PROTOTHREAD_H__ |
hodgins | 0:e541909ea6b0 | 51 | #define __PROTOTHREAD_H__ |
hodgins | 0:e541909ea6b0 | 52 | |
hodgins | 0:e541909ea6b0 | 53 | // A lightweight, stackless thread. Override the Run() method and use |
hodgins | 0:e541909ea6b0 | 54 | // the PT_* macros to do work of the thread. |
hodgins | 0:e541909ea6b0 | 55 | // |
hodgins | 0:e541909ea6b0 | 56 | // A simple example |
hodgins | 0:e541909ea6b0 | 57 | // ---------------- |
hodgins | 0:e541909ea6b0 | 58 | // class LEDFlasher : public Protothread |
hodgins | 0:e541909ea6b0 | 59 | // { |
hodgins | 0:e541909ea6b0 | 60 | // public: |
hodgins | 0:e541909ea6b0 | 61 | // virtual bool Run(); |
hodgins | 0:e541909ea6b0 | 62 | // |
hodgins | 0:e541909ea6b0 | 63 | // private: |
hodgins | 0:e541909ea6b0 | 64 | // ExpiryTimer _timer; |
hodgins | 0:e541909ea6b0 | 65 | // uintf _i; |
hodgins | 0:e541909ea6b0 | 66 | // }; |
hodgins | 0:e541909ea6b0 | 67 | // |
hodgins | 0:e541909ea6b0 | 68 | // bool LEDFlasher::Run() |
hodgins | 0:e541909ea6b0 | 69 | // { |
hodgins | 0:e541909ea6b0 | 70 | // PT_BEGIN(); |
hodgins | 0:e541909ea6b0 | 71 | // |
hodgins | 0:e541909ea6b0 | 72 | // for (_i = 0; _i < 10; _i++) |
hodgins | 0:e541909ea6b0 | 73 | // { |
hodgins | 0:e541909ea6b0 | 74 | // SetLED(true); |
hodgins | 0:e541909ea6b0 | 75 | // _timer.Start(250); |
hodgins | 0:e541909ea6b0 | 76 | // PT_WAIT_UNTIL(_timer.Expired()); |
hodgins | 0:e541909ea6b0 | 77 | // |
hodgins | 0:e541909ea6b0 | 78 | // SetLED(false); |
hodgins | 0:e541909ea6b0 | 79 | // _timer.Start(750); |
hodgins | 0:e541909ea6b0 | 80 | // PT_WAIT_UNTIL(_timer.Expired()); |
hodgins | 0:e541909ea6b0 | 81 | // } |
hodgins | 0:e541909ea6b0 | 82 | // |
hodgins | 0:e541909ea6b0 | 83 | // PT_END(); |
hodgins | 0:e541909ea6b0 | 84 | // } |
hodgins | 0:e541909ea6b0 | 85 | // |
hodgins | 0:e541909ea6b0 | 86 | class Protothread |
hodgins | 0:e541909ea6b0 | 87 | { |
hodgins | 0:e541909ea6b0 | 88 | public: |
hodgins | 0:e541909ea6b0 | 89 | // Construct a new protothread that will start from the beginning |
hodgins | 0:e541909ea6b0 | 90 | // of its Run() function. |
hodgins | 0:e541909ea6b0 | 91 | Protothread() : _ptLine(0) { } |
hodgins | 0:e541909ea6b0 | 92 | |
hodgins | 0:e541909ea6b0 | 93 | // Restart protothread. |
hodgins | 0:e541909ea6b0 | 94 | void Restart() { _ptLine = 0; } |
hodgins | 0:e541909ea6b0 | 95 | |
hodgins | 0:e541909ea6b0 | 96 | // Stop the protothread from running. Happens automatically at PT_END. |
hodgins | 0:e541909ea6b0 | 97 | // Note: this differs from the Dunkels' original protothread behaviour |
hodgins | 0:e541909ea6b0 | 98 | // (his restart automatically, which is usually not what you want). |
hodgins | 0:e541909ea6b0 | 99 | void Stop() { _ptLine = LineNumberInvalid; } |
hodgins | 0:e541909ea6b0 | 100 | |
hodgins | 0:e541909ea6b0 | 101 | // Return true if the protothread is running or waiting, false if it has |
hodgins | 0:e541909ea6b0 | 102 | // ended or exited. |
hodgins | 0:e541909ea6b0 | 103 | bool IsRunning() { return _ptLine != LineNumberInvalid; } |
hodgins | 0:e541909ea6b0 | 104 | |
hodgins | 0:e541909ea6b0 | 105 | // Run next part of protothread or return immediately if it's still |
hodgins | 0:e541909ea6b0 | 106 | // waiting. Return true if protothread is still running, false if it |
hodgins | 0:e541909ea6b0 | 107 | // has finished. Implement this method in your Protothread subclass. |
hodgins | 0:e541909ea6b0 | 108 | virtual bool Run() = 0; |
hodgins | 0:e541909ea6b0 | 109 | |
hodgins | 0:e541909ea6b0 | 110 | protected: |
hodgins | 0:e541909ea6b0 | 111 | // Used to store a protothread's position (what Dunkels calls a |
hodgins | 0:e541909ea6b0 | 112 | // "local continuation"). |
hodgins | 0:e541909ea6b0 | 113 | typedef unsigned short LineNumber; |
hodgins | 0:e541909ea6b0 | 114 | |
hodgins | 0:e541909ea6b0 | 115 | // An invalid line number, used to mark the protothread has ended. |
hodgins | 0:e541909ea6b0 | 116 | static const LineNumber LineNumberInvalid = (LineNumber)(-1); |
hodgins | 0:e541909ea6b0 | 117 | |
hodgins | 0:e541909ea6b0 | 118 | // Stores the protothread's position (by storing the line number of |
hodgins | 0:e541909ea6b0 | 119 | // the last PT_WAIT, which is then switched on at the next Run). |
hodgins | 0:e541909ea6b0 | 120 | LineNumber _ptLine; |
hodgins | 0:e541909ea6b0 | 121 | }; |
hodgins | 0:e541909ea6b0 | 122 | |
hodgins | 0:e541909ea6b0 | 123 | // Declare start of protothread (use at start of Run() implementation). |
hodgins | 0:e541909ea6b0 | 124 | #define PT_BEGIN() bool ptYielded = true; (void) ptYielded; switch (_ptLine) { case 0: |
hodgins | 0:e541909ea6b0 | 125 | |
hodgins | 0:e541909ea6b0 | 126 | // Stop protothread and end it (use at end of Run() implementation). |
hodgins | 0:e541909ea6b0 | 127 | #define PT_END() default: ; } Stop(); return false; |
hodgins | 0:e541909ea6b0 | 128 | |
hodgins | 0:e541909ea6b0 | 129 | // Cause protothread to wait until given condition is true. |
hodgins | 0:e541909ea6b0 | 130 | #define PT_WAIT_UNTIL(condition) \ |
hodgins | 0:e541909ea6b0 | 131 | do { _ptLine = __LINE__; case __LINE__: \ |
hodgins | 0:e541909ea6b0 | 132 | if (!(condition)) return true; } while (0) |
hodgins | 0:e541909ea6b0 | 133 | |
hodgins | 0:e541909ea6b0 | 134 | // Cause protothread to wait while given condition is true. |
hodgins | 0:e541909ea6b0 | 135 | #define PT_WAIT_WHILE(condition) PT_WAIT_UNTIL(!(condition)) |
hodgins | 0:e541909ea6b0 | 136 | |
hodgins | 0:e541909ea6b0 | 137 | // Cause protothread to wait until given child protothread completes. |
hodgins | 0:e541909ea6b0 | 138 | #define PT_WAIT_THREAD(child) PT_WAIT_WHILE((child).Run()) |
hodgins | 0:e541909ea6b0 | 139 | |
hodgins | 0:e541909ea6b0 | 140 | // Restart and spawn given child protothread and wait until it completes. |
hodgins | 0:e541909ea6b0 | 141 | #define PT_SPAWN(child) \ |
hodgins | 0:e541909ea6b0 | 142 | do { (child).Restart(); PT_WAIT_THREAD(child); } while (0) |
hodgins | 0:e541909ea6b0 | 143 | |
hodgins | 0:e541909ea6b0 | 144 | // Restart protothread's execution at its PT_BEGIN. |
hodgins | 0:e541909ea6b0 | 145 | #define PT_RESTART() do { Restart(); return true; } while (0) |
hodgins | 0:e541909ea6b0 | 146 | |
hodgins | 0:e541909ea6b0 | 147 | // Stop and exit from protothread. |
hodgins | 0:e541909ea6b0 | 148 | #define PT_EXIT() do { Stop(); return false; } while (0) |
hodgins | 0:e541909ea6b0 | 149 | |
hodgins | 0:e541909ea6b0 | 150 | // Yield protothread till next call to its Run(). |
hodgins | 0:e541909ea6b0 | 151 | #define PT_YIELD() \ |
hodgins | 0:e541909ea6b0 | 152 | do { ptYielded = false; _ptLine = __LINE__; case __LINE__: \ |
hodgins | 0:e541909ea6b0 | 153 | if (!ptYielded) return true; } while (0) |
hodgins | 0:e541909ea6b0 | 154 | |
hodgins | 0:e541909ea6b0 | 155 | // Yield protothread until given condition is true. |
hodgins | 0:e541909ea6b0 | 156 | #define PT_YIELD_UNTIL(condition) \ |
hodgins | 0:e541909ea6b0 | 157 | do { ptYielded = false; _ptLine = __LINE__; case __LINE__: \ |
hodgins | 0:e541909ea6b0 | 158 | if (!ptYielded || !(condition)) return true; } while (0) |
hodgins | 0:e541909ea6b0 | 159 | |
hodgins | 0:e541909ea6b0 | 160 | #endif // __PROTOTHREAD_H__ |