Alien-SVN
view release on metacpan or search on metacpan
src/subversion/subversion/libsvn_subr/named_atomic.c view on Meta::CPAN
/*
* svn_named_atomic.c: routines for machine-wide named atomics.
*
* ====================================================================
* 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.
* ====================================================================
*/
#include "private/svn_named_atomic.h"
#include <apr_global_mutex.h>
#include <apr_mmap.h>
#include "svn_private_config.h"
#include "private/svn_atomic.h"
#include "private/svn_mutex.h"
#include "svn_pools.h"
#include "svn_dirent_uri.h"
#include "svn_io.h"
/* Implementation aspects.
*
* We use a single shared memory block (memory mapped file) that will be
* created by the first user and merely mapped by all subsequent ones.
* The memory block contains an short header followed by a fixed-capacity
* array of named atomics. The number of entries currently in use is stored
* in the header part.
*
* Finding / creating the MMAP object as well as adding new array entries
* is being guarded by an APR global mutex. Since releasing the MMAP
* structure and closing the underlying does not affect other users of the
* same, cleanup will not be synchronized.
*
* The array is append-only. Once a process mapped the block into its
* address space, it may freely access any of the used entries. However,
* it must synchronize access to the volatile data within the entries.
* On Windows and where otherwise supported by GCC, lightweight "lock-free"
* synchronization will be used. Other targets serialize all access using
* a global mutex.
*
* Atomics will be identified by their name (a short string) and lookup
* takes linear time. But even that takes only about 10 microseconds for a
* full array scan -- which is in the same order of magnitude than e.g. a
* single global mutex lock / unlock pair.
*/
/* Capacity of our shared memory object, i.e. max number of named atomics
* that may be created. Should have the form 2**N - 1.
*/
#define MAX_ATOMIC_COUNT 1023
/* We choose the size of a single named atomic object to fill a complete
* cache line (on most architectures). Thereby, we minimize the cache
* sync. overhead between different CPU cores.
*/
#define CACHE_LINE_LENGTH 64
/* We need 8 bytes for the actual value and the remainder is used to
* store the NUL-terminated name.
*
* Must not be smaller than SVN_NAMED_ATOMIC__MAX_NAME_LENGTH.
*/
#define MAX_NAME_LENGTH (CACHE_LINE_LENGTH - sizeof(apr_int64_t) - 1)
/* Particle that will be appended to the namespace name to form the
* name of the mutex / lock file used for that namespace.
*/
#define MUTEX_NAME_SUFFIX ".mutex"
/* Particle that will be appended to the namespace name to form the
* name of the shared memory file that backs that namespace.
*/
#define SHM_NAME_SUFFIX ".shm"
/* Platform-dependent implementations of our basic atomic operations.
* NA_SYNCHRONIZE(op) will ensure that the OP gets executed atomically.
* This will be zero-overhead if OP itself is already atomic.
*
* (We don't call it SYNCHRONIZE because Windows has a preprocess macro by
* that name.)
*
* The default implementation will use the same mutex for initialization
* as well as any type of data access. This is quite expensive and we
* can do much better on most platforms.
*/
#if defined(WIN32) && ((_WIN32_WINNT >= 0x0502) || defined(InterlockedExchangeAdd64))
/* Interlocked API / intrinsics guarantee full data synchronization
*/
#define synched_read(mem) *mem
#define synched_write(mem, value) InterlockedExchange64(mem, value)
#define synched_add(mem, delta) InterlockedExchangeAdd64(mem, delta)
#define synched_cmpxchg(mem, value, comperand) \
InterlockedCompareExchange64(mem, value, comperand)
#define NA_SYNCHRONIZE(_atomic,op) op;
#define NA_SYNCHRONIZE_IS_FAST TRUE
#elif SVN_HAS_ATOMIC_BUILTINS
/* GCC provides atomic intrinsics for most common CPU types
*/
#define synched_read(mem) *mem
#define synched_write(mem, value) __sync_lock_test_and_set(mem, value)
#define synched_add(mem, delta) __sync_add_and_fetch(mem, delta)
#define synched_cmpxchg(mem, value, comperand) \
__sync_val_compare_and_swap(mem, comperand, value)
#define NA_SYNCHRONIZE(_atomic,op) op;
#define NA_SYNCHRONIZE_IS_FAST TRUE
#else
/* Default implementation
*/
static apr_int64_t
synched_read(volatile apr_int64_t *mem)
{
return *mem;
}
static apr_int64_t
synched_write(volatile apr_int64_t *mem, apr_int64_t value)
{
apr_int64_t old_value = *mem;
*mem = value;
return old_value;
}
static apr_int64_t
synched_add(volatile apr_int64_t *mem, apr_int64_t delta)
{
return *mem += delta;
}
static apr_int64_t
synched_cmpxchg(volatile apr_int64_t *mem,
apr_int64_t value,
apr_int64_t comperand)
{
apr_int64_t old_value = *mem;
if (old_value == comperand)
*mem = value;
return old_value;
}
( run in 0.784 second using v1.01-cache-2.11-cpan-d7f47b0818f )