blob: bbadd02ec726b837a5aebb0ae127f2be0f91adf4 [file] [log] [blame]
adamdunkelsa2f3c422004-09-12 20:24:53 +00001/*
adamdunkels70316a92005-02-22 22:41:04 +00002 * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
adamdunkelsa2f3c422004-09-12 20:24:53 +00003 * 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 Contiki operating system.
30 *
31 * Author: Adam Dunkels <adam@sics.se>
32 *
adamdunkels2caed812005-04-01 09:07:49 +000033 * $Id: pt.h,v 1.10 2005/04/01 09:07:49 adamdunkels Exp $
adamdunkelsa2f3c422004-09-12 20:24:53 +000034 */
35
adamdunkelsebd157c2004-08-14 21:52:09 +000036/**
adamdunkels70316a92005-02-22 22:41:04 +000037 * \addtogroup pt
38 * @{
adamdunkelsebd157c2004-08-14 21:52:09 +000039 */
40
41/**
42 * \file
43 * Protothreads implementation.
44 * \author
45 * Adam Dunkels <adam@sics.se>
46 *
47 */
48
49#ifndef __PT_H__
50#define __PT_H__
51
52#include "lc.h"
53
54struct pt {
55 lc_t lc;
56};
57
58#define PT_THREAD_WAITING 0
59#define PT_THREAD_EXITED 1
60
adamdunkels17062542004-08-15 22:04:43 +000061/**
62 * Declaration of a protothread.
63 *
adamdunkels70316a92005-02-22 22:41:04 +000064 * This macro is used to declare a protothread. All protothreads must
65 * be declared with this macro.
adamdunkels17062542004-08-15 22:04:43 +000066 *
67 * Example:
68 \code
69 PT_THREAD(consumer(struct pt *p, int event)) {
adamdunkelsf2fd9c12004-09-01 18:24:04 +000070 PT_BEGIN(p);
adamdunkels70316a92005-02-22 22:41:04 +000071 while(1) {
adamdunkelsa5f1e792005-04-01 08:13:45 +000072 PT_WAIT_UNTIL(p, event == AVAILABLE);
adamdunkels70316a92005-02-22 22:41:04 +000073 consume();
adamdunkelsa5f1e792005-04-01 08:13:45 +000074 PT_WAIT_UNTIL(p, event == CONSUMED);
adamdunkels70316a92005-02-22 22:41:04 +000075 acknowledge_consumed();
76 }
adamdunkelsf2fd9c12004-09-01 18:24:04 +000077 PT_END(p);
adamdunkels17062542004-08-15 22:04:43 +000078 }
79 \endcode
80 *
adamdunkels70316a92005-02-22 22:41:04 +000081 * \param name_args The name and arguments of the C function
82 * implementing the protothread.
83 *
adamdunkels17062542004-08-15 22:04:43 +000084 * \hideinitializer
85 */
86#define PT_THREAD(name_args) char name_args
adamdunkelsebd157c2004-08-14 21:52:09 +000087
adamdunkels17062542004-08-15 22:04:43 +000088/**
89 * Initialize a protothread.
90 *
91 * Initializes a protothread. Initialization must be done prior to
92 * starting to execute the protothread.
93 *
94 * \param pt A pointer to the protothread control structure.
95 *
96 * Example:
97 *
98 \code
adamdunkels70316a92005-02-22 22:41:04 +000099 void main(void) {
adamdunkels17062542004-08-15 22:04:43 +0000100 struct pt p;
101 int event;
102
103 PT_INIT(&p);
adamdunkels70316a92005-02-22 22:41:04 +0000104 while(PT_SCHEDULE(consumer(&p, event))) {
adamdunkels17062542004-08-15 22:04:43 +0000105 event = get_event();
106 }
107 }
108 \endcode
109 *
adamdunkelsa5f1e792005-04-01 08:13:45 +0000110 * \sa PT_SPAWN()
111 *
adamdunkels17062542004-08-15 22:04:43 +0000112 * \hideinitializer
113 */
adamdunkels1f7f6522005-03-14 13:53:37 +0000114#define PT_INIT(pt) LC_INIT((pt)->lc)
adamdunkels17062542004-08-15 22:04:43 +0000115
116/**
adamdunkels70316a92005-02-22 22:41:04 +0000117 * Declare the start of a protothread inside the C function
118 * implementing the protothread.
adamdunkels17062542004-08-15 22:04:43 +0000119 *
adamdunkels70316a92005-02-22 22:41:04 +0000120 * This macro is used to declare the starting point of a
121 * protothread. It should be placed at the start of the function in
122 * which the protothread runs. All C statements above the PT_BEGIN()
123 * invokation will be executed each time the protothread is scheduled.
adamdunkels17062542004-08-15 22:04:43 +0000124 *
125 * \param pt A pointer to the protothread control structure.
126 *
127 * Example:
128 *
129 \code
130 PT_THREAD(producer(struct pt *p, int event)) {
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000131 PT_BEGIN(p);
adamdunkels70316a92005-02-22 22:41:04 +0000132 while(1) {
adamdunkelsa5f1e792005-04-01 08:13:45 +0000133 PT_WAIT_UNTIL(p, event == CONSUMED || event == DROPPED);
adamdunkels70316a92005-02-22 22:41:04 +0000134 produce();
adamdunkelsa5f1e792005-04-01 08:13:45 +0000135 PT_WAIT_UNTIL(p, event == PRODUCED);
adamdunkels70316a92005-02-22 22:41:04 +0000136 }
adamdunkels17062542004-08-15 22:04:43 +0000137
adamdunkels70316a92005-02-22 22:41:04 +0000138 PT_END(p);
adamdunkels17062542004-08-15 22:04:43 +0000139 }
140 \endcode
141 *
142 * \hideinitializer
143 */
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000144#define PT_BEGIN(pt) LC_RESUME((pt)->lc)
adamdunkelsebd157c2004-08-14 21:52:09 +0000145
adamdunkels17062542004-08-15 22:04:43 +0000146/**
147 * Block and wait until condition is true.
148 *
149 * This macro blocks the protothread until the specified condition is
150 * true.
151 *
152 * \param pt A pointer to the protothread control structure.
153 * \param condition The condition.
154 *
155 * Example:
156 \code
157 PT_THREAD(seconds(struct pt *p)) {
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000158 PT_BEGIN(p);
adamdunkels17062542004-08-15 22:04:43 +0000159
160 PT_WAIT_UNTIL(p, time >= 2 * SECOND);
161 printf("Two seconds have passed\n");
162
adamdunkels70316a92005-02-22 22:41:04 +0000163 PT_END(p);
adamdunkels17062542004-08-15 22:04:43 +0000164 }
165 \endcode
166 *
167 * \hideinitializer
168 */
169#define PT_WAIT_UNTIL(pt, condition) \
adamdunkelsebd157c2004-08-14 21:52:09 +0000170 do { \
171 LC_SET((pt)->lc); \
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000172 if(!(condition)) { \
adamdunkelsebd157c2004-08-14 21:52:09 +0000173 return PT_THREAD_WAITING; \
174 } \
175 } while(0)
176
adamdunkels17062542004-08-15 22:04:43 +0000177/**
178 * Block and wait while condition is true.
179 *
180 * This function blocks and waits while condition is true. See
181 * PT_WAIT_UNTIL().
182 *
183 * \param pt A pointer to the protothread control structure.
184 * \param cond The condition.
185 *
186 * \hideinitializer
187 */
adamdunkels1f7f6522005-03-14 13:53:37 +0000188#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond))
adamdunkelsebd157c2004-08-14 21:52:09 +0000189
adamdunkels17062542004-08-15 22:04:43 +0000190
191/**
192 * Block and wait until a child protothread completes.
193 *
194 * This macro schedules a child protothread. The current protothread
adamdunkelsc7fd77d2004-08-17 20:35:46 +0000195 * will block until the child protothread completes.
196 *
197 * \note The child protothread must be manually initialized with the
198 * PT_INIT() function before this function is used.
adamdunkels17062542004-08-15 22:04:43 +0000199 *
200 * \param pt A pointer to the protothread control structure.
adamdunkelsc7fd77d2004-08-17 20:35:46 +0000201 * \param thread The child protothread with arguments
adamdunkels17062542004-08-15 22:04:43 +0000202 *
203 * Example:
204 \code
205 PT_THREAD(child(struct pt *p, int event)) {
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000206 PT_BEGIN(p);
adamdunkels17062542004-08-15 22:04:43 +0000207
adamdunkelsa5f1e792005-04-01 08:13:45 +0000208 PT_WAIT_UNTIL(p, event == EVENT1);
adamdunkels17062542004-08-15 22:04:43 +0000209
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000210 PT_END(p);
adamdunkels17062542004-08-15 22:04:43 +0000211 }
212
213 PT_THREAD(parent(struct pt *p, struct pt *child_pt, int event)) {
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000214 PT_BEGIN(p);
adamdunkels17062542004-08-15 22:04:43 +0000215
216 PT_INIT(child_pt);
217
218 PT_WAIT_THREAD(p, child(child_pt, event));
219
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000220 PT_END(p);
adamdunkels17062542004-08-15 22:04:43 +0000221 }
222 \endcode
223 *
adamdunkelsa5f1e792005-04-01 08:13:45 +0000224 * \sa PT_SPAWN()
225 *
adamdunkels17062542004-08-15 22:04:43 +0000226 * \hideinitializer
227 */
adamdunkels1f7f6522005-03-14 13:53:37 +0000228#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))
adamdunkelsebd157c2004-08-14 21:52:09 +0000229
adamdunkels17062542004-08-15 22:04:43 +0000230/**
adamdunkels73e70f42004-08-20 21:26:02 +0000231 * Spawn a child protothread and wait until it exits.
232 *
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000233 * This macro spawns a child protothread and waits until it exits. The
234 * macro can only be used within a protothread.
adamdunkels73e70f42004-08-20 21:26:02 +0000235 *
adamdunkels2caed812005-04-01 09:07:49 +0000236 * Example:
237 \code
238 static struct pt parent_pt, child_pt;
239 int should_spawn_flag;
240
241 PT_THREAD(child(struct pt *pt)) {
242 PT_BEGIN(pt);
243
244 while(all_items_processed()) {
245 process_item();
246 PT_WAIT_UNTIL(pt, item_processed());
247 }
248
249 PT_END(pt);
250 }
251
252 PT_THREAD(parent(void)) {
253 PT_BEGIN(&parent_pt);
254
255 if(should_spawn_flag) {
256 PT_SPAWN(&parent_pt, &child_pt, child(&child_pt));
257 }
258
259 PT_END(&parent_pt);
260 }
261 \endcode
262 *
263 *
adamdunkels73e70f42004-08-20 21:26:02 +0000264 * \param pt A pointer to the protothread control structure.
adamdunkels1f7f6522005-03-14 13:53:37 +0000265 * \param child A pointer to the child protothread's control structure.
adamdunkels73e70f42004-08-20 21:26:02 +0000266 * \param thread The child protothread with arguments
267 *
268 * \hideinitializer
269 */
adamdunkels1f7f6522005-03-14 13:53:37 +0000270#define PT_SPAWN(pt, child, thread) \
adamdunkels73e70f42004-08-20 21:26:02 +0000271 do { \
adamdunkels1f7f6522005-03-14 13:53:37 +0000272 PT_INIT((child)); \
adamdunkels73e70f42004-08-20 21:26:02 +0000273 PT_WAIT_THREAD((pt), (thread)); \
274 } while(0)
275
276/**
adamdunkels17062542004-08-15 22:04:43 +0000277 * Restart the protothread.
278 *
adamdunkels70316a92005-02-22 22:41:04 +0000279 * This macro will block and cause the running protothread to restart
280 * its execution at the place of the PT_BEGIN() call.
adamdunkels17062542004-08-15 22:04:43 +0000281 *
282 * \param pt A pointer to the protothread control structure.
283 *
284 * \hideinitializer
285 */
adamdunkelsebd157c2004-08-14 21:52:09 +0000286#define PT_RESTART(pt) \
287 do { \
adamdunkels17062542004-08-15 22:04:43 +0000288 PT_INIT(pt); \
adamdunkelsebd157c2004-08-14 21:52:09 +0000289 return PT_THREAD_WAITING; \
290 } while(0)
291
adamdunkels17062542004-08-15 22:04:43 +0000292/**
293 * Exit the protothread.
294 *
295 * This macro causes the protothread to exit. If the protothread was
296 * spawned by another protothread, the parent protothread will become
297 * unblocked and can continue to run.
298 *
299 * \param pt A pointer to the protothread control structure.
300 *
301 * \hideinitializer
302 */
adamdunkelsebd157c2004-08-14 21:52:09 +0000303#define PT_EXIT(pt) \
304 do { \
305 PT_INIT(pt); \
306 return PT_THREAD_EXITED; \
307 } while(0)
308
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000309/**
310 * Declare the end of a protothread.
311 *
312 * This macro is used for declaring that a protothread ends. It should
313 * always be used together with a matching PT_BEGIN() macro.
314 *
315 * \param pt A pointer to the protothread control structure.
316 *
317 * \hideinitializer
318 */
319#define PT_END(pt) LC_END((pt)->lc); PT_EXIT(pt)
320
adamdunkels70316a92005-02-22 22:41:04 +0000321
322/**
323 * Schedule a protothread.
324 *
325 * This function shedules a protothread. The return value of the
326 * function is non-zero if the protothread is running or zero if the
327 * protothread has exited.
328 *
329 * Example
330 \code
331 void main(void) {
332 struct pt p;
333 int event;
334
335 PT_INIT(&p);
336 while(PT_SCHEDULE(consumer(&p, event))) {
337 event = get_event();
338 }
339 }
340 \endcode
341 *
342 * \param f The call to the C function implementing the protothread to
343 * be scheduled
344 *
345 * \hideinitializer
346 */
347#define PT_SCHEDULE(f) (f == PT_THREAD_WAITING)
adamdunkels17062542004-08-15 22:04:43 +0000348
adamdunkels1f7f6522005-03-14 13:53:37 +0000349/**
350 * Declarare that a protothread can yield.
351 *
352 * If a protothread should be able to yield with the PT_YIELD()
353 * statement, this flag must be placed first in the protothread's
354 * function body.
355 *
356 * Example:
357 \code
358 static
359 PT_THREAD(loop_thread(struct pt *pt))
360 {
361 PT_YIELDING();
362 static int i;
363
364 PT_BEGIN(pt);
365
366 for(i = 0; i < 200; ++i) {
367 handle_item(i);
368 PT_YIELD(pt);
369 }
370
371 PT_END(pt);
372 }
373 \endcode
374 *
375 * \hideinitializer
376 */
377#define PT_YIELDING() char pt_yielded = 1
378
379/**
380 * Yield from the current protothread.
381 *
382 * This function will yield the protothread, thereby allowing other
383 * processing to take place in the system.
384 *
385 * \note The PT_YIELDING() flag must be placed first in the
386 * protothread's body if the PT_YIELD() function should be used.
387 *
388 * Example
389 \code
390static
391PT_THREAD(fade(struct pt *pt))
392{
393 PT_YIELDING();
394 static int delay;
395
396 PT_BEGIN(pt);
397
398 for(delay = 3980; delay > 20; delay -= 20) {
399 leds_red(LEDS_ON);
400 clock_delay(4000 - delay);
401 leds_red(LEDS_OFF);
402 clock_delay(delay);
403 PT_YIELD(pt);
404 }
405
406 PT_END(pt);
407}
408 \endcode
409 * \param pt A pointer to the protothread control structure.
410 *
411 * \hideinitializer
412 */
413#define PT_YIELD(pt) \
414 do { \
415 pt_yielded = 0; \
416 PT_WAIT_UNTIL(pt, pt_yielded); \
417 } while(0)
418
adamdunkelsebd157c2004-08-14 21:52:09 +0000419#endif /* __PT_H__ */
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000420
adamdunkelsf2fd9c12004-09-01 18:24:04 +0000421
adamdunkels17062542004-08-15 22:04:43 +0000422/** @} */