• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / nikola.irinchev_589

03 Jan 2025 09:14AM UTC coverage: 91.542%. First build
nikola.irinchev_589

Pull #8061

Evergreen

nirinchev
Reverse some unnecessary reverts
Pull Request #8061: Revert e003bda

68480 of 128056 branches covered (53.48%)

1 of 3 new or added lines in 1 file covered. (33.33%)

136282 of 148873 relevant lines covered (91.54%)

3213695.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

2.33
/src/realm/util/thread.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2016 Realm Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 **************************************************************************/
18

19
#include <realm/util/thread.hpp>
20
#include <realm/util/backtrace.hpp>
21

22
#include <cstring>
23
#include <stdexcept>
24
#include <system_error>
25

26
#if !defined _WIN32
27
#include <unistd.h>
28
#endif
29

30
// "Process shared mutexes" are not officially supported on Android,
31
// but they appear to work anyway.
32
#if (defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED > 0) || REALM_ANDROID
33
#define REALM_HAVE_PTHREAD_PROCESS_SHARED
34
#endif
35

36
// Unfortunately Older Ubuntu releases such as 10.04 reports support
37
// for robust mutexes by setting _POSIX_THREADS = 200809L and
38
// _POSIX_THREAD_PROCESS_SHARED = 200809L even though they do not
39
// provide pthread_mutex_consistent(). See also
40
// http://www.gnu.org/software/gnulib/manual/gnulib.html#pthread_005fmutex_005fconsistent.
41
// Support was added to glibc 2.12, so we disable for earlier versions
42
// of glibs
43
#ifdef REALM_HAVE_PTHREAD_PROCESS_SHARED
44
#if !defined _WIN32 // 'robust' not supported by our windows pthreads port
45
#if _POSIX_THREADS >= 200809L
46
#ifdef __GNU_LIBRARY__
47
#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 12 && !REALM_ANDROID
48
#define REALM_HAVE_ROBUST_PTHREAD_MUTEX
49
#endif
50
#elif !REALM_ANDROID
51
#define REALM_HAVE_ROBUST_PTHREAD_MUTEX
52
#endif
53
#endif
54
#endif
55
#endif
56

57

58
using namespace realm;
59
using namespace realm::util;
60

61
void Thread::set_name(const std::string& name)
62
{
16✔
63
#if defined _GNU_SOURCE && !REALM_ANDROID && !REALM_PLATFORM_APPLE && !defined(__EMSCRIPTEN__)
64
    const size_t max = 16;
65
    size_t n = name.size();
66
    if (n > max - 1)
67
        n = max - 1;
68
    char name_2[max];
69
    std::copy(name.data(), name.data() + n, name_2);
70
    name_2[n] = '\0';
71
    pthread_t id = pthread_self();
72
    int r = pthread_setname_np(id, name_2);
73
    if (REALM_UNLIKELY(r != 0))
74
        throw std::system_error(r, std::system_category(), "pthread_setname_np() failed");
75
#elif REALM_PLATFORM_APPLE
76
    int r = pthread_setname_np(name.data());
77
    if (REALM_UNLIKELY(r != 0))
16✔
NEW
78
        throw std::system_error(r, std::system_category(), "pthread_setname_np() failed");
×
79
#else
80
    static_cast<void>(name);
81
#endif
82
}
16✔
83

84

85
bool Thread::get_name(std::string& name) noexcept
86
{
×
NEW
87
#if (defined _GNU_SOURCE && !REALM_ANDROID && !defined(__EMSCRIPTEN__)) || REALM_PLATFORM_APPLE
×
88
    const size_t max = 64;
×
89
    char name_2[max];
×
90
    pthread_t id = pthread_self();
×
91
    int r = pthread_getname_np(id, name_2, max);
×
92
    if (REALM_UNLIKELY(r != 0)) {
×
93
        return false;
×
94
    }
×
95
    name_2[max - 1] = '\0';              // Eliminate any risk of buffer overrun in strlen().
×
96
    name.assign(name_2, strlen(name_2)); // Throws
×
97
    return true;
×
98
#else
99
    static_cast<void>(name);
100
    return false;
101
#endif
102
}
×
103

104

