aboutsummaryrefslogblamecommitdiffstats
path: root/erts/include/internal/ethr_optimized_fallbacks.h
blob: 8c27a9ba5b42d35084838999292143eb4ac44dca (plain) (tree)
1
2
3
4
5
6
7
8
9


                   
                                                        
  


                                                                   
  






                                                                           




                 
                                                                    





                                    









                                                              

      
                                          



                                                                             
 
                                                  


                                                              

                                                       
 


                                                                


                      
                                                          



                                                             

                                                     
 


                                                               

 

                                                   
 


                                                             



      
                                                

                                                                                



                                                  


                                                              


                                                                             


                                                       






                                                          




                                                     

                                                  




                                                   

                                                            
                           



                          
                      
 
      
 


      












                                                              

                                                                                
                                                    
 
                                             
                                                       


                                                              


                                                                               


                                                   






                                                          




                                                   

                                                    




                                                 
                               
               
                                                                

                       
                                      

                                         
                                                

                  






                                                    

                                                                    




                                                  
                               
               
                                                                                

                       





                                                




                                      
                                                 



                          
                        
 
      
 


      
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2010-2016. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * %CopyrightEnd%
 */

/*
 * Description: Optimized fallbacks used when native ops are missing
 * Author: Rickard Green
 */

#ifndef ETHR_OPTIMIZED_FALLBACKS_H__
#define ETHR_OPTIMIZED_FALLBACKS_H__

#if defined(ETHR_HAVE_NATIVE_SPINLOCKS)

#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)

static ETHR_INLINE int
ethr_native_spinlock_destroy(ethr_native_spinlock_t *lock)
{
    return 0;
}

#endif

#elif defined(ETHR_HAVE_PTHREAD_SPIN_LOCK)
/* --- Native spinlocks using pthread spinlocks -------------------------- */
#define ETHR_HAVE_NATIVE_SPINLOCKS 1

#define ETHR_NATIVE_SPINLOCK_IMPL "pthread"

typedef pthread_spinlock_t ethr_native_spinlock_t;

#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)

static ETHR_INLINE void
ethr_native_spinlock_init(ethr_native_spinlock_t *lock)
{
    int err = pthread_spin_init((pthread_spinlock_t *) lock, 0);
    if (err)
	ETHR_FATAL_ERROR__(err);
}

static ETHR_INLINE int
ethr_native_spinlock_destroy(ethr_native_spinlock_t *lock)
{
    return pthread_spin_destroy((pthread_spinlock_t *) lock);
}

static ETHR_INLINE void
ethr_native_spin_unlock(ethr_native_spinlock_t *lock)
{
    int err = pthread_spin_unlock((pthread_spinlock_t *) lock);
    if (err)
	ETHR_FATAL_ERROR__(err);
}

static ETHR_INLINE void
ethr_native_spin_lock(ethr_native_spinlock_t *lock)
{
    int err = pthread_spin_lock((pthread_spinlock_t *) lock);
    if (err)
	ETHR_FATAL_ERROR__(err);
}

#endif

#elif defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
/* --- Native spinlocks using native atomics -------------------------------- */
#define ETHR_HAVE_NATIVE_SPINLOCKS 1

#define ETHR_NATIVE_SPINLOCK_IMPL "native-atomics"

typedef ethr_atomic32_t ethr_native_spinlock_t;

#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)

#undef ETHR_NSPN_AOP__
#define ETHR_NSPN_AOP__(X) ETHR_INLINE_ATMC32_FUNC_NAME_(ethr_atomic32_ ## X)

static ETHR_INLINE void
ethr_native_spinlock_init(ethr_native_spinlock_t *lock)
{
    ETHR_NSPN_AOP__(init)(lock, 0);
}

static ETHR_INLINE int
ethr_native_spinlock_destroy(ethr_native_spinlock_t *lock)
{
    return ETHR_NSPN_AOP__(read)(lock) == 0 ? 0 : EBUSY;
}

static ETHR_INLINE void
ethr_native_spin_unlock(ethr_native_spinlock_t *lock)
{
    ETHR_ASSERT(ETHR_NSPN_AOP__(read)(lock) == 1);
    ETHR_NSPN_AOP__(set_relb)(lock, 0);
}

