1 /*
   2  * Copyright © 2007  Chris Wilson
   3  * Copyright © 2009,2010  Red Hat, Inc.
   4  * Copyright © 2011,2012  Google, Inc.
   5  *
   6  *  This is part of HarfBuzz, a text shaping library.
   7  *
   8  * Permission is hereby granted, without written agreement and without
   9  * license or royalty fees, to use, copy, modify, and distribute this
  10  * software and its documentation for any purpose, provided that the
  11  * above copyright notice and the following two paragraphs appear in
  12  * all copies of this software.
  13  *
  14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  18  * DAMAGE.
  19  *
  20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  25  *
  26  * Contributor(s):
  27  *      Chris Wilson <chris@chris-wilson.co.uk>
  28  * Red Hat Author(s): Behdad Esfahbod
  29  * Google Author(s): Behdad Esfahbod
  30  */
  31 
  32 #ifndef HB_MUTEX_PRIVATE_HH
  33 #define HB_MUTEX_PRIVATE_HH
  34 
  35 #include "hb-private.hh"
  36 
  37 
  38 /* mutex */
  39 
  40 /* We need external help for these */
  41 
  42 #if defined(HB_MUTEX_IMPL_INIT) \
  43  && defined(hb_mutex_impl_init) \
  44  && defined(hb_mutex_impl_lock) \
  45  && defined(hb_mutex_impl_unlock) \
  46  && defined(hb_mutex_impl_finish)
  47 
  48 /* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
  49 
  50 
  51 #elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
  52 
  53 #include <windows.h>
  54 typedef CRITICAL_SECTION hb_mutex_impl_t;
  55 #define HB_MUTEX_IMPL_INIT      {0}
  56 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
  57 #define hb_mutex_impl_init(M)   InitializeCriticalSectionEx (M, 0, 0)
  58 #else
  59 #define hb_mutex_impl_init(M)   InitializeCriticalSection (M)
  60 #endif
  61 #define hb_mutex_impl_lock(M)   EnterCriticalSection (M)
  62 #define hb_mutex_impl_unlock(M) LeaveCriticalSection (M)
  63 #define hb_mutex_impl_finish(M) DeleteCriticalSection (M)
  64 
  65 
  66 #elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
  67 
  68 #include <pthread.h>
  69 typedef pthread_mutex_t hb_mutex_impl_t;
  70 #define HB_MUTEX_IMPL_INIT      PTHREAD_MUTEX_INITIALIZER
  71 #define hb_mutex_impl_init(M)   pthread_mutex_init (M, nullptr)
  72 #define hb_mutex_impl_lock(M)   pthread_mutex_lock (M)
  73 #define hb_mutex_impl_unlock(M) pthread_mutex_unlock (M)
  74 #define hb_mutex_impl_finish(M) pthread_mutex_destroy (M)
  75 
  76 
  77 #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
  78 
  79 #if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
  80 # include <sched.h>
  81 # define HB_SCHED_YIELD() sched_yield ()
  82 #else
  83 # define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
  84 #endif
  85 
  86 /* This actually is not a totally awful implementation. */
  87 typedef volatile int hb_mutex_impl_t;
  88 #define HB_MUTEX_IMPL_INIT      0
  89 #define hb_mutex_impl_init(M)   *(M) = 0
  90 #define hb_mutex_impl_lock(M)   HB_STMT_START { while (__sync_lock_test_and_set((M), 1)) HB_SCHED_YIELD (); } HB_STMT_END
  91 #define hb_mutex_impl_unlock(M) __sync_lock_release (M)
  92 #define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
  93 
  94 
  95 #elif !defined(HB_NO_MT)
  96 
  97 #if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
  98 # include <sched.h>
  99 # define HB_SCHED_YIELD() sched_yield ()
 100 #else
 101 # define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
 102 #endif
 103 
 104 #define HB_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */
 105 typedef volatile int hb_mutex_impl_t;
 106 #define HB_MUTEX_IMPL_INIT      0
 107 #define hb_mutex_impl_init(M)   *(M) = 0
 108 #define hb_mutex_impl_lock(M)   HB_STMT_START { while (*(M)) HB_SCHED_YIELD (); (*(M))++; } HB_STMT_END
 109 #define hb_mutex_impl_unlock(M) (*(M))--;
 110 #define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
 111 
 112 
 113 #else /* HB_NO_MT */
 114 
 115 typedef int hb_mutex_impl_t;
 116 #define HB_MUTEX_IMPL_INIT      0
 117 #define hb_mutex_impl_init(M)   HB_STMT_START {} HB_STMT_END
 118 #define hb_mutex_impl_lock(M)   HB_STMT_START {} HB_STMT_END
 119 #define hb_mutex_impl_unlock(M) HB_STMT_START {} HB_STMT_END
 120 #define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
 121 
 122 
 123 #endif
 124 
 125 
 126 #define HB_MUTEX_INIT           {HB_MUTEX_IMPL_INIT}
 127 
 128 struct hb_mutex_t
 129 {
 130   /* TODO Add tracing. */
 131 
 132   hb_mutex_impl_t m;
 133 
 134   inline void init   (void) { hb_mutex_impl_init   (&m); }
 135   inline void lock   (void) { hb_mutex_impl_lock   (&m); }
 136   inline void unlock (void) { hb_mutex_impl_unlock (&m); }
 137   inline void fini (void) { hb_mutex_impl_finish (&m); }
 138 };
 139 
 140 
 141 #endif /* HB_MUTEX_PRIVATE_HH */