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

STEllAR-GROUP / hpx / #855

20 Dec 2022 09:59PM UTC coverage: 86.55% (+0.04%) from 86.511%
#855

push

StellarBot
Merge #6112

6112: Modernize modules from levels 9 and 10 r=hkaiser a=hkaiser

working towards https://github.com/STEllAR-GROUP/hpx/issues/5497

Co-authored-by: Hartmut Kaiser <hartmut.kaiser@gmail.com>

185 of 185 new or added lines in 30 files covered. (100.0%)

174495 of 201611 relevant lines covered (86.55%)

1898061.31 hits per line

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

84.62
/libs/core/lock_registration/src/register_locks.cpp
1
//  Copyright (c) 2007-2022 Hartmut Kaiser
2
//  Copyright (c) 2014 Thomas Heller
3
//
4
//  SPDX-License-Identifier: BSL-1.0
5
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
6
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7

8
#include <hpx/config.hpp>
9

10
#ifdef HPX_HAVE_VERIFY_LOCKS
11
#include <hpx/assert.hpp>
12
#include <hpx/lock_registration/detail/register_locks.hpp>
13
#include <hpx/modules/errors.hpp>
14
#include <hpx/type_support/unused.hpp>
15

16
#include <cstddef>
17
#include <memory>
18
#include <string>
19
#include <utility>
20

