1 /* atomic.c : perform atomic initialization
3 * ====================================================================
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
20 * ====================================================================
24 #include "private/svn_atomic.h"
26 /* Magic values for atomic initialization */
27 #define SVN_ATOMIC_UNINITIALIZED 0
28 #define SVN_ATOMIC_START_INIT 1
29 #define SVN_ATOMIC_INIT_FAILED 2
30 #define SVN_ATOMIC_INITIALIZED 3
33 svn_atomic__init_once(volatile svn_atomic_t *global_status,
34 svn_error_t *(*init_func)(void*,apr_pool_t*),
38 /* !! Don't use localizable strings in this function, because these
39 !! might cause deadlocks. This function can be used to initialize
40 !! libraries that are used for generating error messages. */
42 /* We have to call init_func exactly once. Because APR
43 doesn't have statically-initialized mutexes, we implement a poor
44 man's spinlock using svn_atomic_cas. */
45 svn_atomic_t status = svn_atomic_cas(global_status,
46 SVN_ATOMIC_START_INIT,
47 SVN_ATOMIC_UNINITIALIZED);
49 if (status == SVN_ATOMIC_UNINITIALIZED)
51 svn_error_t *err = init_func(baton, pool);
55 /* Tell other threads that the initialization failed. */
56 svn_atomic_cas(global_status,
57 SVN_ATOMIC_INIT_FAILED,
58 SVN_ATOMIC_START_INIT);
60 return svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, err,
61 "Couldn't perform atomic initialization");
63 svn_atomic_cas(global_status,
64 SVN_ATOMIC_INITIALIZED,
65 SVN_ATOMIC_START_INIT);
68 /* Wait for whichever thread is performing initialization to finish. */
69 /* XXX FIXME: Should we have a maximum wait here, like we have in
70 the Windows file IO spinner? */
71 else while (status != SVN_ATOMIC_INITIALIZED)
73 if (status == SVN_ATOMIC_INIT_FAILED)
74 return svn_error_create(SVN_ERR_ATOMIC_INIT_FAILURE, NULL,
75 "Couldn't perform atomic initialization");
77 apr_sleep(APR_USEC_PER_SEC / 1000);
78 status = svn_atomic_cas(global_status,
79 SVN_ATOMIC_UNINITIALIZED,
80 SVN_ATOMIC_UNINITIALIZED);
82 #endif /* APR_HAS_THREADS */