105
void Mutex::init_as_process_shared(bool robust_if_available)
106
{
×
107
#ifdef REALM_HAVE_PTHREAD_PROCESS_SHARED
×
108
    pthread_mutexattr_t attr;
×
109
    int r = pthread_mutexattr_init(&attr);
×
110
    if (REALM_UNLIKELY(r != 0))
×
111
        attr_init_failed(r);
×
112
    r = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
×
113
    REALM_ASSERT(r == 0);
×
114
#ifdef REALM_HAVE_ROBUST_PTHREAD_MUTEX
115
    if (robust_if_available) {
116
        r = pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
117
        REALM_ASSERT(r == 0);
118
    }
119
#else // !REALM_HAVE_ROBUST_PTHREAD_MUTEX
120
    static_cast<void>(robust_if_available);
×
121
#endif
×
122
    r = pthread_mutex_init(&m_impl, &attr);
×
123
    int r2 = pthread_mutexattr_destroy(&attr);
×
124
    REALM_ASSERT(r2 == 0);
×
125
    if (REALM_UNLIKELY(r != 0))
×
126
        init_failed(r);
×
127
#else // !REALM_HAVE_PTHREAD_PROCESS_SHARED
128
    static_cast<void>(robust_if_available);
129
    throw util::runtime_error("No support for process-shared mutexes");
130
#endif
131
}
×
132

133
REALM_NORETURN void Mutex::init_failed(int err)
134
{
×
135
    switch (err) {
×
136
        case ENOMEM:
×
137
            throw util::bad_alloc();
×
138
        default:
×
139
            throw std::system_error(err, std::system_category(), "pthread_mutex_init() failed");
×
140
    }
×
141
}
×
142

143
REALM_NORETURN void Mutex::attr_init_failed(int err)
144
{
×
145
    switch (err) {
×
146
        case ENOMEM:
×
147
            throw util::bad_alloc();
×
148
        default:
×
149
            throw std::system_error(err, std::system_category(), "pthread_mutexattr_init() failed");
×
150
    }
×
151
}
×
152

153
REALM_NORETURN void Mutex::destroy_failed(int err) noexcept
154
{
×
155
    if (err == EBUSY)
×
156
        REALM_TERMINATE("Destruction of mutex in use");
157
    REALM_TERMINATE("pthread_mutex_destroy() failed");
158
}
×
159

160

161
REALM_NORETURN void Mutex::lock_failed(int err) noexcept
162
{
×
163
    switch (err) {
×
164
        case EDEADLK:
×
165
            REALM_TERMINATE("pthread_mutex_lock() failed: Recursive locking of mutex (deadlock)");
166
        case EINVAL:
×
167
            REALM_TERMINATE("pthread_mutex_lock() failed: Invalid mutex object provided");
168
        case EAGAIN:
×
169
            REALM_TERMINATE("pthread_mutex_lock() failed: Maximum number of recursive locks exceeded");
170
        default:
×
171
            REALM_TERMINATE("pthread_mutex_lock() failed");
172
    }
×
173
}
×
174

175

176
bool RobustMutex::low_level_lock()
177
{
×
178
#ifdef _WIN32
179
    REALM_ASSERT_RELEASE(false);
180
#else
181
    int r = pthread_mutex_lock(&m_impl);
×
182
    if (REALM_LIKELY(r == 0))
×
183
        return true;
×
184
#ifdef REALM_HAVE_ROBUST_PTHREAD_MUTEX
185
    if (r == EOWNERDEAD)
186
        return false;
187
    if (r == ENOTRECOVERABLE)
188
        throw NotRecoverable();
189
#endif
190
    lock_failed(r);
×
191
#endif // _WIN32
×
192
}
×
193

194
int RobustMutex::try_low_level_lock()
195
{
×
196
#ifdef _WIN32
197
    REALM_ASSERT_RELEASE(false);
198
#else
199
    int r = pthread_mutex_trylock(&m_impl);
×
200
    if (REALM_LIKELY(r == 0))
×
201
        return 1;
×
202
    if (r == EBUSY)
×
203
        return 0;
×
204
#ifdef REALM_HAVE_ROBUST_PTHREAD_MUTEX
205
    if (r == EOWNERDEAD)
206
        return -1;
207
    if (r == ENOTRECOVERABLE)
208
        throw NotRecoverable();
209
#endif
210
    lock_failed(r);
×
211
#endif // _WIN32
×
212
}
×
213

