# 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 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