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 65 0.0 %
Date: 2015-06-10 18:10:59 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2003 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             : #if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__BORLANDC__) \
      47             :     || defined(AO_USE_NO_SIGNALS)
      48             : 
      49             : #undef AO_REQUIRE_CAS
      50             : 
      51             : #include <pthread.h>
      52             : 
      53             : #ifndef AO_USE_NO_SIGNALS
      54             : # include <signal.h>
      55             : #endif
      56             : 
      57             : #ifdef AO_USE_NANOSLEEP
      58             :   /* This requires _POSIX_TIMERS feature. */
      59             : # include <sys/time.h>
      60             : # include <time.h>
      61             : #elif defined(AO_USE_WIN32_PTHREADS)
      62             : # include <windows.h> /* for Sleep() */
      63             : #elif defined(_HPUX_SOURCE)
      64             : # include <sys/time.h>
      65             : #else
      66             : # include <sys/select.h>
      67             : #endif
      68             : 
      69             : #include "atomic_ops.h"  /* Without cas emulation! */
      70             : 
      71             : #ifndef AO_HAVE_double_t
      72             : # include "atomic_ops/sysdeps/standard_ao_double_t.h"
      73             : #endif
      74             : 
      75             : /*
      76             :  * Lock for pthreads-based implementation.
      77             :  */
      78             : 
      79             : pthread_mutex_t AO_pt_lock = PTHREAD_MUTEX_INITIALIZER;
      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             :  * FIXME: We should 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             : static AO_T dummy = 1;
     105             : 
     106             : /* Spin for 2**n units. */
     107           0 : void AO_spin(int n)
     108             : {
     109             :   int i;
     110           0 :   AO_T j = AO_load(&dummy);
     111             : 
     112           0 :   for (i = 0; i < (2 << n); ++i)
     113             :     {
     114           0 :        j *= 5;
     115           0 :        j -= 4;
     116             :     }
     117           0 :   AO_store(&dummy, j);
     118           0 : }
     119             : 
     120           0 : void AO_pause(int n)
     121             : {
     122           0 :   if (n < 12)
     123           0 :     AO_spin(n);
     124             :   else
     125             :     {
     126             : #     ifdef AO_USE_NANOSLEEP
     127             :         struct timespec ts;
     128             :         ts.tv_sec = 0;
     129             :         ts.tv_nsec = (n > 28 ? 100000 * 1000 : 1 << (n - 2));
     130             :         nanosleep(&ts, 0);
     131             : #     elif defined(AO_USE_WIN32_PTHREADS)
     132             :         Sleep(n > 28 ? 100 : 1 << (n - 22)); /* in millis */
     133             : #     else
     134             :         struct timeval tv;
     135             :         /* Short async-signal-safe sleep. */
     136           0 :         tv.tv_sec = 0;
     137           0 :         tv.tv_usec = n > 28 ? 100000 : 1 << (n - 12);
     138           0 :         select(0, 0, 0, 0, &tv);
     139             : #     endif
     140             :     }
     141           0 : }
     142             : 
     143           0 : static void lock_ool(volatile AO_TS_t *l)
     144             : {
     145           0 :   int i = 0;
     146             : 
     147           0 :   while (AO_test_and_set_acquire(l) == AO_TS_SET)
     148           0 :     AO_pause(++i);
     149           0 : }
     150             : 
     151           0 : AO_INLINE void lock(volatile AO_TS_t *l)
     152             : {
     153           0 :   if (AO_test_and_set_acquire(l) == AO_TS_SET)
     154           0 :     lock_ool(l);
     155           0 : }
     156             : 
     157           0 : AO_INLINE void unlock(volatile AO_TS_t *l)
     158             : {
     159           0 :   AO_CLEAR(l);
     160           0 : }
     161             : 
     162             : #ifndef AO_USE_NO_SIGNALS
     163             :   static sigset_t all_sigs;
     164             :   static volatile AO_t initialized = 0;
     165             :   static volatile AO_TS_t init_lock = AO_TS_INITIALIZER;
     166             : #endif
     167             : 
     168           0 : int AO_compare_and_swap_emulation(volatile AO_t *addr, AO_t old,
     169             :                                   AO_t new_val)
     170             : {
     171           0 :   AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
     172             :   int result;
     173             : 
     174             : # ifndef AO_USE_NO_SIGNALS
     175             :     sigset_t old_sigs;
     176           0 :     if (!AO_load_acquire(&initialized))
     177             :     {
     178           0 :       lock(&init_lock);
     179           0 :       if (!initialized) sigfillset(&all_sigs);
     180           0 :       unlock(&init_lock);
     181           0 :       AO_store_release(&initialized, 1);
     182             :     }
     183           0 :     sigprocmask(SIG_BLOCK, &all_sigs, &old_sigs);
     184             :         /* Neither sigprocmask nor pthread_sigmask is 100%      */
     185             :         /* guaranteed to work here.  Sigprocmask is not         */
     186             :         /* guaranteed be thread safe, and pthread_sigmask       */
     187             :         /* is not async-signal-safe.  Under linuxthreads,       */
     188             :         /* sigprocmask may block some pthreads-internal         */
     189             :         /* signals.  So long as we do that for short periods,   */
     190             :         /* we should be OK.                                     */
     191             : # endif
     192           0 :   lock(my_lock);
     193           0 :   if (*addr == old)
     194             :     {
     195           0 :       *addr = new_val;
     196           0 :       result = 1;
     197             :     }
     198             :   else
     199           0 :     result = 0;
     200           0 :   unlock(my_lock);
     201             : # ifndef AO_USE_NO_SIGNALS
     202           0 :     sigprocmask(SIG_SETMASK, &old_sigs, NULL);
     203             : # endif
     204           0 :   return result;
     205             : }
     206             : 
     207           0 : int AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,
     208             :                                                 AO_t old_val1, AO_t old_val2,
     209             :                                                 AO_t new_val1, AO_t new_val2)
     210             : {
     211           0 :   AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
     212             :   int result;
     213             : 
     214             : # ifndef AO_USE_NO_SIGNALS
     215             :     sigset_t old_sigs;
     216           0 :     if (!AO_load_acquire(&initialized))
     217             :     {
     218           0 :       lock(&init_lock);
     219           0 :       if (!initialized) sigfillset(&all_sigs);
     220           0 :       unlock(&init_lock);
     221           0 :       AO_store_release(&initialized, 1);
     222             :     }
     223           0 :     sigprocmask(SIG_BLOCK, &all_sigs, &old_sigs);
     224             :         /* Neither sigprocmask nor pthread_sigmask is 100%      */
     225             :         /* guaranteed to work here.  Sigprocmask is not         */
     226             :         /* guaranteed be thread safe, and pthread_sigmask       */
     227             :         /* is not async-signal-safe.  Under linuxthreads,       */
     228             :         /* sigprocmask may block some pthreads-internal         */
     229             :         /* signals.  So long as we do that for short periods,   */
     230             :         /* we should be OK.                                     */
     231             : # endif
     232           0 :   lock(my_lock);
     233           0 :   if (addr -> AO_val1 == old_val1 && addr -> AO_val2 == old_val2)
     234             :     {
     235           0 :       addr -> AO_val1 = new_val1;
     236           0 :       addr -> AO_val2 = new_val2;
     237           0 :       result = 1;
     238             :     }
     239             :   else
     240           0 :     result = 0;
     241           0 :   unlock(my_lock);
     242             : # ifndef AO_USE_NO_SIGNALS
     243           0 :     sigprocmask(SIG_SETMASK, &old_sigs, NULL);
     244             : # endif
     245           0 :   return result;
     246             : }
     247             : 
     248           0 : void AO_store_full_emulation(volatile AO_t *addr, AO_t val)
     249             : {
     250           0 :   AO_TS_t *my_lock = AO_locks + AO_HASH(addr);
     251           0 :   lock(my_lock);
     252           0 :   *addr = val;
     253           0 :   unlock(my_lock);
     254           0 : }
     255             : 
     256             : #else /* Non-posix platform */
     257             : 
     258             : extern int AO_non_posix_implementation_is_entirely_in_headers;
     259             : 
     260             : #endif

Generated by: LCOV version 1.11