21
///////////////////////////////////////////////////////////////////////////////
22
namespace hpx::util {
23

24
    ///////////////////////////////////////////////////////////////////////////
25
    namespace detail {
26

27
        lock_data::lock_data([[maybe_unused]] std::size_t trace_depth)
178,796,378✔
28
          : ignore_(false)
178,796,561✔
29
          , user_data_(nullptr)
178,796,561✔
30
#ifdef HPX_HAVE_VERIFY_LOCKS_BACKTRACE
31
          , backtrace_(hpx::util::trace(trace_depth))
32
#endif
33
        {
34
        }
178,796,561✔
35

36
        lock_data::lock_data(
×
37
            register_lock_data* data, [[maybe_unused]] std::size_t trace_depth)
38
          : ignore_(false)
×
39
          , user_data_(data)
×
40
#ifdef HPX_HAVE_VERIFY_LOCKS_BACKTRACE
41
          , backtrace_(hpx::detail::trace(trace_depth))
42
#endif
43
        {
44
        }
×
45

46
        lock_data::~lock_data()
535,058,819✔
47
        {
48
            delete user_data_;
535,058,819✔
49
        }
535,059,457✔
50

51
        struct held_locks_data_ptr
8,092✔
52
        {
53
            held_locks_data_ptr()
8,060✔
54
              : data_(new held_locks_data)
8,060✔
55
            {
56
            }
8,072✔
57

58
            void reinitialize()
72,645,939✔
59
            {
60
                data_.reset(new held_locks_data);
72,645,939✔
61
            }
73,234,449✔
62

63
            // note: this invalidates the stored pointer - this is intentional
64
            std::unique_ptr<held_locks_data> release() noexcept
73,642,549✔
65
            {
66
                HPX_ASSERT(!!data_);
73,642,549✔
67
                return HPX_MOVE(data_);
73,784,927✔
68
            }
69

70
            void set(std::unique_ptr<held_locks_data>&& data) noexcept
72,508,547✔
71
            {
72
                data_ = HPX_MOVE(data);
72,509,095✔
73
            }
72,509,095✔
74

75
            std::unique_ptr<held_locks_data> data_;
76
        };
77

78
        struct register_locks
79
        {
80
            using held_locks_map = held_locks_data::held_locks_map;
81

82
            static held_locks_data_ptr& get_held_locks()
731,453,395✔
83
            {
84
                static thread_local held_locks_data_ptr held_locks;
731,453,395✔
85
                if (!held_locks.data_)
750,484,059✔
86
                {
87
                    held_locks.reinitialize();
72,509,199✔
88
                }
72,509,199✔
89
                return held_locks;
742,383,363✔
90
            }
91

92
            static bool lock_detection_enabled_;
93
            static std::size_t lock_detection_trace_depth_;
94

95
            static held_locks_map& get_lock_map()
442,871,908✔
96
            {
97
                return get_held_locks().data_->map_;
442,871,908✔
98
            }
99

100
            static bool get_lock_enabled()
88,168,262✔
101
            {
102
                return get_held_locks().data_->enabled_;
88,168,262✔
103
            }
104

105
            static void set_lock_enabled(bool enable)
468,854✔
106
            {
107
                get_held_locks().data_->enabled_ = enable;
468,854✔
108
            }
468,854✔
109

110
            static bool get_ignore_all_locks()
88,174,026✔
111
            {
112
                return !get_held_locks().data_->ignore_all_locks_;
88,174,026✔
113
            }
114

115
            static void set_ignore_all_locks(bool enable)
8,776✔
116
            {
117
                get_held_locks().data_->ignore_all_locks_ = enable;
8,776✔
118
            }
8,776✔
119
        };
120

121
        bool register_locks::lock_detection_enabled_ = false;
122
        std::size_t register_locks::lock_detection_trace_depth_ =
123
            HPX_HAVE_THREAD_BACKTRACE_DEPTH;
124

125
        struct reset_lock_enabled_on_exit
126
        {
127
            reset_lock_enabled_on_exit()
234,427✔
128
              : old_value_(register_locks::get_lock_enabled())
234,427✔
129
            {
130
                register_locks::set_lock_enabled(false);
234,427✔
131
            }
234,427✔
132
            ~reset_lock_enabled_on_exit()
234,427✔
133
            {
134
                register_locks::set_lock_enabled(old_value_);
234,427✔
135
            }
234,427✔
136

137
            bool old_value_;
138
        };
139
    }    // namespace detail
140

141
    // retrieve the current thread_local data about held locks
142
    std::unique_ptr<held_locks_data> get_held_locks_data()
73,680,746✔
143
    {
144
        return detail::register_locks::get_held_locks().release();
73,681,448✔
145
    }
146

147
    // set the current thread_local data about held locks
148
    void set_held_locks_data(std::unique_ptr<held_locks_data>&& data)
72,209,014✔
149
    {
150
        detail::register_locks::get_held_locks().set(HPX_MOVE(data));
72,213,550✔
151
    }
72,213,550✔
152

153
    ///////////////////////////////////////////////////////////////////////////
154
    void enable_lock_detection() noexcept
1,221✔
155
    {
156
        detail::register_locks::lock_detection_enabled_ = true;
1,221✔
157
    }
1,221✔
158

159
    void disable_lock_detection() noexcept
×
160
    {
161
        detail::register_locks::lock_detection_enabled_ = false;
×
162
    }
×
163

164
    void trace_depth_lock_detection(std::size_t value) noexcept
1,221✔
165
    {
166
        detail::register_locks::lock_detection_trace_depth_ = value;
1,221✔
167
    }
1,221✔
168

169
    static registered_locks_error_handler_type registered_locks_error_handler;
1,251✔
170

171
    void set_registered_locks_error_handler(
1,221✔
172
        registered_locks_error_handler_type f) noexcept
173
    {
174
        registered_locks_error_handler = HPX_MOVE(f);
1,221✔
175
    }
1,221✔
176

177
    static register_locks_predicate_type register_locks_predicate;
1,251✔
178

179
    void set_register_locks_predicate(register_locks_predicate_type f) noexcept
1,221✔
180
    {
181
        register_locks_predicate = HPX_MOVE(f);
1,221✔
182
    }
1,221✔
183

184
    ///////////////////////////////////////////////////////////////////////////
185
    bool register_lock(
220,643,109✔
186
        void const* lock, util::register_lock_data* data) noexcept
187
    {
188
        using detail::register_locks;
189

190
        try
191
        {
192
            if (register_locks::lock_detection_enabled_ &&
406,895,252✔
193
                (!register_locks_predicate || register_locks_predicate()))
186,871,504✔
194
            {
195
                register_locks::held_locks_map& held_locks =
180,124,745✔
196
                    register_locks::get_lock_map();
180,612,990✔
197

198
                register_locks::held_locks_map::iterator it =
199
                    held_locks.find(lock);
180,612,990✔
200
                if (it != held_locks.end())
180,309,259✔
201
                    return false;    // this lock is already registered
1,663,037✔
202

203
                std::pair<register_locks::held_locks_map::iterator, bool> p;
178,645,233✔
204
                if (!data)
178,649,098✔
205
                {
206
                    p = held_locks.insert(std::make_pair(lock,
178,649,098✔
207
                        detail::lock_data(
178,778,882✔
208
                            register_locks::lock_detection_trace_depth_)));
178,778,882✔
209
                }
178,380,363✔
210
                else
211
                {
212
                    p = held_locks.insert(std::make_pair(lock,
×
213
                        detail::lock_data(data,
×
214
                            register_locks::lock_detection_trace_depth_)));
×
215
                }
216
                return p.second;
178,378,757✔
217
            }
218
            return true;
39,277,522✔
219
        }
×
220
        catch (...)
221
        {
222
            return false;
×
223
        }
×
224
    }
219,319,316✔
225

226
    // unregister the given lock from this HPX-thread
227
    bool unregister_lock(void const* lock) noexcept
220,084,955✔
228
    {
229
        using detail::register_locks;
230

231
        try
232
        {
233
            if (register_locks::lock_detection_enabled_ &&
405,971,893✔
234
                (!register_locks_predicate || register_locks_predicate()))
186,315,264✔
235
            {
236
                register_locks::held_locks_map& held_locks =
180,398,405✔
237
                    register_locks::get_lock_map();
180,662,788✔
238

239
                register_locks::held_locks_map::iterator it =
240
                    held_locks.find(lock);
180,662,788✔
241
                if (it == held_locks.end())
180,373,319✔
242
                    return false;    // this lock is not registered
1,685,745✔
243

244
                held_locks.erase(lock);
179,022,091✔
245
            }
179,022,778✔
246
            return true;
218,189,594✔
247
        }
×
248
        catch (...)
249
        {
250
            return false;
×
251
        }
×
252
    }
219,875,339✔
253

254
    // verify that no locks are held by this HPX-thread
255
    namespace detail {
256

257
        inline bool some_locks_are_not_ignored(
234,426✔
258
            register_locks::held_locks_map const& held_locks) noexcept
259
        {
260
            using iterator = register_locks::held_locks_map::const_iterator;
261

262
            iterator end = held_locks.end();
234,427✔
263
            for (iterator it = held_locks.begin(); it != end; ++it)
468,934✔
264
            {
265
                //lock_data const& data = *(*it).second;
266
                if (!it->second.ignore_)
234,508✔
267
                    return true;
×
268
            }
234,508✔
269

270
            return false;
234,426✔
271
        }
234,426✔
272
    }    // namespace detail
273

274
    void verify_no_locks()
88,181,078✔
275
    {
276
        using detail::register_locks;
277

278
        bool enabled = register_locks::get_ignore_all_locks() &&
176,504,639✔
279
            register_locks::get_lock_enabled();
88,323,561✔
280

281
        if (enabled && register_locks::lock_detection_enabled_ &&
176,804,357✔
282
            (!register_locks_predicate || register_locks_predicate()))
88,557,924✔
283
        {
284
            register_locks::held_locks_map& held_locks =
84,639,283✔
285
                register_locks::get_lock_map();
84,639,283✔
286

287
            // we create a log message if there are still registered locks for
288
            // this OS-thread
289
            if (!held_locks.empty())
84,639,283✔
290
            {
291
                // Temporarily disable verifying locks in case verify_no_locks
292
                // gets called recursively.
293
                detail::reset_lock_enabled_on_exit e;
234,426✔
294

295
                if (detail::some_locks_are_not_ignored(held_locks))
234,426✔
296
                {
297
                    if (registered_locks_error_handler)
×
298
                    {
299
                        registered_locks_error_handler();
×
300
                    }
×
301
                    else
302
                    {
303
                        HPX_THROW_EXCEPTION(hpx::error::invalid_status,
×
304
                            "verify_no_locks",
305
                            "suspending thread while at least one lock is "
306
                            "being held (default handler)");
307
                    }
308
                }
×
309
            }
234,426✔
310
        }
84,600,778✔
311
    }
88,274,577✔
312

313
    void force_error_on_lock()
5,110,077✔
314
    {
315
        // For now just do the same as during suspension. We can't reliably
316
        // tell whether there are still locks held as those could have been
317
        // acquired in a different OS thread.
318
        verify_no_locks();
5,110,077✔
319

320
        //{
321
        //    register_locks::held_locks_map const& held_locks =
322
        //       register_locks::get_lock_map();
323
        //
324
        //    // we throw an error if there are still registered locks for
325
        //    // this OS-thread
326
        //    if (!held_locks.empty()) {
327
        //        HPX_THROW_EXCEPTION(hpx::error::invalid_status,
328
        //            "force_error_on_lock",
329
        //            "At least one lock is held while thread is being "
330
        //            terminated or interrupted.");
331
        //    }
332
        //}
333
    }
5,110,095✔
334

335
    namespace detail {
336

337
        void set_ignore_status(void const* lock, bool status)
5,336,654✔
338
        {
339
            if (register_locks::lock_detection_enabled_ &&
10,673,120✔
340
                (!register_locks_predicate || register_locks_predicate()))
5,336,772✔
341
            {
342
                register_locks::held_locks_map& held_locks =
5,314,358✔
343
                    register_locks::get_lock_map();
5,314,358✔
344

345
                register_locks::held_locks_map::iterator it =
346
                    held_locks.find(lock);
5,314,358✔
347
                if (it == held_locks.end())
5,314,358✔
348
                {
349
                    // this can happen if the lock was registered to be ignore
350
                    // on a different OS thread
351
                    // HPX_THROW_EXCEPTION(
352
                    //     hpx::error::invalid_status, "set_ignore_status",
353
                    //     "The given lock has not been registered.");
354
                    return;
1,684,264✔
355
                }
356

357
                it->second.ignore_ = status;
3,630,239✔
358
            }
3,630,239✔
359
        }
5,338,346✔
360
    }    // namespace detail
361

362
    void ignore_lock(void const* lock) noexcept
2,680,512✔
363
    {
364
        try
365
        {
366
            detail::set_ignore_status(lock, true);
2,680,822✔
367
        }
2,680,822✔
368
        catch (...)
369
        {
370
        }
×
371
    }
2,680,874✔
372

373
    void reset_ignored(void const* lock) noexcept
2,658,320✔
374
    {
375
        try
376
        {
377
            detail::set_ignore_status(lock, false);
2,658,104✔
378
        }
2,658,104✔
379
        catch (...)
380
        {
381
        }
×
382
    }
2,658,106✔
383

384
    void ignore_all_locks() noexcept
4,388✔
385
    {
386
        try
387
        {
388
            detail::register_locks::set_ignore_all_locks(true);
4,388✔
389
        }
4,388✔
390
        catch (...)
391
        {
392
        }
×
393
    }
4,388✔
394

395
    void reset_ignored_all() noexcept
4,388✔
396
    {
397
        try
398
        {
399
            detail::register_locks::set_ignore_all_locks(false);
4,388✔
400
        }
4,388✔
401
        catch (...)
402
        {
403
        }
×
404
    }
4,388✔
405
}    // namespace hpx::util
406

407
#endif
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

© 2026 Coveralls, Inc