static ETHR_INLINE void
ethr_native_spin_lock(ethr_native_spinlock_t *lock)
{
    while (ETHR_NSPN_AOP__(cmpxchg_acqb)(lock, 1, 0) != 0) {
	while (ETHR_NSPN_AOP__(read)(lock) != 0)
	    ETHR_SPIN_BODY;
    }
    ETHR_COMPILER_BARRIER;
}

#undef ETHR_NSPN_AOP__

#endif

#endif


#if defined(ETHR_HAVE_NATIVE_RWSPINLOCKS)

#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)

static ETHR_INLINE int
ethr_native_rwlock_destroy(ethr_native_rwlock_t *lock)
{
    return 0;
}

#endif

#elif defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
/* --- Native rwspinlocks using native atomics ------------------------------ */
#define ETHR_HAVE_NATIVE_RWSPINLOCKS 1
#define ETHR_NATIVE_RWSPINLOCK_IMPL "native-atomics"

typedef ethr_atomic32_t ethr_native_rwlock_t;
#  define ETHR_WLOCK_FLAG__ (((ethr_sint32_t) 1) << 30)

#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__)

#undef ETHR_NRWSPN_AOP__
#define ETHR_NRWSPN_AOP__(X) ETHR_INLINE_ATMC32_FUNC_NAME_(ethr_atomic32_ ## X)

static ETHR_INLINE void
ethr_native_rwlock_init(ethr_native_rwlock_t *lock)
{
    ETHR_NRWSPN_AOP__(init)(lock, 0);
}

static ETHR_INLINE int
ethr_native_rwlock_destroy(ethr_native_rwlock_t *lock)
{
    return ETHR_NRWSPN_AOP__(read)(lock) == 0 ? 0 : EBUSY;
}

static ETHR_INLINE void
ethr_native_read_unlock(ethr_native_rwlock_t *lock)
{
    ETHR_ASSERT(ETHR_NRWSPN_AOP__(read)(lock) >= 0);
    ETHR_NRWSPN_AOP__(dec_relb)(lock);
}

static ETHR_INLINE void
ethr_native_read_lock(ethr_native_rwlock_t *lock)
{
    ethr_sint32_t act, exp = 0;
    while (1) {
	act = ETHR_NRWSPN_AOP__(cmpxchg_acqb)(lock, exp+1, exp);
	if (act == exp)
	    break;
	/* Wait for writer to leave */
	while (act & ETHR_WLOCK_FLAG__) {
	    ETHR_SPIN_BODY;
	    act = ETHR_NRWSPN_AOP__(read)(lock);
	}
	exp = act;
    }
    ETHR_COMPILER_BARRIER;
}

static ETHR_INLINE void
ethr_native_write_unlock(ethr_native_rwlock_t *lock)
{
    ETHR_ASSERT(ETHR_NRWSPN_AOP__(read)(lock) == ETHR_WLOCK_FLAG__);
    ETHR_NRWSPN_AOP__(set_relb)(lock, 0);
}

static ETHR_INLINE void
ethr_native_write_lock(ethr_native_rwlock_t *lock)
{
    ethr_sint32_t act, exp = 0;
    while (1) {
	act = ETHR_NRWSPN_AOP__(cmpxchg_acqb)(lock, exp|ETHR_WLOCK_FLAG__, exp);
	if (act == exp)
	    break;
	/* Wait for writer to leave */
	while (act & ETHR_WLOCK_FLAG__) {
	    ETHR_SPIN_BODY;
	    act = ETHR_NRWSPN_AOP__(read)(lock);
	}
	exp = act;
    }
    act |= ETHR_WLOCK_FLAG__;
    /* Wait for readers to leave */
    while (act != ETHR_WLOCK_FLAG__) {
	ETHR_SPIN_BODY;
	act = ETHR_NRWSPN_AOP__(read_acqb)(lock);
    }
    ETHR_COMPILER_BARRIER;
}

#undef ETHR_NRWSPN_AOP__

#endif

#endif

#endif