1/**
2 * @copyright
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
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
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
19 *    under the License.
20 * ====================================================================
21 * @endcopyright
22 *
23 * @file svn_mutex.h
24 * @brief Structures and functions for mutual exclusion
25 */
26
27#ifndef SVN_MUTEX_H
28#define SVN_MUTEX_H
29
30#include "svn_error.h"
31
32#ifdef __cplusplus
33extern "C" {
34#endif /* __cplusplus */
35
36/**
37 * This is a simple wrapper around @c apr_thread_mutex_t and will be a
38 * valid identifier even if APR does not support threading.
39 */
40
41/** A mutex for synchronization between threads. It may be NULL, in
42 * which case no synchronization will take place. The latter is useful
43 * when implementing some functionality with optional synchronization.
44 */
45typedef struct svn_mutex__t svn_mutex__t;
46
47/** Initialize the @a *mutex. If @a mutex_required is TRUE, the mutex will
48 * actually be created with a lifetime defined by @a result_pool. Otherwise,
49 * the pointer will be set to @c NULL and svn_mutex__lock() as well as
50 * svn_mutex__unlock() will be no-ops.
51 *
52 * We don't support recursive locks, i.e. a thread may not acquire the same
53 * mutex twice without releasing it in between.  Attempts to lock a mutex
54 * recursively will cause lock ups and other undefined behavior on some
55 * systems.
56 *
57 * If threading is not supported by APR, this function is a no-op.
58 */
59svn_error_t *
60svn_mutex__init(svn_mutex__t **mutex,
61                svn_boolean_t mutex_required,
62                apr_pool_t *result_pool);
63
64/** Acquire the @a mutex, if that has been enabled in svn_mutex__init().
65 * Make sure to call svn_mutex__unlock() some time later in the same
66 * thread to release the mutex again. Recursive locking are not supported.
67 *
68 * @note You should use #SVN_MUTEX__WITH_LOCK instead of explicit lock
69 * acquisition and release.
70 */
71svn_error_t *
72svn_mutex__lock(svn_mutex__t *mutex);
73
74/** Release the @a mutex, previously acquired using svn_mutex__lock()
75 * that has been enabled in svn_mutex__init().
76 *
77 * Since this is often used as part of the calling function's exit
78 * sequence, we accept that function's current return code in @a err.
79 * If it is not #SVN_NO_ERROR, it will be used as the return value -
80 * irrespective of the possible internal failures during unlock. If @a err
81 * is #SVN_NO_ERROR, internal failures of this function will be
82 * reported in the return value.
83 *
84 * @note You should use #SVN_MUTEX__WITH_LOCK instead of explicit lock
85 * acquisition and release.
86 */
87svn_error_t *
88svn_mutex__unlock(svn_mutex__t *mutex,
89                  svn_error_t *err);
90
91/** Acquires the @a mutex, executes the expression @a expr and finally
92 * releases the @a mutex. If any of these steps fail, the function using
93 * this macro will return an #svn_error_t. This macro guarantees that
94 * the @a mutex will always be unlocked again if it got locked successfully
95 * by the first step.
96 *
97 * @note Prefer using this macro instead of explicit lock acquisition and
98 * release.
99 */
100#define SVN_MUTEX__WITH_LOCK(mutex, expr)               \
101do {                                                    \
102  svn_mutex__t *svn_mutex__m = (mutex);                 \
103  SVN_ERR(svn_mutex__lock(svn_mutex__m));               \
104  SVN_ERR(svn_mutex__unlock(svn_mutex__m, (expr)));     \
105} while (0)
106
107#if APR_HAS_THREADS
108
109/** Return the APR mutex encapsulated in @a mutex.
110 *
111 * @note This function should only be called by APR wrapper code.
112 */
113apr_thread_mutex_t *
114svn_mutex__get(svn_mutex__t *mutex);
115
116#endif
117
118#ifdef __cplusplus
119}
120#endif /* __cplusplus */
121
122#endif /* SVN_MUTEX_H */
123