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 protothreads library. 00030 * 00031 * Author: Adam Dunkels <adam@sics.se> 00032 * 00033 * $Id: pt.h,v 1.2 2005/02/24 10:36:59 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(event == AVAILABLE); 00073 consume(); 00074 PT_WAIT_UNTIL(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 * \hideinitializer 00111 */ 00112 #define PT_INIT(pt) \ 00113 LC_INIT((pt)->lc) 00114 00115 /** 00116 * Declare the start of a protothread inside the C function 00117 * implementing the protothread. 00118 * 00119 * This macro is used to declare the starting point of a 00120 * protothread. It should be placed at the start of the function in 00121 * which the protothread runs. All C statements above the PT_BEGIN() 00122 * invokation will be executed each time the protothread is scheduled. 00123 * 00124 * \param pt A pointer to the protothread control structure. 00125 * 00126 * Example: 00127 * 00128 \code 00129 PT_THREAD(producer(struct pt *p, int event)) { 00130 PT_BEGIN(p); 00131 while(1) { 00132 PT_WAIT_UNTIL(event == CONSUMED || event == DROPPED); 00133 produce(); 00134 PT_WAIT_UNTIL(event == PRODUCED); 00135 } 00136 00137 PT_END(p); 00138 } 00139 \endcode 00140 * 00141 * \hideinitializer 00142 */ 00143 #define PT_BEGIN(pt) LC_RESUME((pt)->lc) 00144 /*\ 00145 do { \ 00146 if((pt)->lc != LC_NULL) { \ 00147 LC_RESUME((pt)->lc); \ 00148 } \ 00149 } while(0)*/ 00150 00151 /** 00152 * Block and wait until condition is true. 00153 * 00154 * This macro blocks the protothread until the specified condition is 00155 * true. 00156 * 00157 * \param pt A pointer to the protothread control structure. 00158 * \param condition The condition. 00159 * 00160 * Example: 00161 \code 00162 PT_THREAD(seconds(struct pt *p)) { 00163 PT_BEGIN(p); 00164 00165 PT_WAIT_UNTIL(p, time >= 2 * SECOND); 00166 printf("Two seconds have passed\n"); 00167 00168 PT_END(p); 00169 } 00170 \endcode 00171 * 00172 * \hideinitializer 00173 */ 00174 #define PT_WAIT_UNTIL(pt, condition) \ 00175 do { \ 00176 LC_SET((pt)->lc); \ 00177 if(!(condition)) { \ 00178 return PT_THREAD_WAITING; \ 00179 } \ 00180 } while(0) 00181 00182 /** 00183 * Block and wait while condition is true. 00184 * 00185 * This function blocks and waits while condition is true. See 00186 * PT_WAIT_UNTIL(). 00187 * 00188 * \param pt A pointer to the protothread control structure. 00189 * \param cond The condition. 00190 * 00191 * \hideinitializer 00192 */ 00193 #define PT_WAIT_WHILE(pt, cond) \ 00194 PT_WAIT_UNTIL((pt), !(cond)) 00195 00196 00197 /** 00198 * Block and wait until a child protothread completes. 00199 * 00200 * This macro schedules a child protothread. The current protothread 00201 * will block until the child protothread completes. 00202 * 00203 * \note The child protothread must be manually initialized with the 00204 * PT_INIT() function before this function is used. 00205 * 00206 * \param pt A pointer to the protothread control structure. 00207 * \param thread The child protothread with arguments 00208 * 00209 * Example: 00210 \code 00211 PT_THREAD(child(struct pt *p, int event)) { 00212 PT_BEGIN(p); 00213 00214 PT_WAIT_UNTIL(event == EVENT1); 00215 00216 PT_END(p); 00217 } 00218 00219 PT_THREAD(parent(struct pt *p, struct pt *child_pt, int event)) { 00220 PT_BEGIN(p); 00221 00222 PT_INIT(child_pt); 00223 00224 PT_WAIT_THREAD(p, child(child_pt, event)); 00225 00226 PT_END(p); 00227 } 00228 \endcode 00229 * 00230 * \hideinitializer 00231 */ 00232 #define PT_WAIT_THREAD(pt, thread) \ 00233 PT_WAIT_UNTIL((pt), (thread)) 00234 00235 /** 00236 * Spawn a child protothread and wait until it exits. 00237 * 00238 * This macro spawns a child protothread and waits until it exits. The 00239 * macro can only be used within a protothread. 00240 * 00241 * \param pt A pointer to the protothread control structure. 00242 * \param thread The child protothread with arguments 00243 * 00244 * \hideinitializer 00245 */ 00246 #define PT_SPAWN(pt, thread) \ 00247 do { \ 00248 PT_INIT((pt)); \ 00249 PT_WAIT_THREAD((pt), (thread)); \ 00250 } while(0) 00251 00252 /** 00253 * Restart the protothread. 00254 * 00255 * This macro will block and cause the running protothread to restart 00256 * its execution at the place of the PT_BEGIN() call. 00257 * 00258 * \param pt A pointer to the protothread control structure. 00259 * 00260 * \hideinitializer 00261 */ 00262 #define PT_RESTART(pt) \ 00263 do { \ 00264 PT_INIT(pt); \ 00265 return PT_THREAD_WAITING; \ 00266 } while(0) 00267 00268 /** 00269 * Exit the protothread. 00270 * 00271 * This macro causes the protothread to exit. If the protothread was 00272 * spawned by another protothread, the parent protothread will become 00273 * unblocked and can continue to run. 00274 * 00275 * \param pt A pointer to the protothread control structure. 00276 * 00277 * \hideinitializer 00278 */ 00279 #define PT_EXIT(pt) \ 00280 do { \ 00281 PT_INIT(pt); \ 00282 return PT_THREAD_EXITED; \ 00283 } while(0) 00284 00285 /** 00286 * Declare the end of a protothread. 00287 * 00288 * This macro is used for declaring that a protothread ends. It should 00289 * always be used together with a matching PT_BEGIN() macro. 00290 * 00291 * \param pt A pointer to the protothread control structure. 00292 * 00293 * \hideinitializer 00294 */ 00295 #define PT_END(pt) LC_END((pt)->lc); PT_EXIT(pt) 00296 00297 00298 /** 00299 * Schedule a protothread. 00300 * 00301 * This function shedules a protothread. The return value of the 00302 * function is non-zero if the protothread is running or zero if the 00303 * protothread has exited. 00304 * 00305 * Example 00306 \code 00307 void main(void) { 00308 struct pt p; 00309 int event; 00310 00311 PT_INIT(&p); 00312 while(PT_SCHEDULE(consumer(&p, event))) { 00313 event = get_event(); 00314 } 00315 } 00316 \endcode 00317 * 00318 * \param f The call to the C function implementing the protothread to 00319 * be scheduled 00320 * 00321 * \hideinitializer 00322 */ 00323 #define PT_SCHEDULE(f) (f == PT_THREAD_WAITING) 00324 00325 #endif /* __PT_H__ */ 00326 00327 00328 /** @} */