214
bool RobustMutex::is_valid() noexcept
215
{
×
216
#ifdef _WIN32
217
    REALM_ASSERT_RELEASE(false);
218
#else
219
    // FIXME: This check tries to lock the mutex, and only unlocks it if the
220
    // return value is zero. If pthread_mutex_trylock() fails with EOWNERDEAD,
221
    // this leads to deadlock during the following propper attempt to lock. This
222
    // cannot be fixed by also unlocking on failure with EOWNERDEAD, because
223
    // that would mark the mutex as consistent again and prevent the expected
224
    // notification.
225
    int r = pthread_mutex_trylock(&m_impl);
×
226
    if (r == 0) {
×
227
        r = pthread_mutex_unlock(&m_impl);
×
228
        REALM_ASSERT(r == 0);
×
229
        return true;
×
230
    }
×
231
    return r != EINVAL;
×
232
#endif
×
233
}
×
234

235

236
void RobustMutex::mark_as_consistent() noexcept
237
{
×
238
#ifdef REALM_HAVE_ROBUST_PTHREAD_MUTEX
239
    int r = pthread_mutex_consistent(&m_impl);
240
    REALM_ASSERT(r == 0);
241
#endif
242
}
×
243

244

245
CondVar::CondVar(process_shared_tag)
246
{
×
247
#ifdef REALM_HAVE_PTHREAD_PROCESS_SHARED
×
248
    pthread_condattr_t attr;
×
249
    int r = pthread_condattr_init(&attr);
×
250
    if (REALM_UNLIKELY(r != 0))
×
251
        attr_init_failed(r);
×
252
    r = pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
×
253
    REALM_ASSERT(r == 0);
×
254
    r = pthread_cond_init(&m_impl, &attr);
×
255
    int r2 = pthread_condattr_destroy(&attr);
×
256
    REALM_ASSERT(r2 == 0);
×
257
    if (REALM_UNLIKELY(r != 0))
×
258
        init_failed(r);
×
259
#else
260
    throw util::runtime_error("No support for process-shared condition variables");
261
#endif
262
}
×
263

264
REALM_NORETURN void CondVar::init_failed(int err)
265
{
×
266
    switch (err) {
×
267
        case ENOMEM:
×
268
            throw util::bad_alloc();
×
269
        default:
×
270
            throw std::system_error(err, std::system_category(), "pthread_cond_init() failed");
×
271
    }
×
272
}
×
273

274
void CondVar::handle_wait_error(int err)
275
{
×
276
    switch (err) {
×
277
#ifdef REALM_HAVE_ROBUST_PTHREAD_MUTEX
278
        case ENOTRECOVERABLE:
279
            throw RobustMutex::NotRecoverable();
280
        case EOWNERDEAD:
281
            return;
282
#endif
283
        case EINVAL:
×
284
            REALM_TERMINATE("pthread_cond_wait()/pthread_cond_timedwait() failed: Invalid argument provided");
285
        case EPERM:
×
286
            REALM_TERMINATE("pthread_cond_wait()/pthread_cond_timedwait() failed:"
287
                            "Mutex not owned by calling thread");
×
288
        default:
×
289
            REALM_TERMINATE("pthread_cond_wait()/pthread_cond_timedwait() failed");
290
    }
×
291
}
×
292

293
REALM_NORETURN void CondVar::attr_init_failed(int err)
294
{
×
295
    switch (err) {
×
296
        case ENOMEM:
×
297
            throw util::bad_alloc();
×
298
        default:
×
299
            throw std::system_error(err, std::system_category(), "pthread_condattr_init() failed");
×
300
    }
×
301
}
×
302

303
REALM_NORETURN void CondVar::destroy_failed(int err) noexcept
304
{
×
305
    if (err == EBUSY)
×
306
        REALM_TERMINATE("Destruction of condition variable in use");
307
    REALM_TERMINATE("pthread_cond_destroy() failed");
308
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc