LCOV - code coverage report
Current view: top level - mm/boehm-gc/libatomic_ops/src - atomic_ops.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 63 0.0 %
Date: 2017-07-14 10:03:36 Functions: 0 9 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2003-2011 Hewlett-Packard Development Company, L.P.
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  * of this software and associated documentation files (the "Software"), to deal
       6             :  * in the Software without restriction, including without limitation the rights
       7             :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  * copies of the Software, and to permit persons to whom the Software is
       9             :  * furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in
      12             :  * all copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      20             :  * SOFTWARE.
      21             :  */
      22             : 
      23             : /*
      24             :  * Initialized data and out-of-line functions to support atomic_ops.h
      25             :  * go here.  Currently this is needed only for pthread-based atomics
      26             :  * emulation, or for compare-and-swap emulation.
      27             :  * Pthreads emulation isn't useful on a native Windows platform, and
      28             :  * cas emulation is not needed.  Thus we skip this on Windows.
      29             :  */
      30             : 
      31             : #if defined(HAVE_CONFIG_H)
      32             : # include "config.h"
      33             : #endif
      34             : 
      35             : #if defined(__native_client__) && !defined(AO_USE_NO_SIGNALS) \
      36             :     && !defined(AO_USE_NANOSLEEP)
      37             :   /* Since NaCl is not recognized by configure yet, we do it here.      */
      38             : # define AO_USE_NO_SIGNALS
      39             : # define AO_USE_NANOSLEEP
      40             : #endif
      41             : 
      42             : #if defined(AO_USE_WIN32_PTHREADS) && !defined(AO_USE_NO_SIGNALS)
      43             : # define AO_USE_NO_SIGNALS
      44             : #endif
      45             : 
      46             : #undef AO_REQUIRE_CAS
      47             : #include "atomic_ops.h" /* Without cas emulation! */
      48             : 
      49             : #if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__BORLANDC__) \
      50             :     || defined(AO_USE_NO_SIGNALS)
      51             : 
      52             : #ifndef AO_NO_PTHREADS
      53             : # include <pthread.h>
      54             : #endif
      55             : 
      56             : #ifndef AO_USE_NO_SIGNALS
      57             : # include <signal.h>
      58             : #endif
      59             : 
      60             : #ifdef AO_USE_NANOSLEEP
      61             :   /* This requires _POSIX_TIMERS feature. */
      62             : # include <sys/time.h>
      63             : # include <time.h>
      64             : #elif defined(AO_USE_WIN32_PTHREADS)
      65             : # include <windows.h> /* for Sleep() */
      66             : #elif defined(_HPUX_SOURCE)
      67             : # include <sys/time.h>
      68             : #else
      69             : # include <sys/select.h>
      70             : #endif
      71             : 
      72             : #ifndef AO_HAVE_double_t
      73             : # include "atomic_ops/sysdeps/standard_ao_double_t.h"
      74             : #endif
      75             : 
      76             : /* Lock for pthreads-based implementation.      */
      77             : #ifndef AO_NO_PTHREADS
      78             :   pthread_mutex_t AO_pt_lock = PTHREAD_MUTEX_INITIALIZER;
      79             : #endif
      80             : 
      81             : /*
      82             :  * Out of line compare-and-swap emulation based on test and set.
      83             :  *
      84             :  * We use a small table of locks for different compare_and_swap locations.
      85             :  * Before we update perform a compare-and-swap, we grab the corresponding
      86             :  * lock.  Different locations may hash to the same lock, but since we
      87             :  * never acquire more than one lock at a time, this can't deadlock.
      88             :  * We explicitly disable signals while we perform this operation.
      89             :  *
      90             :  * TODO: Probably also support emulation based on Lamport
      91             :  * locks, since we may not have test_and_set either.
      92             :  */
      93             : #define AO_HASH_SIZE 16
      94             : 
      95             : #define AO_HASH(x) (((unsigned long)(x) >> 12) & (AO_HASH_SIZE-1))
      96             : 
      97             : AO_TS_t AO_locks[AO_HASH_SIZE] = {
      98             :   AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER,
      99             :   AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER,
     100             :   AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER,
     101             :   AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER, AO_TS_INITIALIZER,
     102             : };
     103             : 
     104             : void AO_pause(int); /* defined below */
     105             : 
     106           0 : static void lock_ool(volatile AO_TS_t *l)
     107             : {
     108           0 :   int i = 0;
     109             : 
     110           0 :   while (AO_test_and_set_acquire(l) == AO_TS_SET)
     111           0 :     AO_pause(++i);
     112           0 : }
     113             : 
     114           0 : AO_INLINE void lock(volatile AO_TS_t *l)
     115             : {
     116           0 :   if (AO_EXPECT_FALSE(AO_test_and_set_acquire(l) == AO_TS_SET))
     117           0 :     lock_ool(l);
     118           0 : }
     119             : 
     120           0 : AO_INLINE void unlock(volatile AO_TS_t *l)
     121             : {
     122           0 :   AO_CLEAR(l);
     123           0 : }
     124             : 
     125             : #ifndef AO_USE_NO_SIGNALS
     126             :   static sigset_t all_sigs;
     127             :   static volatile AO_t initialized = 0;
     128             :   static volatile AO_TS_t init_lock = AO_TS_INITIALIZER;
     129             : 
     130           0 :   AO_INLINE void block_all_signals(sigset_t *old_sigs_ptr)
     131             :   {
     132           0 :     if (AO_EXPECT_FALSE(!AO_load_acquire(&initialized)))
     133             :     {
     134           0 :       lock(&init_lock);
     135           0 :       if (!initialized)
     136           0 :         sigfillset(&all_sigs);
     137           0 :       unlock(&init_lock);
     138           0 :       AO_store_release(&initialized, 1);
     139             :     }
     140           0 :     sigprocmask(SIG_BLOCK, &all_sigs, old_sigs_ptr);
     141             :         /* Neither sigprocmask nor pthread_sigmask is 100%      */
     142             :         /* guaranteed to work here.  Sigprocmask is not         */
     143             :         /* guaranteed be thread safe, and pthread_sigmask       */
     144             :         /* is not async-signal-safe.  Under linuxthreads,       */
     145             :         /* sigprocmask may block some pthreads-internal         */
     146             :         /* signals.  So long as we do that for short periods,   */
     147             :         /* we should be OK.                                     */
     148           0 :   }
     149             : #endif /* !AO_USE_NO_SIGNALS */
     150             : 
     151           0 : AO_t AO_fetch_compare_and_swap_emulation(volatile AO_t *addr, AO_t old_val,
     152             :                                          AO_t new_val)
     153             : {
     154           0 :   AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
     155             :   AO_t fetched_val;
     156             : 
     157             : # ifndef AO_USE_NO_SIGNALS
     158             :     sigset_t old_sigs;
     159           0 :     block_all_signals(&old_sigs);
     160             : # endif
     161           0 :   lock(my_lock);
     162           0 :   fetched_val = *addr;
     163           0 :   if (fetched_val == old_val)
     164           0 :     *addr = new_val;
     165           0 :   unlock(my_lock);
     166             : # ifndef AO_USE_NO_SIGNALS
     167           0 :     sigprocmask(SIG_SETMASK, &old_sigs, NULL);
     168             : # endif
     169           0 :   return fetched_val;
     170             : }
     171             : 
     172           0 : int AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,
     173             :                                                 AO_t old_val1, AO_t old_val2,
     174             :                                                 AO_t new_val1, AO_t new_val2)
     175             : {
     176           0 :   AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
     177             :   int result;
     178             : 
     179             : # ifndef AO_USE_NO_SIGNALS
     180             :     sigset_t old_sigs;
     181           0 :     block_all_signals(&old_sigs);
     182             : # endif
     183           0 :   lock(my_lock);
     184           0 :   if (addr -> AO_val1 == old_val1 && addr -> AO_val2 == old_val2)
     185             :     {
     186           0 :       addr -> AO_val1 = new_val1;
     187           0 :       addr -> AO_val2 = new_val2;
     188           0 :       result = 1;
     189             :     }
     190             :   else
     191           0 :     result = 0;
     192           0 :   unlock(my_lock);
     193             : # ifndef AO_USE_NO_SIGNALS
     194           0 :     sigprocmask(SIG_SETMASK, &old_sigs, NULL);
     195             : # endif
     196           0 :   return result;
     197             : }
     198             : 
     199           0 : void AO_store_full_emulation(volatile AO_t *addr, AO_t val)
     200             : {
     201           0 :   AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
     202           0 :   lock(my_lock);
     203           0 :   *addr = val;
     204           0 :   unlock(my_lock);
     205           0 : }
     206             : 
     207             : #else /* Non-posix platform */
     208             : 
     209             : # include <windows.h>
     210             : 
     211             : # define AO_USE_WIN32_PTHREADS
     212             :                 /* define to use Sleep() */
     213             : 
     214             :   extern int AO_non_posix_implementation_is_entirely_in_headers;
     215             : 
     216             : #endif
     217             : 
     218             : static AO_t spin_dummy = 1;
     219             : 
     220             : /* Spin for 2**n units. */
     221           0 : static void AO_spin(int n)
     222             : {
     223           0 :   AO_t j = AO_load(&spin_dummy);
     224           0 :   int i = 2 << n;
     225             : 
     226           0 :   while (i-- > 0)
     227           0 :     j += (j - 1) << 2;
     228             :   /* Given 'spin_dummy' is initialized to 1, j is 1 after the loop.     */
     229           0 :   AO_store(&spin_dummy, j);
     230           0 : }
     231             : 
     232           0 : void AO_pause(int n)
     233             : {
     234           0 :   if (n < 12)
     235           0 :     AO_spin(n);
     236             :   else
     237             :     {
     238             : #     ifdef AO_USE_NANOSLEEP
     239             :         struct timespec ts;
     240             :         ts.tv_sec = 0;
     241             :         ts.tv_nsec = (n > 28 ? 100000 * 1000 : 1 << (n - 2));
     242             :         nanosleep(&ts, 0);
     243             : #     elif defined(AO_USE_WIN32_PTHREADS)
     244             :         Sleep(n > 28 ? 100 : n < 22 ? 1 : 1 << (n - 22)); /* in millis */
     245             : #     else
     246             :         struct timeval tv;
     247             :         /* Short async-signal-safe sleep. */
     248           0 :         tv.tv_sec = 0;
     249           0 :         tv.tv_usec = n > 28 ? 100000 : 1 << (n - 12);
     250           0 :         select(0, 0, 0, 0, &tv);
     251             : #     endif
     252             :     }
     253           0 : }

Generated by: LCOV version 1.11