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 uIP TCP/IP stack 30 * 31 * Author: Adam Dunkels <[email protected]> 32 * 33 * $Id: pt.h,v 1.2 2006/06/12 08:00:30 adam Exp $ 34 */ 35 36 /** 37 * \addtogroup pt 38 * @{ 39 */ 40 41 /** 42 * \file 43 * Protothreads implementation. 44 * \author 45 * Adam Dunkels <[email protected]> 46 * 47 */ 48 49 #ifndef __PT_H__ 50 #define __PT_H__ 51 52 #include "lc.h" 53 54 struct pt { 55 lc_t lc; 56 }; 57 58 #define PT_WAITING 0 59 #define PT_EXITED 1 60 #define PT_ENDED 2 61 #define PT_YIELDED 3 62 63 /** 64 * \name Initialization 65 * @{ 66 */ 67 68 /** 69 * Initialize a protothread. 70 * 71 * Initializes a protothread. Initialization must be done prior to 72 * starting to execute the protothread. 73 * 74 * \param pt A pointer to the protothread control structure. 75 * 76 * \sa PT_SPAWN() 77 * 78 * \hideinitializer 79 */ 80 #define PT_INIT(pt) LC_INIT((pt)->lc) 81 82 /** @} */ 83 84 /** 85 * \name Declaration and definition 86 * @{ 87 */ 88 89 /** 90 * Declaration of a protothread. 91 * 92 * This macro is used to declare a protothread. All protothreads must 93 * be declared with this macro. 94 * 95 * \param name_args The name and arguments of the C function 96 * implementing the protothread. 97 * 98 * \hideinitializer 99 */ 100 #define PT_THREAD(name_args) char name_args 101 102 /** 103 * Declare the start of a protothread inside the C function 104 * implementing the protothread. 105 * 106 * This macro is used to declare the starting point of a 107 * protothread. It should be placed at the start of the function in 108 * which the protothread runs. All C statements above the PT_BEGIN() 109 * invokation will be executed each time the protothread is scheduled. 110 * 111 * \param pt A pointer to the protothread control structure. 112 * 113 * \hideinitializer 114 */ 115 #define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc) 116 117 /** 118 * Declare the end of a protothread. 119 * 120 * This macro is used for declaring that a protothread ends. It must 121 * always be used together with a matching PT_BEGIN() macro. 122 * 123 * \param pt A pointer to the protothread control structure. 124 * 125 * \hideinitializer 126 */ 127 #define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \ 128 PT_INIT(pt); return PT_ENDED; } 129 130 /** @} */ 131 132 /** 133 * \name Blocked wait 134 * @{ 135 */ 136 137 /** 138 * Block and wait until condition is true. 139 * 140 * This macro blocks the protothread until the specified condition is 141 * true. 142 * 143 * \param pt A pointer to the protothread control structure. 144 * \param condition The condition. 145 * 146 * \hideinitializer 147 */ 148 #define PT_WAIT_UNTIL(pt, condition) \ 149 do { \ 150 LC_SET((pt)->lc); \ 151 if(!(condition)) { \ 152 return PT_WAITING; \ 153 } \ 154 } while(0) 155 156 /** 157 * Block and wait while condition is true. 158 * 159 * This function blocks and waits while condition is true. See 160 * PT_WAIT_UNTIL(). 161 * 162 * \param pt A pointer to the protothread control structure. 163 * \param cond The condition. 164 * 165 * \hideinitializer 166 */ 167 #define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond)) 168 169 /** @} */ 170 171 /** 172 * \name Hierarchical protothreads 173 * @{ 174 */ 175 176 /** 177 * Block and wait until a child protothread completes. 178 * 179 * This macro schedules a child protothread. The current protothread 180 * will block until the child protothread completes. 181 * 182 * \note The child protothread must be manually initialized with the 183 * PT_INIT() function before this function is used. 184 * 185 * \param pt A pointer to the protothread control structure. 186 * \param thread The child protothread with arguments 187 * 188 * \sa PT_SPAWN() 189 * 190 * \hideinitializer 191 */ 192 #define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread)) 193 194 /** 195 * Spawn a child protothread and wait until it exits. 196 * 197 * This macro spawns a child protothread and waits until it exits. The 198 * macro can only be used within a protothread. 199 * 200 * \param pt A pointer to the protothread control structure. 201 * \param child A pointer to the child protothread's control structure. 202 * \param thread The child protothread with arguments 203 * 204 * \hideinitializer 205 */ 206 #define PT_SPAWN(pt, child, thread) \ 207 do { \ 208 PT_INIT((child)); \ 209 PT_WAIT_THREAD((pt), (thread)); \ 210 } while(0) 211 212 /** @} */ 213 214 /** 215 * \name Exiting and restarting 216 * @{ 217 */ 218 219 /** 220 * Restart the protothread. 221 * 222 * This macro will block and cause the running protothread to restart 223 * its execution at the place of the PT_BEGIN() call. 224 * 225 * \param pt A pointer to the protothread control structure. 226 * 227 * \hideinitializer 228 */ 229 #define PT_RESTART(pt) \ 230 do { \ 231 PT_INIT(pt); \ 232 return PT_WAITING; \ 233 } while(0) 234 235 /** 236 * Exit the protothread. 237 * 238 * This macro causes the protothread to exit. If the protothread was 239 * spawned by another protothread, the parent protothread will become 240 * unblocked and can continue to run. 241 * 242 * \param pt A pointer to the protothread control structure. 243 * 244 * \hideinitializer 245 */ 246 #define PT_EXIT(pt) \ 247 do { \ 248 PT_INIT(pt); \ 249 return PT_EXITED; \ 250 } while(0) 251 252 /** @} */ 253 254 /** 255 * \name Calling a protothread 256 * @{ 257 */ 258 259 /** 260 * Schedule a protothread. 261 * 262 * This function shedules a protothread. The return value of the 263 * function is non-zero if the protothread is running or zero if the 264 * protothread has exited. 265 * 266 * \param f The call to the C function implementing the protothread to 267 * be scheduled 268 * 269 * \hideinitializer 270 */ 271 #define PT_SCHEDULE(f) ((f) == PT_WAITING) 272 273 /** @} */ 274 275 /** 276 * \name Yielding from a protothread 277 * @{ 278 */ 279 280 /** 281 * Yield from the current protothread. 282 * 283 * This function will yield the protothread, thereby allowing other 284 * processing to take place in the system. 285 * 286 * \param pt A pointer to the protothread control structure. 287 * 288 * \hideinitializer 289 */ 290 #define PT_YIELD(pt) \ 291 do { \ 292 PT_YIELD_FLAG = 0; \ 293 LC_SET((pt)->lc); \ 294 if(PT_YIELD_FLAG == 0) { \ 295 return PT_YIELDED; \ 296 } \ 297 } while(0) 298 299 /** 300 * \brief Yield from the protothread until a condition occurs. 301 * \param pt A pointer to the protothread control structure. 302 * \param cond The condition. 303 * 304 * This function will yield the protothread, until the 305 * specified condition evaluates to true. 306 * 307 * 308 * \hideinitializer 309 */ 310 #define PT_YIELD_UNTIL(pt, cond) \ 311 do { \ 312 PT_YIELD_FLAG = 0; \ 313 LC_SET((pt)->lc); \ 314 if((PT_YIELD_FLAG == 0) || !(cond)) { \ 315 return PT_YIELDED; \ 316 } \ 317 } while(0) 318 319 /** @} */ 320 321 #endif /* __PT_H__ */ 322 323 /** @} */ 324