From 784568999263d5e20d303e16a350a9bc48c0d275 Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Wed, 27 May 2026 22:19:55 +0200 Subject: [PATCH] swapped protothreads library with custom coroutines library --- fw/coroutine.h | 224 +++++++++++++++++++++++++++++ fw/pt/lc-addrlabels.h | 85 ----------- fw/pt/lc-switch.h | 76 ---------- fw/pt/lc.h | 132 ----------------- fw/pt/pt-sem.h | 228 ----------------------------- fw/pt/pt.h | 323 ------------------------------------------ 6 files changed, 224 insertions(+), 844 deletions(-) create mode 100644 fw/coroutine.h delete mode 100644 fw/pt/lc-addrlabels.h delete mode 100644 fw/pt/lc-switch.h delete mode 100644 fw/pt/lc.h delete mode 100644 fw/pt/pt-sem.h delete mode 100644 fw/pt/pt.h diff --git a/fw/coroutine.h b/fw/coroutine.h new file mode 100644 index 0000000..9e6af9e --- /dev/null +++ b/fw/coroutine.h @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2026, Alessandro Mauri . + * All rights reserved. + * + * This file is a heavily modified, single-header derivative of the + * protothreads library. + * + * ============================================================================= + * Original Protothreads License: + * ============================================================================= + * Copyright (c) 2004-2005, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Adam Dunkels + */ + + +#ifndef _COROUTINE_H +#define _COROUTINE_H + +/* This is an implementation of stackless coroutines that uses the labels as + * values [1] feature of GNU C, similar to protothreads [2] with the lc-addrlabels.h + * include, the only difference being better ergonomics and minimal type checking. + * + * Since coroutines implemented this way need to return to wait for a condition + * stack-local variables are NOT preserved between wait()s, as such these functions + * have to be considered stackless. Any state that has to be preserved between + * waits have to be declared static or have to be preserved outside the routine. + * + * This library's intended use is in microcontrollers and memory-constrained + * systems where having a full rtos and/or having stackful coroutines is either + * too heavy or overkill. Stackless coroutines implemented this way are an + * alternative way of expressing state machines. Since coroutines have to be + * repeatedly called to be "scheduled", the code maintains a main loop, but state + * changes can be expressed with waits on conditions, timers, semaphores and other + * more expressive constructs. + * + * A simple example program is: + * + * #include "coroutine.h" + * + * // Updates the timer when called, returns true when it expires + * static int timer_expired(struct timer *t); + * // Sets a timer in milliseconds + * static void timer_set(struct timer *t, int interval); + * + * // First coroutine, waits for 1s and prints something + * coroutine coro_1(coro_state_t *s) + * { + * static struct timer t; + * coro_begin(s); + * for (;;) { + * timer_set(&t, 1000); + * coro_wait_until(s, timer_expired(&t)); + * printf("coroutine 1\n"); + * } + * coro_end(); + * } + * + * // Second coroutine, waits for 500ms and prints something + * coroutine coro_2(coro_state_t *s) + * { + * static struct timer t; + * coro_begin(s); + * for (;;) { + * timer_set(&t, 500); + * coro_wait_until(s, timer_expired(&t)); + * printf("coroutine 2\n"); + * } + * coro_end(); + * } + * + * int main(void) + * { + * coro_state_t s1, s2; + * coro_init(&s1); + * coro_init(&s2); + * + * // Main loop, calls each coroutine periodically + * for (;;) { + * coro_1(&s1); + * coro_2(&s2); + * usleep(100); + * } + * } + * + * [1]: https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Labels-as-Values.html + * [2]: https://dunkels.com/adam/pt/index.html + */ + + +// Useful macros +#define CORO_CONCAT2(s1, s2) s1##s2 +#define CORO_CONCAT(s1, s2) CORO_CONCAT2(s1, s2) +#define CORO_CHECK_TYPE(var,type) { typedef void (*type_t)(type); type_t tmp = (type_t)0; if(0) tmp(var); } + + +// Return value of a coroutine, a coroutine should be scheduled (called) until +// it's return value becomes DONE +typedef enum { + CORO_INIT = 0, + CORO_CONT = CORO_INIT, + CORO_DONE = 1, + CORO_YIELDED = 2, + CORO_WAITING = 3, +} coroutine; + +// Local continuation of the coroutine, where it left off +typedef void* coro_state_t; + + +/* -------------------------- COROUTINE MANAGEMENT -------------------------- */ + +// Initialize the coroutine state +#define coro_init(s) CORO_CHECK_TYPE(s, coro_state_t*) \ + do { *s = NULL; } while (0) + +// Jump to the previous state where the coroutine left off, __yield flag indicates +// wether the coroutine should yield this cycle +#define coro_begin(s) CORO_CHECK_TYPE(s, coro_state_t*) \ + unsigned char __yield = 0; \ + do { if(*s != NULL) goto *(*s); } while (0) + +#define coro_end() + +// Set a jump with a gcc label as value feature, this is a GNU C extension +#define CORO_SET_JUMP(s) CORO_CHECK_TYPE(s, coro_state_t*) \ + do { \ + CORO_CONCAT(LC_LABEL, __LINE__): \ + *s = &&CORO_CONCAT(LC_LABEL, __LINE__); \ + } while (0) + +// Yield from a coroutine +#define coro_yield(s) CORO_CHECK_TYPE(s, coro_state_t*) \ + do { \ + __yield = 1; \ + CORO_SET_JUMP(s); \ + if (__yield == 1) return CORO_YIELDED; \ + } while (0) + +// Wait until a condition is met (becomes true) +#define coro_wait_until(s, cond) CORO_CHECK_TYPE(s, coro_state_t*) \ + do { \ + CORO_SET_JUMP(s); \ + if (!(cond)) return CORO_WAITING; \ + } while (0) + +// Shorthand for wait_until +#define coro_wait(s, cond) coro_wait_until(s, cond) + +// Wait while a condition remains true +#define coro_wait_while(s, cond) coro_wait_until(s, !(cond)) + +// Exit from the coroutine, resets the state +#define coro_exit(s) CORO_CHECK_TYPE(s, coro_state_t*) \ + do { \ + coro_init(s); \ + return CORO_DONE; \ + } while (0) + +// Restart a coroutine, when called it will not resume from where it left off, +// instead it will start from the beginning, the only difference with exit is +// the return value. To determine wether a coroutine has exited or restarted +// is to check it's return value +#define coro_restart(s) CORO_CHECK_TYPE(s, coro_state_t*) \ + do { \ + coro_init(s); \ + return CORO_INIT; \ + } while(0) + + +/* ------------------------- SEMAPHORE IMPLEMENTATION ----------------------- */ +// Implements a basic semaphore type with the classic wait and signal operations +// semaphores are not bound checked + +typedef int coro_semaphore_t; + +// Initializes a semaphore with a starting value of "count" +#define coro_sem_init(sem, count) CORO_CHECK_TYPE(sem, coro_semaphore_t*) \ + do { \ + *sem = (int)count; \ + } while (0) + +// Wait until a semaphore has a value other than zero +#define coro_sem_wait(state, sem) \ + CORO_CHECK_TYPE(state, coro_state_t*) \ + CORO_CHECK_TYPE(sem, coro_semaphore_t*) \ + do { \ + coro_wait_until(state, *(sem) > 0); \ + --(*sem); \ + } while (0) + +// Signal a semaphore +#define coro_sem_signal(state, sem) \ + CORO_CHECK_TYPE(state, coro_state_t*) \ + CORO_CHECK_TYPE(sem, coro_semaphore_t*) \ + ++(*sem) + + +#endif diff --git a/fw/pt/lc-addrlabels.h b/fw/pt/lc-addrlabels.h deleted file mode 100644 index 3e6474e..0000000 --- a/fw/pt/lc-addrlabels.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2004-2005, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * This file is part of the Contiki operating system. - * - * Author: Adam Dunkels - * - * $Id: lc-addrlabels.h,v 1.4 2006/06/03 11:29:43 adam Exp $ - */ - -/** - * \addtogroup lc - * @{ - */ - -/** - * \file - * Implementation of local continuations based on the "Labels as - * values" feature of gcc - * \author - * Adam Dunkels - * - * This implementation of local continuations is based on a special - * feature of the GCC C compiler called "labels as values". This - * feature allows assigning pointers with the address of the code - * corresponding to a particular C label. - * - * For more information, see the GCC documentation: - * http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html - * - */ - -#ifndef __LC_ADDRLABELS_H__ -#define __LC_ADDRLABELS_H__ - -/** \hideinitializer */ -typedef void * lc_t; - -#define LC_INIT(s) s = NULL - -#define LC_RESUME(s) \ - do { \ - if(s != NULL) { \ - goto *s; \ - } \ - } while(0) - -#define LC_CONCAT2(s1, s2) s1##s2 -#define LC_CONCAT(s1, s2) LC_CONCAT2(s1, s2) - -#define LC_SET(s) \ - do { \ - LC_CONCAT(LC_LABEL, __LINE__): \ - (s) = &&LC_CONCAT(LC_LABEL, __LINE__); \ - } while(0) - -#define LC_END(s) - -#endif /* __LC_ADDRLABELS_H__ */ -/** @} */ diff --git a/fw/pt/lc-switch.h b/fw/pt/lc-switch.h deleted file mode 100644 index dbdde01..0000000 --- a/fw/pt/lc-switch.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2004-2005, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * This file is part of the Contiki operating system. - * - * Author: Adam Dunkels - * - * $Id: lc-switch.h,v 1.4 2006/06/03 11:29:43 adam Exp $ - */ - -/** - * \addtogroup lc - * @{ - */ - -/** - * \file - * Implementation of local continuations based on switch() statment - * \author Adam Dunkels - * - * This implementation of local continuations uses the C switch() - * statement to resume execution of a function somewhere inside the - * function's body. The implementation is based on the fact that - * switch() statements are able to jump directly into the bodies of - * control structures such as if() or while() statmenets. - * - * This implementation borrows heavily from Simon Tatham's coroutines - * implementation in C: - * http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html - */ - -#ifndef __LC_SWITCH_H__ -#define __LC_SWITCH_H__ - -/* WARNING! lc implementation using switch() does not work if an - LC_SET() is done within another switch() statement! */ - -/** \hideinitializer */ -typedef unsigned short lc_t; - -#define LC_INIT(s) s = 0; - -#define LC_RESUME(s) switch(s) { case 0: - -#define LC_SET(s) s = __LINE__; case __LINE__: - -#define LC_END(s) } - -#endif /* __LC_SWITCH_H__ */ - -/** @} */ diff --git a/fw/pt/lc.h b/fw/pt/lc.h deleted file mode 100644 index a965956..0000000 --- a/fw/pt/lc.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2004-2005, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * This file is part of the protothreads library. - * - * Author: Adam Dunkels - * - * $Id: lc.h,v 1.2 2005/02/24 10:36:59 adam Exp $ - */ - -/** - * \addtogroup pt - * @{ - */ - -/** - * \defgroup lc Local continuations - * @{ - * - * Local continuations form the basis for implementing protothreads. A - * local continuation can be set in a specific function to - * capture the state of the function. After a local continuation has - * been set can be resumed in order to restore the state of the - * function at the point where the local continuation was set. - * - * - */ - -/** - * \file lc.h - * Local continuations - * \author - * Adam Dunkels - * - */ - -#ifdef DOXYGEN -/** - * Initialize a local continuation. - * - * This operation initializes the local continuation, thereby - * unsetting any previously set continuation state. - * - * \hideinitializer - */ -#define LC_INIT(lc) - -/** - * Set a local continuation. - * - * The set operation saves the state of the function at the point - * where the operation is executed. As far as the set operation is - * concerned, the state of the function does not include the - * call-stack or local (automatic) variables, but only the program - * counter and such CPU registers that needs to be saved. - * - * \hideinitializer - */ -#define LC_SET(lc) - -/** - * Resume a local continuation. - * - * The resume operation resumes a previously set local continuation, thus - * restoring the state in which the function was when the local - * continuation was set. If the local continuation has not been - * previously set, the resume operation does nothing. - * - * \hideinitializer - */ -#define LC_RESUME(lc) - -/** - * Mark the end of local continuation usage. - * - * The end operation signifies that local continuations should not be - * used any more in the function. This operation is not needed for - * most implementations of local continuation, but is required by a - * few implementations. - * - * \hideinitializer - */ -#define LC_END(lc) - -/** - * \var typedef lc_t; - * - * The local continuation type. - * - * \hideinitializer - */ -#endif /* DOXYGEN */ - -#ifndef __LC_H__ -#define __LC_H__ - - -#ifdef LC_INCLUDE -#include LC_INCLUDE -#else -#include "lc-switch.h" -#endif /* LC_INCLUDE */ - -#endif /* __LC_H__ */ - -/** @} */ -/** @} */ diff --git a/fw/pt/pt-sem.h b/fw/pt/pt-sem.h deleted file mode 100644 index 98ae25d..0000000 --- a/fw/pt/pt-sem.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2004, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * This file is part of the protothreads library. - * - * Author: Adam Dunkels - * - * $Id: pt-sem.h,v 1.2 2005/02/24 10:36:59 adam Exp $ - */ - -/** - * \addtogroup pt - * @{ - */ - -/** - * \defgroup ptsem Protothread semaphores - * @{ - * - * This module implements counting semaphores on top of - * protothreads. Semaphores are a synchronization primitive that - * provide two operations: "wait" and "signal". The "wait" operation - * checks the semaphore counter and blocks the thread if the counter - * is zero. The "signal" operation increases the semaphore counter but - * does not block. If another thread has blocked waiting for the - * semaphore that is signalled, the blocked thread will become - * runnable again. - * - * Semaphores can be used to implement other, more structured, - * synchronization primitives such as monitors and message - * queues/bounded buffers (see below). - * - * The following example shows how the producer-consumer problem, also - * known as the bounded buffer problem, can be solved using - * protothreads and semaphores. Notes on the program follow after the - * example. - * - \code -#include "pt-sem.h" - -#define NUM_ITEMS 32 -#define BUFSIZE 8 - -static struct pt_sem mutex, full, empty; - -PT_THREAD(producer(struct pt *pt)) -{ - static int produced; - - PT_BEGIN(pt); - - for(produced = 0; produced < NUM_ITEMS; ++produced) { - - PT_SEM_WAIT(pt, &full); - - PT_SEM_WAIT(pt, &mutex); - add_to_buffer(produce_item()); - PT_SEM_SIGNAL(pt, &mutex); - - PT_SEM_SIGNAL(pt, &empty); - } - - PT_END(pt); -} - -PT_THREAD(consumer(struct pt *pt)) -{ - static int consumed; - - PT_BEGIN(pt); - - for(consumed = 0; consumed < NUM_ITEMS; ++consumed) { - - PT_SEM_WAIT(pt, &empty); - - PT_SEM_WAIT(pt, &mutex); - consume_item(get_from_buffer()); - PT_SEM_SIGNAL(pt, &mutex); - - PT_SEM_SIGNAL(pt, &full); - } - - PT_END(pt); -} - -PT_THREAD(driver_thread(struct pt *pt)) -{ - static struct pt pt_producer, pt_consumer; - - PT_BEGIN(pt); - - PT_SEM_INIT(&empty, 0); - PT_SEM_INIT(&full, BUFSIZE); - PT_SEM_INIT(&mutex, 1); - - PT_INIT(&pt_producer); - PT_INIT(&pt_consumer); - - PT_WAIT_THREAD(pt, producer(&pt_producer) & - consumer(&pt_consumer)); - - PT_END(pt); -} - \endcode - * - * The program uses three protothreads: one protothread that - * implements the consumer, one thread that implements the producer, - * and one protothread that drives the two other protothreads. The - * program uses three semaphores: "full", "empty" and "mutex". The - * "mutex" semaphore is used to provide mutual exclusion for the - * buffer, the "empty" semaphore is used to block the consumer is the - * buffer is empty, and the "full" semaphore is used to block the - * producer is the buffer is full. - * - * The "driver_thread" holds two protothread state variables, - * "pt_producer" and "pt_consumer". It is important to note that both - * these variables are declared as static. If the static - * keyword is not used, both variables are stored on the stack. Since - * protothreads do not store the stack, these variables may be - * overwritten during a protothread wait operation. Similarly, both - * the "consumer" and "producer" protothreads declare their local - * variables as static, to avoid them being stored on the stack. - * - * - */ - -/** - * \file - * Couting semaphores implemented on protothreads - * \author - * Adam Dunkels - * - */ - -#ifndef __PT_SEM_H__ -#define __PT_SEM_H__ - -#include "pt.h" - -struct pt_sem { - unsigned int count; -}; - -/** - * Initialize a semaphore - * - * This macro initializes a semaphore with a value for the - * counter. Internally, the semaphores use an "unsigned int" to - * represent the counter, and therefore the "count" argument should be - * within range of an unsigned int. - * - * \param s (struct pt_sem *) A pointer to the pt_sem struct - * representing the semaphore - * - * \param c (unsigned int) The initial count of the semaphore. - * \hideinitializer - */ -#define PT_SEM_INIT(s, c) (s)->count = c - -/** - * Wait for a semaphore - * - * This macro carries out the "wait" operation on the semaphore. The - * wait operation causes the protothread to block while the counter is - * zero. When the counter reaches a value larger than zero, the - * protothread will continue. - * - * \param pt (struct pt *) A pointer to the protothread (struct pt) in - * which the operation is executed. - * - * \param s (struct pt_sem *) A pointer to the pt_sem struct - * representing the semaphore - * - * \hideinitializer - */ -#define PT_SEM_WAIT(pt, s) \ - do { \ - PT_WAIT_UNTIL(pt, (s)->count > 0); \ - --(s)->count; \ - } while(0) - -/** - * Signal a semaphore - * - * This macro carries out the "signal" operation on the semaphore. The - * signal operation increments the counter inside the semaphore, which - * eventually will cause waiting protothreads to continue executing. - * - * \param pt (struct pt *) A pointer to the protothread (struct pt) in - * which the operation is executed. - * - * \param s (struct pt_sem *) A pointer to the pt_sem struct - * representing the semaphore - * - * \hideinitializer - */ -#define PT_SEM_SIGNAL(pt, s) ++(s)->count - -#endif /* __PT_SEM_H__ */ - -/** @} */ -/** @} */ - diff --git a/fw/pt/pt.h b/fw/pt/pt.h deleted file mode 100644 index 92856cb..0000000 --- a/fw/pt/pt.h +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (c) 2004-2005, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * This file is part of the Contiki operating system. - * - * Author: Adam Dunkels - * - * $Id: pt.h,v 1.7 2006/10/02 07:52:56 adam Exp $ - */ - -/** - * \addtogroup pt - * @{ - */ - -/** - * \file - * Protothreads implementation. - * \author - * Adam Dunkels - * - */ - -#ifndef __PT_H__ -#define __PT_H__ - -#include "lc.h" - -struct pt { - lc_t lc; -}; - -#define PT_WAITING 0 -#define PT_YIELDED 1 -#define PT_EXITED 2 -#define PT_ENDED 3 - -/** - * \name Initialization - * @{ - */ - -/** - * Initialize a protothread. - * - * Initializes a protothread. Initialization must be done prior to - * starting to execute the protothread. - * - * \param pt A pointer to the protothread control structure. - * - * \sa PT_SPAWN() - * - * \hideinitializer - */ -#define PT_INIT(pt) LC_INIT((pt)->lc) - -/** @} */ - -/** - * \name Declaration and definition - * @{ - */ - -/** - * Declaration of a protothread. - * - * This macro is used to declare a protothread. All protothreads must - * be declared with this macro. - * - * \param name_args The name and arguments of the C function - * implementing the protothread. - * - * \hideinitializer - */ -#define PT_THREAD(name_args) char name_args - -/** - * Declare the start of a protothread inside the C function - * implementing the protothread. - * - * This macro is used to declare the starting point of a - * protothread. It should be placed at the start of the function in - * which the protothread runs. All C statements above the PT_BEGIN() - * invokation will be executed each time the protothread is scheduled. - * - * \param pt A pointer to the protothread control structure. - * - * \hideinitializer - */ -#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc) - -/** - * Declare the end of a protothread. - * - * This macro is used for declaring that a protothread ends. It must - * always be used together with a matching PT_BEGIN() macro. - * - * \param pt A pointer to the protothread control structure. - * - * \hideinitializer - */ -#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \ - PT_INIT(pt); return PT_ENDED; } - -/** @} */ - -/** - * \name Blocked wait - * @{ - */ - -/** - * Block and wait until condition is true. - * - * This macro blocks the protothread until the specified condition is - * true. - * - * \param pt A pointer to the protothread control structure. - * \param condition The condition. - * - * \hideinitializer - */ -#define PT_WAIT_UNTIL(pt, condition) \ - do { \ - LC_SET((pt)->lc); \ - if(!(condition)) { \ - return PT_WAITING; \ - } \ - } while(0) - -/** - * Block and wait while condition is true. - * - * This function blocks and waits while condition is true. See - * PT_WAIT_UNTIL(). - * - * \param pt A pointer to the protothread control structure. - * \param cond The condition. - * - * \hideinitializer - */ -#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond)) - -/** @} */ - -/** - * \name Hierarchical protothreads - * @{ - */ - -/** - * Block and wait until a child protothread completes. - * - * This macro schedules a child protothread. The current protothread - * will block until the child protothread completes. - * - * \note The child protothread must be manually initialized with the - * PT_INIT() function before this function is used. - * - * \param pt A pointer to the protothread control structure. - * \param thread The child protothread with arguments - * - * \sa PT_SPAWN() - * - * \hideinitializer - */ -#define PT_WAIT_THREAD(pt, thread) PT_WAIT_WHILE((pt), PT_SCHEDULE(thread)) - -/** - * Spawn a child protothread and wait until it exits. - * - * This macro spawns a child protothread and waits until it exits. The - * macro can only be used within a protothread. - * - * \param pt A pointer to the protothread control structure. - * \param child A pointer to the child protothread's control structure. - * \param thread The child protothread with arguments - * - * \hideinitializer - */ -#define PT_SPAWN(pt, child, thread) \ - do { \ - PT_INIT((child)); \ - PT_WAIT_THREAD((pt), (thread)); \ - } while(0) - -/** @} */ - -/** - * \name Exiting and restarting - * @{ - */ - -/** - * Restart the protothread. - * - * This macro will block and cause the running protothread to restart - * its execution at the place of the PT_BEGIN() call. - * - * \param pt A pointer to the protothread control structure. - * - * \hideinitializer - */ -#define PT_RESTART(pt) \ - do { \ - PT_INIT(pt); \ - return PT_WAITING; \ - } while(0) - -/** - * Exit the protothread. - * - * This macro causes the protothread to exit. If the protothread was - * spawned by another protothread, the parent protothread will become - * unblocked and can continue to run. - * - * \param pt A pointer to the protothread control structure. - * - * \hideinitializer - */ -#define PT_EXIT(pt) \ - do { \ - PT_INIT(pt); \ - return PT_EXITED; \ - } while(0) - -/** @} */ - -/** - * \name Calling a protothread - * @{ - */ - -/** - * Schedule a protothread. - * - * This function shedules a protothread. The return value of the - * function is non-zero if the protothread is running or zero if the - * protothread has exited. - * - * \param f The call to the C function implementing the protothread to - * be scheduled - * - * \hideinitializer - */ -#define PT_SCHEDULE(f) ((f) < PT_EXITED) - -/** @} */ - -/** - * \name Yielding from a protothread - * @{ - */ - -/** - * Yield from the current protothread. - * - * This function will yield the protothread, thereby allowing other - * processing to take place in the system. - * - * \param pt A pointer to the protothread control structure. - * - * \hideinitializer - */ -#define PT_YIELD(pt) \ - do { \ - PT_YIELD_FLAG = 0; \ - LC_SET((pt)->lc); \ - if(PT_YIELD_FLAG == 0) { \ - return PT_YIELDED; \ - } \ - } while(0) - -/** - * \brief Yield from the protothread until a condition occurs. - * \param pt A pointer to the protothread control structure. - * \param cond The condition. - * - * This function will yield the protothread, until the - * specified condition evaluates to true. - * - * - * \hideinitializer - */ -#define PT_YIELD_UNTIL(pt, cond) \ - do { \ - PT_YIELD_FLAG = 0; \ - LC_SET((pt)->lc); \ - if((PT_YIELD_FLAG == 0) || !(cond)) { \ - return PT_YIELDED; \ - } \ - } while(0) - -/** @} */ - -#endif /* __PT_H__ */ - -/** @} */