Contiki 2.6
|
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 */ 00034 00035 /** 00036 * \addtogroup pt 00037 * @{ 00038 */ 00039 00040 /** 00041 * \file 00042 * Protothreads implementation. 00043 * \author 00044 * Adam Dunkels <adam@sics.se> 00045 * 00046 */ 00047 00048 #ifndef __PT_H__ 00049 #define __PT_H__ 00050 00051 #include "sys/lc.h" 00052 00053 struct pt { 00054 lc_t lc; 00055 }; 00056 00057 #define PT_WAITING 0 00058 #define PT_YIELDED 1 00059 #define PT_EXITED 2 00060 #define PT_ENDED 3 00061 00062 /** 00063 * \name Initialization 00064 * @{ 00065 */ 00066 00067 /** 00068 * Initialize a protothread. 00069 * 00070 * Initializes a protothread. Initialization must be done prior to 00071 * starting to execute the protothread. 00072 * 00073 * \param pt A pointer to the protothread control structure. 00074 * 00075 * \sa PT_SPAWN() 00076 * 00077 * \hideinitializer 00078 */ 00079 #define PT_INIT(pt) LC_INIT((pt)->lc) 00080 00081 /** @} */ 00082 00083 /** 00084 * \name Declaration and definition 00085 * @{ 00086 */ 00087 00088 /** 00089 * Declaration of a protothread. 00090 * 00091 * This macro is used to declare a protothread. All protothreads must 00092 * be declared with this macro. 00093 * 00094 * \param name_args The name and arguments of the C function 00095 * implementing the protothread. 00096 * 00097 * \hideinitializer 00098 */ 00099 #define PT_THREAD(name_args) char name_args 00100 00101 /** 00102 * Declare the start of a protothread inside the C function 00103 * implementing the protothread. 00104 * 00105 * This macro is used to declare the starting point of a 00106 * protothread. It should be placed at the start of the function in 00107 * which the protothread runs. All C statements above the PT_BEGIN() 00108 * invokation will be executed each time the protothread is scheduled. 00109 * 00110 * \param pt A pointer to the protothread control structure. 00111 * 00112 * \hideinitializer 00113 */ 00114 #define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; if (PT_YIELD_FLAG) {;} LC_RESUME((pt)->lc) 00115 00116 /** 00117 * Declare the end of a protothread. 00118 * 00119 * This macro is used for declaring that a protothread ends. It must 00120 * always be used together with a matching PT_BEGIN() macro. 00121 * 00122 * \param pt A pointer to the protothread control structure. 00123 * 00124 * \hideinitializer 00125 */ 00126 #define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \ 00127 PT_INIT(pt); return PT_ENDED; } 00128 00129 /** @} */ 00130 00131 /** 00132 * \name Blocked wait 00133 * @{ 00134 */ 00135 00136 /** 00137 * Block and wait until condition is true. 00138 * 00139 * This macro blocks the protothread until the specified condition is 00140 * true. 00141 * 00142 * \param pt A pointer to the protothread control structure. 00143 * \param condition The condition. 00144 * 00145 * \hideinitializer 00146 */ 00147 #define PT_WAIT_UNTIL(pt, condition) \ 00148 do { \ 00149 LC_SET((pt)->lc); \ 00150 if(!(condition)) { \ 00151 return PT_WAITING; \ 00152 } \ 00153 } while(0) 00154 00155 /** 00156 * Block and wait while condition is true. 00157 * 00158 * This function blocks and waits while condition is true. See 00159 * PT_WAIT_UNTIL(). 00160 * 00161 * \param pt A pointer to the protothread control structure. 00162 * \param cond The condition. 00163 * 00164 * \hideinitializer 00165 */ 00166 #define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond)) 00167 00168 /** @} */ 00169 00170 /** 00171 * \name Hierarchical protothreads 00172 * @{ 00173 */ 00174 00175 /** 00176 * Block and wait until a child protothread completes. 00177 * 00178 * This macro schedules a child protothread. The current protothread 00179 * will block until the child protothread completes. 00180 * 00181 * \note The child protothread must be manually initialized with the 00182 * PT_INIT() function before this function is used. 00183 * 00184 * \param pt A pointer to the protothread control structure. 00185 * \param thread The child protothread with arguments 00186 * 00187 * \sa PT_SPAWN() 00188 * 00189 * \hideinitializer 00190 */ 00191 #define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread)) 00192 00193 /** 00194 * Spawn a child protothread and wait until it exits. 00195 * 00196 * This macro spawns a child protothread and waits until it exits. The 00197 * macro can only be used within a protothread. 00198 * 00199 * \param pt A pointer to the protothread control structure. 00200 * \param child A pointer to the child protothread's control structure. 00201 * \param thread The child protothread with arguments 00202 * 00203 * \hideinitializer 00204 */ 00205 #define PT_SPAWN(pt, child, thread) \ 00206 do { \ 00207 PT_INIT((child)); \ 00208 PT_WAIT_THREAD((pt), (thread)); \ 00209 } while(0) 00210 00211 /** @} */ 00212 00213 /** 00214 * \name Exiting and restarting 00215 * @{ 00216 */ 00217 00218 /** 00219 * Restart the protothread. 00220 * 00221 * This macro will block and cause the running protothread to restart 00222 * its execution at the place of the PT_BEGIN() call. 00223 * 00224 * \param pt A pointer to the protothread control structure. 00225 * 00226 * \hideinitializer 00227 */ 00228 #define PT_RESTART(pt) \ 00229 do { \ 00230 PT_INIT(pt); \ 00231 return PT_WAITING; \ 00232 } while(0) 00233 00234 /** 00235 * Exit the protothread. 00236 * 00237 * This macro causes the protothread to exit. If the protothread was 00238 * spawned by another protothread, the parent protothread will become 00239 * unblocked and can continue to run. 00240 * 00241 * \param pt A pointer to the protothread control structure. 00242 * 00243 * \hideinitializer 00244 */ 00245 #define PT_EXIT(pt) \ 00246 do { \ 00247 PT_INIT(pt); \ 00248 return PT_EXITED; \ 00249 } while(0) 00250 00251 /** @} */ 00252 00253 /** 00254 * \name Calling a protothread 00255 * @{ 00256 */ 00257 00258 /** 00259 * Schedule a protothread. 00260 * 00261 * This function schedules a protothread. The return value of the 00262 * function is non-zero if the protothread is running or zero if the 00263 * protothread has exited. 00264 * 00265 * \param f The call to the C function implementing the protothread to 00266 * be scheduled 00267 * 00268 * \hideinitializer 00269 */ 00270 #define PT_SCHEDULE(f) ((f) < PT_EXITED) 00271 00272 /** @} */ 00273 00274 /** 00275 * \name Yielding from a protothread 00276 * @{ 00277 */ 00278 00279 /** 00280 * Yield from the current protothread. 00281 * 00282 * This function will yield the protothread, thereby allowing other 00283 * processing to take place in the system. 00284 * 00285 * \param pt A pointer to the protothread control structure. 00286 * 00287 * \hideinitializer 00288 */ 00289 #define PT_YIELD(pt) \ 00290 do { \ 00291 PT_YIELD_FLAG = 0; \ 00292 LC_SET((pt)->lc); \ 00293 if(PT_YIELD_FLAG == 0) { \ 00294 return PT_YIELDED; \ 00295 } \ 00296 } while(0) 00297 00298 /** 00299 * \brief Yield from the protothread until a condition occurs. 00300 * \param pt A pointer to the protothread control structure. 00301 * \param cond The condition. 00302 * 00303 * This function will yield the protothread, until the 00304 * specified condition evaluates to true. 00305 * 00306 * 00307 * \hideinitializer 00308 */ 00309 #define PT_YIELD_UNTIL(pt, cond) \ 00310 do { \ 00311 PT_YIELD_FLAG = 0; \ 00312 LC_SET((pt)->lc); \ 00313 if((PT_YIELD_FLAG == 0) || !(cond)) { \ 00314 return PT_YIELDED; \ 00315 } \ 00316 } while(0) 00317 00318 /** @} */ 00319 00320 #endif /* __PT_H__ */ 00321 00322 /** @} */