summaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite/20_util/synchronized_pool_resource/multithreaded.cc
blob: d01d65a3bc6d6df22b8a341cfee197020e99d77b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// Copyright (C) 2018 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3.  If not see
// <http://www.gnu.org/licenses/>.

// { dg-do run }
// { dg-options "-std=gnu++17 -pthread" }
// { dg-require-effective-target c++17 }
// { dg-require-effective-target pthread }
// { dg-require-gthreads "" }

#include <memory_resource>
#include <future>
#include <testsuite_allocator.h>
#include <testsuite_hooks.h>

void
test01()
{
  __gnu_test::memory_resource test_mr;
  std::pmr::synchronized_pool_resource smr(&test_mr);

  const std::size_t largest_pool = smr.options().largest_required_pool_block;

  auto do_alloc = [&smr](void*& p, size_t n) {
    // perform some other allocations and deallocations on the same thread:
    void* p2 = smr.allocate(n);
    smr.deallocate(p2, n);
    p2 = smr.allocate(n);
    p = smr.allocate(n);
    smr.deallocate(p2, n);
  };
  auto do_dealloc = [&smr](void* p, size_t n) { smr.deallocate(p, n); };

  void* p1;
  void* p2;
  void* p3;
  auto f1 = std::async(std::launch::async, do_alloc, std::ref(p1), 8);
  auto f2 = std::async(std::launch::async, do_alloc, std::ref(p2), 64);
  auto f3 = std::async(std::launch::async, do_alloc, std::ref(p3),
		       largest_pool* 2);

  f1.get();
  f2.get();
  f3.get();
  VERIFY( p1 != nullptr );
  VERIFY( p2 != nullptr );
  VERIFY( p3 != nullptr );
  size_t nallocs = test_mr.number_of_active_allocations();
  VERIFY( nallocs >= 4 );

  // deallocate on different threads from allocation:
  f1 = std::async(std::launch::async, do_dealloc, p1, 8);
  f2 = std::async(std::launch::async, do_dealloc, p2, 64);
  f1.get();
  f2.get();
  // No additional memory is allocated by deallocating on new threads:
  VERIFY( test_mr.number_of_active_allocations() == nallocs );

  // Deallocate large unpooled allocation:
  f3 = std::async(std::launch::async, do_dealloc, p3, largest_pool * 2);
  f3.get();
  // The large allocation should have been returned upstream:
  VERIFY( test_mr.number_of_active_allocations() == nallocs - 1 );

  smr.release();
  VERIFY( test_mr.number_of_active_allocations() == 0 );
}

int
main()
{
  test01();
}