root/src/gauche/port.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


   1 /*
   2  * gauche/port.h - Port inline macros
   3  *
   4  *   Copyright (c) 2000-2004 Shiro Kawai, All rights reserved.
   5  * 
   6  *   Redistribution and use in source and binary forms, with or without
   7  *   modification, are permitted provided that the following conditions
   8  *   are met:
   9  * 
  10  *   1. Redistributions of source code must retain the above copyright
  11  *      notice, this list of conditions and the following disclaimer.
  12  *
  13  *   2. Redistributions in binary form must reproduce the above copyright
  14  *      notice, this list of conditions and the following disclaimer in the
  15  *      documentation and/or other materials provided with the distribution.
  16  *
  17  *   3. Neither the name of the authors nor the names of its contributors
  18  *      may be used to endorse or promote products derived from this
  19  *      software without specific prior written permission.
  20  *
  21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
  27  *   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28  *   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29  *   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  *
  33  *  $Id: port.h,v 1.11 2004/10/17 10:29:39 shirok Exp $
  34  */
  35 
  36 /*
  37  * Defines several macros that inlines primitive port opertaions.
  38  * Used in Gauche internally.  Not for general use.
  39  */
  40 
  41 /* Mutex of ports:
  42  *  SRFI-18 requires the system to serialize access to ports.
  43  *  I need to implement a few tricks to avoid this requirement
  44  *  from affecting performance too much.
  45  *
  46  *  Each port has a recursive lock, that is, the same thread can
  47  *  lock the port many times; the port will be fully unlocked
  48  *  when the thread calls unlock as many times as it called lock.
  49  *
  50  *  The port functions may call-back Scheme code or other Gauche
  51  *  C API that may take arbitrarily long time to execute, and may
  52  *  raise an error.  It prevents us from using simple mutex; we
  53  *  need to use CVs, and need to save dynamic context to revert
  54  *  lock state in case an error is thrown during processing.
  55  *
  56  *  If implemented naively it costs too much, since in most
  57  *  cases the port operation is trivial; such as fetching some
  58  *  bytes from memory and incrementing a counter.   Only in some
  59  *  occasions the operation involves system calls or calling other
  60  *  Gauche C functions.   In the following macro, mutex call is done
  61  *  only when the caller hasn't been locked the port.
  62  *
  63  *  As you see, PORT_UNLOCK doesn't do any mutex ops.  I count on
  64  *  that the pointer assignment is atomic; if so, the race condition
  65  *  won't happen.  If not, Boehm GC won't work anyway.
  66  *
  67  *  Furthermore, some port functions have 'unsafe' mode, which 
  68  *  should be called when the caller is sure that the thread
  69  *  already locked the port.
  70  */
  71 
  72 /* TODO: what if a thread having a lock of the port died before unlocking it?
  73  * Currently, PORT_LOCK checks if the lock holder is terminated or not.
  74  * However, the dead thread may have left the port state inconsistent.
  75  * I need to set the cancellation points carefully...
  76  */
  77 
  78 #define PORT_LOCK(p, vm)                                        \
  79     do {                                                        \
  80       if (!(p->flags&SCM_PORT_PRIVATE)) {                       \
  81         if (p->lockOwner != vm) {                               \
  82           (void)SCM_INTERNAL_MUTEX_LOCK(p->mutex);              \
  83           while (p->lockOwner != NULL) {                        \
  84             if (p->lockOwner->state == SCM_VM_TERMINATED) {     \
  85               break;                                            \
  86             }                                                   \
  87             (void)SCM_INTERNAL_COND_WAIT(p->cv, p->mutex);      \
  88           }                                                     \
  89           p->lockOwner = vm;                                    \
  90           p->lockCount = 0;       /* for safety */              \
  91           (void)SCM_INTERNAL_MUTEX_UNLOCK(p->mutex);            \
  92         } else {                                                \
  93           p->lockCount++;                                       \
  94         }                                                       \
  95       }                                                         \
  96     } while (0)
  97 
  98 /* Assumes the calling thread has the lock */
  99 #define PORT_UNLOCK(p)                                  \
 100     do {                                                \
 101       if (!(p->flags&SCM_PORT_PRIVATE)) {               \
 102         if (--p->lockCount <= 0) {                      \
 103           p->lockOwner = NULL;                          \
 104           (void)SCM_INTERNAL_COND_SIGNAL(p->cv);        \
 105         }                                               \
 106       }                                                 \
 107     } while (0) 
 108 
 109 #define PORT_SAFE_CALL(p, call)                 \
 110     do {                                        \
 111       if (!(p->flags&SCM_PORT_PRIVATE)) {       \
 112         SCM_UNWIND_PROTECT {                    \
 113           call;                                 \
 114         } SCM_WHEN_ERROR {                      \
 115           PORT_UNLOCK(p);                       \
 116           SCM_NEXT_HANDLER;                     \
 117         } SCM_END_PROTECT;                      \
 118       } else {                                  \
 119         call;                                   \
 120       }                                         \
 121     } while (0)
 122 
 123 #define PORT_LOCKED(p, vm) \
 124    (((p)->flags&SCM_PORT_PRIVATE)||((p)->lockOwner == (vm)))
 125 
 126 /* Should be used in the constructor of provate ports.
 127    Mark the port locked by vm, so that it can be used exclusively by
 128    the vm. */
 129 
 130 #define PORT_PRELOCK(p, vm)                     \
 131    do {                                         \
 132      p->lockOwner = vm;                         \
 133      p->lockCount = 1;                          \
 134    } while (0)
 135    

/* [<][>][^][v][top][bottom][index][help] */