Contiki 2.6

pt-sem.h

Go to the documentation of this file.
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 Contiki operating system.
00030  * 
00031  * Author: Adam Dunkels <adam@sics.se>
00032  *
00033  * $Id: pt-sem.h,v 1.2 2008/10/14 12:46:39 nvt-se 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 signaled, 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  * Counting 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 "sys/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