00001 /* 00002 * Copyright (c) 2004, 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-sem.h,v 1.2 2005/02/24 10:36:59 adam Exp $ 00034 */ 00035 00036 /** 00037 * \addtogroup pt 00038 * @{ 00039 */ 00040 00041 /** 00042 * \defgroup ptsem Protothread semaphores 00043 * @{ 00044 * 00045 * This module implements counting semaphores on top of 00046 * protothreads. Semaphores are a synchronization primitive that 00047 * provide two operations: "wait" and "signal". The "wait" operation 00048 * checks the semaphore counter and blocks the thread if the counter 00049 * is zero. The "signal" operation increases the semaphore counter but 00050 * does not block. If another thread has blocked waiting for the 00051 * semaphore that is signalled, the blocked thread will become 00052 * runnable again. 00053 * 00054 * Semaphores can be used to implement other, more structured, 00055 * synchronization primitives such as monitors and message 00056 * queues/bounded buffers (see below). 00057 * 00058 * The following example shows how the producer-consumer problem, also 00059 * known as the bounded buffer problem, can be solved using 00060 * protothreads and semaphores. Notes on the program follow after the 00061 * example. 00062 * 00063 \code 00064 #include "pt-sem.h" 00065 00066 #define NUM_ITEMS 32 00067 #define BUFSIZE 8 00068 00069 static struct pt_sem mutex, full, empty; 00070 00071 PT_THREAD(producer(struct pt *pt)) 00072 { 00073 static int produced; 00074 00075 PT_BEGIN(pt); 00076 00077 for(produced = 0; produced < NUM_ITEMS; ++produced) { 00078 00079 PT_SEM_WAIT(pt, &full); 00080 00081 PT_SEM_WAIT(pt, &mutex); 00082 add_to_buffer(produce_item()); 00083 PT_SEM_SIGNAL(pt, &mutex); 00084 00085 PT_SEM_SIGNAL(pt, &empty); 00086 } 00087 00088 PT_END(pt); 00089 } 00090 00091 PT_THREAD(consumer(struct pt *pt)) 00092 { 00093 static int consumed; 00094 00095 PT_BEGIN(pt); 00096 00097 for(consumed = 0; consumed < NUM_ITEMS; ++consumed) { 00098 00099 PT_SEM_WAIT(pt, &empty); 00100 00101 PT_SEM_WAIT(pt, &mutex); 00102 consume_item(get_from_buffer()); 00103 PT_SEM_SIGNAL(pt, &mutex); 00104 00105 PT_SEM_SIGNAL(pt, &full); 00106 } 00107 00108 PT_END(pt); 00109 } 00110 00111 PT_THREAD(driver_thread(struct pt *pt)) 00112 { 00113 static struct pt pt_producer, pt_consumer; 00114 00115 PT_BEGIN(pt); 00116 00117 PT_SEM_INIT(&empty, 0); 00118 PT_SEM_INIT(&full, BUFSIZE); 00119 PT_SEM_INIT(&mutex, 1); 00120 00121 PT_INIT(&pt_producer); 00122 PT_INIT(&pt_consumer); 00123 00124 PT_WAIT_THREAD(pt, producer(&pt_producer) & 00125 consumer(&pt_consumer)); 00126 00127 PT_END(pt); 00128 } 00129 \endcode 00130 * 00131 * The program uses three protothreads: one protothread that 00132 * implements the consumer, one thread that implements the producer, 00133 * and one protothread that drives the two other protothreads. The 00134 * program uses three semaphores: "full", "empty" and "mutex". The 00135 * "mutex" semaphore is used to provide mutual exclusion for the 00136 * buffer, the "empty" semaphore is used to block the consumer is the 00137 * buffer is empty, and the "full" semaphore is used to block the 00138 * producer is the buffer is full. 00139 * 00140 * The "driver_thread" holds two protothread state variables, 00141 * "pt_producer" and "pt_consumer". It is important to note that both 00142 * these variables are declared as <i>static</i>. If the static 00143 * keyword is not used, both variables are stored on the stack. Since 00144 * protothreads do not store the stack, these variables may be 00145 * overwritten during a protothread wait operation. Similarly, both 00146 * the "consumer" and "producer" protothreads declare their local 00147 * variables as static, to avoid them being stored on the stack. 00148 * 00149 * 00150 */ 00151 00152 /** 00153 * \file 00154 * Couting semaphores implemented on protothreads 00155 * \author 00156 * Adam Dunkels <adam@sics.se> 00157 * 00158 */ 00159 00160 #ifndef __PT_SEM_H__ 00161 #define __PT_SEM_H__ 00162 00163 #include "pt.h" 00164 00165 struct pt_sem { 00166 unsigned int count; 00167 }; 00168 00169 /** 00170 * Initialize a semaphore 00171 * 00172 * This macro initializes a semaphore with a value for the 00173 * counter. Internally, the semaphores use an "unsigned int" to 00174 * represent the counter, and therefore the "count" argument should be 00175 * within range of an unsigned int. 00176 * 00177 * \param s (struct pt_sem *) A pointer to the pt_sem struct 00178 * representing the semaphore 00179 * 00180 * \param c (unsigned int) The initial count of the semaphore. 00181 * \hideinitializer 00182 */ 00183 #define PT_SEM_INIT(s, c) (s)->count = c 00184 00185 /** 00186 * Wait for a semaphore 00187 * 00188 * This macro carries out the "wait" operation on the semaphore. The 00189 * wait operation causes the protothread to block while the counter is 00190 * zero. When the counter reaches a value larger than zero, the 00191 * protothread will continue. 00192 * 00193 * \param pt (struct pt *) A pointer to the protothread (struct pt) in 00194 * which the operation is executed. 00195 * 00196 * \param s (struct pt_sem *) A pointer to the pt_sem struct 00197 * representing the semaphore 00198 * 00199 * \hideinitializer 00200 */ 00201 #define PT_SEM_WAIT(pt, s) \ 00202 do { \ 00203 PT_WAIT_UNTIL(pt, (s)->count > 0); \ 00204 --(s)->count; \ 00205 } while(0) 00206 00207 /** 00208 * Signal a semaphore 00209 * 00210 * This macro carries out the "signal" operation on the semaphore. The 00211 * signal operation increments the counter inside the semaphore, which 00212 * eventually will cause waiting protothreads to continue executing. 00213 * 00214 * \param pt (struct pt *) A pointer to the protothread (struct pt) in 00215 * which the operation is executed. 00216 * 00217 * \param s (struct pt_sem *) A pointer to the pt_sem struct 00218 * representing the semaphore 00219 * 00220 * \hideinitializer 00221 */ 00222 #define PT_SEM_SIGNAL(pt, s) ++(s)->count 00223 00224 #endif /* __PT_SEM_H__ */ 00225 00226 /** @} */ 00227 /** @} */ 00228