00001 /* 00002 * Copyright (c) 2004-2005, Swedish Institute of Computer Science. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the Institute nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 * 00029 * This file is part of the Contiki operating system. 00030 * 00031 * Author: Adam Dunkels <adam@sics.se> 00032 * 00033 * $Id: pt.h,v 1.6 2005/06/03 06:42:19 adam Exp $ 00034 */ 00035 00036 /** 00037 * \addtogroup pt 00038 * @{ 00039 */ 00040 00041 /** 00042 * \file 00043 * Protothreads implementation. 00044 * \author 00045 * Adam Dunkels <adam@sics.se> 00046 * 00047 */ 00048 00049 #ifndef __PT_H__ 00050 #define __PT_H__ 00051 00052 #include "lc.h" 00053 00054 struct pt { 00055 lc_t lc; 00056 }; 00057 00058 #define PT_THREAD_WAITING 0 00059 #define PT_THREAD_EXITED 1 00060 00061 /** 00062 * Declaration of a protothread. 00063 * 00064 * This macro is used to declare a protothread. All protothreads must 00065 * be declared with this macro. 00066 * 00067 * Example: 00068 \code 00069 PT_THREAD(consumer(struct pt *p, int event)) { 00070 PT_BEGIN(p); 00071 while(1) { 00072 PT_WAIT_UNTIL(p, event == AVAILABLE); 00073 consume(); 00074 PT_WAIT_UNTIL(p, event == CONSUMED); 00075 acknowledge_consumed(); 00076 } 00077 PT_END(p); 00078 } 00079 \endcode 00080 * 00081 * \param name_args The name and arguments of the C function 00082 * implementing the protothread. 00083 * 00084 * \hideinitializer 00085 */ 00086 #define PT_THREAD(name_args) char name_args 00087 00088 /** 00089 * Initialize a protothread. 00090 * 00091 * Initializes a protothread. Initialization must be done prior to 00092 * starting to execute the protothread. 00093 * 00094 * \param pt A pointer to the protothread control structure. 00095 * 00096 * Example: 00097 * 00098 \code 00099 void main(void) { 00100 struct pt p; 00101 int event; 00102 00103 PT_INIT(&p); 00104 while(PT_SCHEDULE(consumer(&p, event))) { 00105 event = get_event(); 00106 } 00107 } 00108 \endcode 00109 * 00110 * \sa PT_SPAWN() 00111 * 00112 * \hideinitializer 00113 */ 00114 #define PT_INIT(pt) LC_INIT((pt)->lc) 00115 00116 /** 00117 * Declare the start of a protothread inside the C function 00118 * implementing the protothread. 00119 * 00120 * This macro is used to declare the starting point of a 00121 * protothread. It should be placed at the start of the function in 00122 * which the protothread runs. All C statements above the PT_BEGIN() 00123 * invokation will be executed each time the protothread is scheduled. 00124 * 00125 * \param pt A pointer to the protothread control structure. 00126 * 00127 * Example: 00128 * 00129 \code 00130 PT_THREAD(producer(struct pt *p, int event)) { 00131 PT_BEGIN(p); 00132 while(1) { 00133 PT_WAIT_UNTIL(p, event == CONSUMED || event == DROPPED); 00134 produce(); 00135 PT_WAIT_UNTIL(p, event == PRODUCED); 00136 } 00137 00138 PT_END(p); 00139 } 00140 \endcode 00141 * 00142 * \hideinitializer 00143 */ 00144 #define PT_BEGIN(pt) { PT_YIELDING(); LC_RESUME((pt)->lc) 00145 00146 /** 00147 * Block and wait until condition is true. 00148 * 00149 * This macro blocks the protothread until the specified condition is 00150 * true. 00151 * 00152 * \param pt A pointer to the protothread control structure. 00153 * \param condition The condition. 00154 * 00155 * Example: 00156 \code 00157 PT_THREAD(seconds(struct pt *p)) { 00158 PT_BEGIN(p); 00159 00160 PT_WAIT_UNTIL(p, time >= 2 * SECOND); 00161 printf("Two seconds have passed\n"); 00162 00163 PT_END(p); 00164 } 00165 \endcode 00166 * 00167 * \hideinitializer 00168 */ 00169 #define PT_WAIT_UNTIL(pt, condition) \ 00170 do { \ 00171 LC_SET((pt)->lc); \ 00172 if(!(condition)) { \ 00173 return PT_THREAD_WAITING; \ 00174 } \ 00175 } while(0) 00176 00177 /** 00178 * Block and wait while condition is true. 00179 * 00180 * This function blocks and waits while condition is true. See 00181 * PT_WAIT_UNTIL(). 00182 * 00183 * \param pt A pointer to the protothread control structure. 00184 * \param cond The condition. 00185 * 00186 * \hideinitializer 00187 */ 00188 #define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond)) 00189 00190 00191 /** 00192 * Block and wait until a child protothread completes. 00193 * 00194 * This macro schedules a child protothread. The current protothread 00195 * will block until the child protothread completes. 00196 * 00197 * \note The child protothread must be manually initialized with the 00198 * PT_INIT() function before this function is used. 00199 * 00200 * \param pt A pointer to the protothread control structure. 00201 * \param thread The child protothread with arguments 00202 * 00203 * Example: 00204 \code 00205 PT_THREAD(child(struct pt *p, int event)) { 00206 PT_BEGIN(p); 00207 00208 PT_WAIT_UNTIL(p, event == EVENT1); 00209 00210 PT_END(p); 00211 } 00212 00213 PT_THREAD(parent(struct pt *p, struct pt *child_pt, int event)) { 00214 PT_BEGIN(p); 00215 00216 PT_INIT(child_pt); 00217 00218 PT_WAIT_THREAD(p, child(child_pt, event)); 00219 00220 PT_END(p); 00221 } 00222 \endcode 00223 * 00224 * \sa PT_SPAWN() 00225 * 00226 * \hideinitializer 00227 */ 00228 #define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread)) 00229 00230 /** 00231 * Spawn a child protothread and wait until it exits. 00232 * 00233 * This macro spawns a child protothread and waits until it exits. The 00234 * macro can only be used within a protothread. 00235 * 00236 * Example: 00237 \code 00238 static struct pt parent_pt, child_pt; 00239 int should_spawn_flag; 00240 00241 PT_THREAD(child(struct pt *pt)) { 00242 PT_BEGIN(pt); 00243 00244 while(all_items_processed()) { 00245 process_item(); 00246 PT_WAIT_UNTIL(pt, item_processed()); 00247 } 00248 00249 PT_END(pt); 00250 } 00251 00252 PT_THREAD(parent(void)) { 00253 PT_BEGIN(&parent_pt); 00254 00255 if(should_spawn_flag) { 00256 PT_SPAWN(&parent_pt, &child_pt, child(&child_pt)); 00257 } 00258 00259 PT_END(&parent_pt); 00260 } 00261 \endcode 00262 * 00263 * 00264 * \param pt A pointer to the protothread control structure. 00265 * \param child A pointer to the child protothread's control structure. 00266 * \param thread The child protothread with arguments 00267 * 00268 * \hideinitializer 00269 */ 00270 #define PT_SPAWN(pt, child, thread) \ 00271 do { \ 00272 PT_INIT((child)); \ 00273 PT_WAIT_THREAD((pt), (thread)); \ 00274 } while(0) 00275 00276 /** 00277 * Restart the protothread. 00278 * 00279 * This macro will block and cause the running protothread to restart 00280 * its execution at the place of the PT_BEGIN() call. 00281 * 00282 * \param pt A pointer to the protothread control structure. 00283 * 00284 * \hideinitializer 00285 */ 00286 #define PT_RESTART(pt) \ 00287 do { \ 00288 PT_INIT(pt); \ 00289 return PT_THREAD_WAITING; \ 00290 } while(0) 00291 00292 /** 00293 * Exit the protothread. 00294 * 00295 * This macro causes the protothread to exit. If the protothread was 00296 * spawned by another protothread, the parent protothread will become 00297 * unblocked and can continue to run. 00298 * 00299 * \param pt A pointer to the protothread control structure. 00300 * 00301 * \hideinitializer 00302 */ 00303 #define PT_EXIT(pt) \ 00304 do { \ 00305 PT_INIT(pt); \ 00306 return PT_THREAD_EXITED; \ 00307 } while(0) 00308 00309 /** 00310 * Declare the end of a protothread. 00311 * 00312 * This macro is used for declaring that a protothread ends. It should 00313 * always be used together with a matching PT_BEGIN() macro. 00314 * 00315 * \param pt A pointer to the protothread control structure. 00316 * 00317 * \hideinitializer 00318 */ 00319 #define PT_END(pt) LC_END((pt)->lc); pt_yielded = 0; PT_EXIT(pt); } 00320 00321 00322 /** 00323 * Schedule a protothread. 00324 * 00325 * This function shedules a protothread. The return value of the 00326 * function is non-zero if the protothread is running or zero if the 00327 * protothread has exited. 00328 * 00329 * Example 00330 \code 00331 void main(void) { 00332 struct pt p; 00333 int event; 00334 00335 PT_INIT(&p); 00336 while(PT_SCHEDULE(consumer(&p, event))) { 00337 event = get_event(); 00338 } 00339 } 00340 \endcode 00341 * 00342 * \param f The call to the C function implementing the protothread to 00343 * be scheduled 00344 * 00345 * \hideinitializer 00346 */ 00347 #define PT_SCHEDULE(f) (f == PT_THREAD_WAITING) 00348 00349 /** 00350 * Declarare that a protothread can yield. 00351 * 00352 * If a protothread should be able to yield with the PT_YIELD() 00353 * statement, this flag must be placed first in the protothread's 00354 * function body. 00355 * 00356 * Example: 00357 \code 00358 static 00359 PT_THREAD(loop_thread(struct pt *pt)) 00360 { 00361 PT_YIELDING(); 00362 static int i; 00363 00364 PT_BEGIN(pt); 00365 00366 for(i = 0; i < 200; ++i) { 00367 handle_item(i); 00368 PT_YIELD(pt); 00369 } 00370 00371 PT_END(pt); 00372 } 00373 \endcode 00374 * 00375 * \hideinitializer 00376 */ 00377 #define PT_YIELDING() char pt_yielded = 1 00378 00379 /** 00380 * Yield from the current protothread. 00381 * 00382 * This function will yield the protothread, thereby allowing other 00383 * processing to take place in the system. 00384 * 00385 * \note The PT_YIELDING() flag must be placed first in the 00386 * protothread's body if the PT_YIELD() function should be used. 00387 * 00388 * Example 00389 \code 00390 static 00391 PT_THREAD(fade(struct pt *pt)) 00392 { 00393 PT_YIELDING(); 00394 static int delay; 00395 00396 PT_BEGIN(pt); 00397 00398 for(delay = 3980; delay > 20; delay -= 20) { 00399 leds_red(LEDS_ON); 00400 clock_delay(4000 - delay); 00401 leds_red(LEDS_OFF); 00402 clock_delay(delay); 00403 PT_YIELD(pt); 00404 } 00405 00406 PT_END(pt); 00407 } 00408 \endcode 00409 * \param pt A pointer to the protothread control structure. 00410 * 00411 * \hideinitializer 00412 */ 00413 #define PT_YIELD(pt) \ 00414 do { \ 00415 pt_yielded = 0; \ 00416 PT_WAIT_UNTIL(pt, pt_yielded); \ 00417 } while(0) 00418 00419 #define PT_YIELD_UNTIL(pt, cond) \ 00420 do { \ 00421 pt_yielded = 0; \ 00422 PT_WAIT_UNTIL(pt, pt_yielded && (cond)); \ 00423 } while(0) 00424 00425 #endif /* __PT_H__ */ 00426 00427 00428 /** @} */
1.3.6