The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

parcel Lucy;

/** Provide atomic memory operations.
 */
inert class Lucy::Util::Atomic { }

__C__

/** Compare and swap a pointer.  Test whether the value at <code>target</code>
 * matches <code>old_value</code>.  If it does, set <code>target</code> to
 * <code>new_value</code> and return true.  Otherwise, return false.
 */
static CHY_INLINE chy_bool_t
lucy_Atomic_cas_ptr(void *volatile *target, void *old_value, void *new_value);

/************************** Single threaded *******************************/
#ifdef LUCY_NOTHREADS

static CHY_INLINE chy_bool_t
lucy_Atomic_cas_ptr(void *volatile *target, void *old_value, void *new_value) {
    if (*target == old_value) {
        *target = new_value;
        return true;
    }
    else {
        return false;
    }
}

/************************** Mac OS X 10.4 and later ***********************/
#elif defined(CHY_HAS_OSATOMIC_CAS_PTR)
#include <libkern/OSAtomic.h>

static CHY_INLINE chy_bool_t
lucy_Atomic_cas_ptr(void *volatile *target, void *old_value, void *new_value) {
    return OSAtomicCompareAndSwapPtr(old_value, new_value, target);
}

/********************************** Windows *******************************/
#elif defined(CHY_HAS_WINDOWS_H)

chy_bool_t
lucy_Atomic_wrapped_cas_ptr(void *volatile *target, void *old_value,
                            void *new_value);

static CHY_INLINE chy_bool_t
lucy_Atomic_cas_ptr(void *volatile *target, void *old_value, void *new_value) {
    return lucy_Atomic_wrapped_cas_ptr(target, old_value, new_value);
}

/**************************** Solaris 10 and later ************************/
#elif defined(CHY_HAS_SYS_ATOMIC_H)
#include <sys/atomic.h>

static CHY_INLINE chy_bool_t
lucy_Atomic_cas_ptr(void *volatile *target, void *old_value, void *new_value) {
    return atomic_cas_ptr(target, old_value, new_value) == old_value;
}

/************************ Fall back to pthread.h. **************************/
#elif defined(CHY_HAS_PTHREAD_H)
#include <pthread.h>

extern pthread_mutex_t lucy_Atomic_mutex;

static CHY_INLINE chy_bool_t
lucy_Atomic_cas_ptr(void *volatile *target, void *old_value, void *new_value) {
    pthread_mutex_lock(&lucy_Atomic_mutex);
    if (*target == old_value) {
        *target = new_value;
        pthread_mutex_unlock(&lucy_Atomic_mutex);
        return true;
    }
    else {
        pthread_mutex_unlock(&lucy_Atomic_mutex);
        return false;
    }
}

/******************** No support for atomics at all. ***********************/
#else

#error "No support for atomic operations."

#endif // Big platform if-else chain.

#ifdef LUCY_USE_SHORT_NAMES
  #define Atomic_cas_ptr lucy_Atomic_cas_ptr
#endif

__END_C__