aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/portal/handle_manager.cpp
blob: b21674fc427db471b02fdf0f5aac0b75f1fc12f0 (plain) (blame)
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "handle_manager.h"

#include <cassert>

namespace vespalib::portal {

void
HandleGuard::unlock()
{
    if (valid()) {
        _manager->unlock(_handle);
        _manager = nullptr;
        _handle = 0;
    }
}

HandleGuard::~HandleGuard()
{
    unlock();
}

//-----------------------------------------------------------------------------

HandleManager::Entry::~Entry()
{
    assert(use_cnt == 0);
    assert(wait_cnt == 0);
}

void
HandleManager::unlock(uint64_t handle)
{
    std::lock_guard guard(_lock);
    auto pos = _repo.find(handle);
    assert(pos != _repo.end());
    --pos->second.use_cnt;
    if (pos->second.should_notify()) {
        pos->second.cond.notify_all();
    }
}

HandleManager::HandleManager()
    : _lock(),
      _next_handle(1),
      _repo()
{
}

HandleManager::~HandleManager() = default;

size_t
HandleManager::size() const
{
    std::lock_guard guard(_lock);
    return _repo.size();
}

uint64_t
HandleManager::create()
{
    std::lock_guard guard(_lock);
    uint64_t handle = _next_handle++;
    _repo[handle];
    return handle;
}

HandleGuard
HandleManager::lock(uint64_t handle)
{
    std::lock_guard guard(_lock);
    auto pos = _repo.find(handle);
    if (pos == _repo.end()) {
        return HandleGuard();
    }
    if (pos->second.disable) {
        return HandleGuard();
    }
    ++pos->second.use_cnt;
    return HandleGuard(*this, handle);
}

bool
HandleManager::destroy(uint64_t handle)
{
    std::unique_lock guard(_lock);
    auto pos = _repo.find(handle);
    if (pos == _repo.end()) {
        return false;
    }
    pos->second.disable = true;
    ++pos->second.wait_cnt;
    while (pos->second.use_cnt > 0) {
        pos->second.cond.wait(guard);
    }
    --pos->second.wait_cnt;
    if (pos->second.should_erase()) {
        _repo.erase(pos);
        return true;
    }
    return false;
}

} // namespace vespalib::portal