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

STEllAR-GROUP / hpx / #882

31 Aug 2023 07:44PM UTC coverage: 41.798% (-44.7%) from 86.546%
#882

push

19442 of 46514 relevant lines covered (41.8%)

126375.38 hits per line

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

75.73
/libs/full/components_base/src/server/wrapper_heap.cpp
1
//  Copyright (c) 1998-2025 Hartmut Kaiser
2
//  Copyright (c)      2011 Bryce Lelbach
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
#include <hpx/assert.hpp>
10
#include <hpx/components_base/agas_interface.hpp>
11
#include <hpx/components_base/server/wrapper_heap.hpp>
12
#include <hpx/modules/itt_notify.hpp>
13
#include <hpx/modules/logging.hpp>
14
#include <hpx/modules/synchronization.hpp>
15
#include <hpx/modules/thread_support.hpp>
16
#include <hpx/naming_base/id_type.hpp>
17

18
#include <cstddef>
19
#include <cstdint>
20
#if HPX_DEBUG_WRAPPER_HEAP != 0
21
#include <cstring>
22
#endif
23
#include <memory>
24
#include <mutex>
25
#include <new>
26
#include <string>
27
#include <type_traits>
28

29
///////////////////////////////////////////////////////////////////////////////
30
namespace hpx::components::detail {
31

32
    namespace one_size_heap_allocators {
33

34
        util::internal_allocator<char> fixed_mallocator::alloc_;
35
    }
36

37
#if HPX_DEBUG_WRAPPER_HEAP != 0
38
#define HPX_WRAPPER_HEAP_INITIALIZED_MEMORY 1
39

40
    namespace debug {
41

42
        ///////////////////////////////////////////////////////////////////////
43
        // Test memory area for being filled as expected
44
        inline bool test_fill_bytes(void* p, unsigned char c, std::size_t cnt)
45
        {
46
            unsigned char* uc = (unsigned char*) p;
47
            for (std::size_t i = 0; i < cnt; ++i)
48
            {
49
                if (*uc++ != c)
50
                {
51
                    return false;
52
                }
53
            }
54
            return true;
55
        }
56

57
        // Fill memory area
58
        inline void fill_bytes(void* p, unsigned char c, std::size_t cnt)
59
        {
60
            using namespace std;    // some systems have memset in namespace std
61
            memset(p, c, cnt);
62
        }
63
    }    // namespace debug
64
#else
65
#define HPX_WRAPPER_HEAP_INITIALIZED_MEMORY 0
66
#endif
67

68
    ///////////////////////////////////////////////////////////////////////////
69
    wrapper_heap::wrapper_heap(char const* class_name,
135✔
70
        [[maybe_unused]] std::size_t count, heap_parameters const& parameters)
135✔
71
      : parameters_(parameters)
135✔
72
      , first_free_(nullptr)
135✔
73
      , free_size_(0)
135✔
74
      , base_gid_(naming::invalid_gid)
135✔
75
      , class_name_(class_name)
76
#if defined(HPX_DEBUG)
135✔
77
      , heap_count_(count)
78
#endif
79
      , heap_alloc_function_("wrapper_heap::alloc", class_name)
80
      , heap_free_function_("wrapper_heap::free", class_name)
81
    {
82
        [[maybe_unused]] util::itt::heap_internal_access hia;
83

135✔
84
        if (!init_pool())
85
        {
86
            throw std::bad_alloc();
87
        }
135✔
88

89
        // use the pool's base address as the first gid, this will also
×
90
        // allow for the ids to be locally resolvable
91
        base_gid_ = naming::replace_locality_id(
135✔
92
            naming::replace_component_type(naming::gid_type(pool_), 0),
93
            agas::get_locality_id());
×
94

×
95
        naming::detail::set_credit_for_gid(
×
96
            base_gid_, static_cast<std::int64_t>(HPX_GLOBALCREDIT_INITIAL));
×
97
    }
×
98

99
    wrapper_heap::wrapper_heap()
100
      : first_free_(nullptr)
101
      , free_size_(0)
102
      , base_gid_(naming::invalid_gid)
103
      , heap_alloc_function_("wrapper_heap::alloc", "<unknown>")
104
      , heap_free_function_("wrapper_heap::free", "<unknown>")
105
    {
×
106
        HPX_ASSERT(false);    // shouldn't ever be called
107
    }
108

×
109
    wrapper_heap::~wrapper_heap()
110
    {
135✔
111
        [[maybe_unused]] util::itt::heap_internal_access hia;
112

113
        tidy();
114
    }
135✔
115

135✔
116
    std::size_t wrapper_heap::size() const
117
    {
135✔
118
        [[maybe_unused]] util::itt::heap_internal_access hia;
119

120
        return parameters_.capacity - free_size_;
121
    }
135✔
122

123
    std::size_t wrapper_heap::free_size() const
124
    {
×
125
        [[maybe_unused]] util::itt::heap_internal_access hia;
126

127
        return free_size_;
128
    }
×
129

130
    bool wrapper_heap::is_empty() const
131
    {
×
132
        [[maybe_unused]] util::itt::heap_internal_access hia;
133

134
        return nullptr == pool_;
135
    }
×
136

137
    bool wrapper_heap::has_allocatable_slots() const
138
    {
×
139
        [[maybe_unused]] util::itt::heap_internal_access hia;
140

141
        std::size_t const num_bytes =
142
            parameters_.capacity * parameters_.element_size;
×
143
        return first_free_ < pool_ + num_bytes;
×
144
    }
×
145

146
    bool wrapper_heap::alloc(void** result, std::size_t count)
147
    {
44,885✔
148
        [[maybe_unused]] util::itt::heap_allocate heap_allocate(
149
            heap_alloc_function_, result, count * parameters_.element_size,
150
            HPX_WRAPPER_HEAP_INITIALIZED_MEMORY);
151

152
        if (nullptr == pool_)
153
        {
44,885✔
154
            return false;
155
        }
44,885✔
156

157
        std::size_t const num_bytes = count * parameters_.element_size;
158
        std::size_t const total_num_bytes =
159
            parameters_.capacity * parameters_.element_size;
160

161
        if (first_free_ + num_bytes > pool_ + total_num_bytes)
162
        {
40,740✔
163
            return false;
164
        }
165

40,740✔
166
#if defined(HPX_DEBUG)
167
        alloc_count_ += count;
168
#endif
40,740✔
169

170
        char* p = first_free_.fetch_add(
171
            static_cast<std::ptrdiff_t>(count * parameters_.element_size),
172
            std::memory_order_relaxed);
173

174
        if (p + num_bytes > pool_ + total_num_bytes)
175
        {
40,740✔
176
            return false;
40,740✔
177
        }
178

179
#if HPX_DEBUG_WRAPPER_HEAP != 0
40,676✔
180
        // init memory blocks
181
        debug::fill_bytes(p, initial_value, count * parameters_.element_size);
182
#endif
183

184
        *result = p;
185
        return true;
186
    }
40,676✔
187

188
    void wrapper_heap::free([[maybe_unused]] void* p, std::size_t count)
189
    {
190
        [[maybe_unused]] util::itt::heap_free heap_free(heap_free_function_, p);
191

192
#if HPX_DEBUG_WRAPPER_HEAP != 0
193
        HPX_ASSERT(did_alloc(p));
194
        char* p1 = p;
195
        std::size_t const total_num_bytes =
196
            parameters_.capacity * parameters_.element_size;
197
        std::size_t const num_bytes = count * parameters_.element_size;
198

199
        HPX_ASSERT(nullptr != pool_ && p1 >= pool_);
200
        HPX_ASSERT(
201
            nullptr != pool_ && p1 + num_bytes <= pool_ + total_num_bytes);
202
        HPX_ASSERT(first_free_ == nullptr || p1 != first_free_);
203
        HPX_ASSERT(free_size_ + count <= parameters_.capacity);
204
        // make sure this has not been freed yet
205
        HPX_ASSERT(!debug::test_fill_bytes(p1, freed_value, num_bytes));
206

207
        // give memory back to pool
208
        debug::fill_bytes(p1, freed_value, num_bytes);
209
#endif
40,676✔
210

211
#if defined(HPX_DEBUG)
212
        free_count_ += count;
40,676✔
213
#endif
40,676✔
214
        size_t const current_free_size =
215
            free_size_.fetch_add(count, std::memory_order_relaxed) + count;
107,262✔
216

217
        // release the pool if this one was the last allocated item
218
        if (current_free_size == parameters_.capacity)
219
            free_pool();
220
    }
107,262✔
221

222
    bool wrapper_heap::did_alloc(void* p) const
105,360✔
223
    {
224
        // no lock is necessary here as all involved variables are immutable
225
        [[maybe_unused]] util::itt::heap_internal_access hia;
105,360✔
226

105,360✔
227
        if (nullptr == pool_)
105,360✔
228
            return false;
229
        if (nullptr == p)
230
            return false;
40,734✔
231

232
        std::size_t const total_num_bytes =
233
            parameters_.capacity * parameters_.element_size;
234
        return p >= pool_ && static_cast<char*>(p) < pool_ + total_num_bytes;
235
    }
236

237
    naming::gid_type wrapper_heap::get_gid(
238
        void* p, components::component_type type)
40,734✔
239
    {
240
        [[maybe_unused]] util::itt::heap_internal_access hia;
241

242
        HPX_ASSERT(did_alloc(p));
243
        HPX_ASSERT(base_gid_);
132✔
244

132✔
245
        naming::gid_type result = base_gid_;
132✔
246
        if (type)
247
        {
248
            result = naming::replace_component_type(result, type);
249
        }
250
        result.set_lsb(p);
251

252
        // We have to assume this credit was split as otherwise the gid returned
253
        // at this point will control the lifetime of the component.
254
        naming::detail::set_credit_split_mask_for_gid(result);
255

256
        return result;
257
    }
258

259
    void wrapper_heap::set_gid(naming::gid_type const& g)
260
    {
40,734✔
261
        [[maybe_unused]] util::itt::heap_internal_access hia;
262

263
        std::unique_lock l(mtx_);
×
264
        base_gid_ = g;
265
    }
266

267
    bool wrapper_heap::free_pool()
×
268
    {
×
269
        HPX_ASSERT(pool_);
×
270

271
        // unbind in AGAS service
40,676✔
272
        if (base_gid_)
273
        {
40,676✔
274
            naming::gid_type base_gid = naming::invalid_gid;
275
            {
276
                std::unique_lock l(mtx_);
277
                if (base_gid_)
278
                {
40,676✔
279
                    base_gid = base_gid_;
40,676✔
280
                    base_gid_ = naming::invalid_gid;
281
                }
40,676✔
282
            }
9,118✔
283
            if (base_gid)
284
                agas::unbind_range_local(base_gid, parameters_.capacity);
285
        }
286

287
        tidy();
288
        return true;
289
    }
290

291
    bool wrapper_heap::init_pool()
292
    {
293
        HPX_ASSERT(first_free_ == nullptr);
294

9✔
295
        std::size_t const total_num_bytes =
296
            parameters_.capacity * parameters_.element_size;
297
        pool_ = static_cast<char*>(allocator_type::alloc(total_num_bytes));
9✔
298
        if (nullptr == pool_)
299
        {
300
            return false;
9✔
301
        }
9✔
302

303
        if (reinterpret_cast<std::size_t>(pool_) %
304
                parameters_.element_alignment ==
44,885✔
305
            0)
306
        {
44,885✔
307
            first_free_.store(pool_, std::memory_order_relaxed);
308
        }
309
        else
310
        {
311
            first_free_.store(pool_ + parameters_.element_alignment,
44,885✔
312
                std::memory_order_relaxed);
44,885✔
313
        }
44,885✔
314

315
        free_size_.store(parameters_.capacity, std::memory_order_release);
44,885✔
316

317
        LOSH_(info).format("wrapper_heap ({}): init_pool ({}) size: {}.",
4,145✔
318
            !class_name_.empty() ? class_name_.c_str() : "<Unknown>",
319
            static_cast<void*>(pool_), total_num_bytes);
320

321
        return true;
322
    }
135✔
323

324
    void wrapper_heap::tidy()
325
    {
326
        if (pool_ != nullptr)
135✔
327
        {
135✔
328
            LOSH_(debug)
135✔
329
                    .format("wrapper_heap ({})",
135✔
330
                        !class_name_.empty() ? class_name_.c_str() :
331
                                               "<Unknown>")
332
#if defined(HPX_DEBUG)
333
                    .format(": releasing heap: alloc count: {}, free "
334
                            "count: {}",
270✔
335
                        alloc_count_, free_count_)
135✔
336
#endif
135✔
337
                << ".";
338

339
            if (wrapper_heap::size() > 0
340
#if defined(HPX_DEBUG)
135✔
341
                || alloc_count_ != free_count_
342
#endif
135✔
343
            )
×
344
            {
×
345
                LOSH_(warning).format("wrapper_heap ({}): releasing heap ({}) "
346
                                      "with {} allocated object(s)!",
347
                    !class_name_.empty() ? class_name_.c_str() : "<Unknown>",
348
                    static_cast<void*>(pool_), wrapper_heap::size());
349
            }
144✔
350

351
            std::size_t const total_num_bytes =
144✔
352
                parameters_.capacity * parameters_.element_size;
353
            allocator_type::free(pool_, total_num_bytes);
135✔
354
            pool_ = nullptr;
355

×
356
            first_free_.store(nullptr, std::memory_order_relaxed);
357
            free_size_.store(0, std::memory_order_release);
358
        }
359
    }
360

361
    // make sure the ABI of this is stable across configurations
362
#if defined(HPX_DEBUG)
363
    std::size_t wrapper_heap::heap_count() const
364
    {
135✔
365
        return heap_count_;
366
    }
367
#else
368
    std::size_t wrapper_heap::heap_count() const
369
    {
370
        return 0;
32✔
371
    }
372
#endif
×
373
}    // namespace hpx::components::detail
×
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