KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kigit_orphan_registry.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifndef KIGIT_ORPHAN_REGISTRY_H_
21#define KIGIT_ORPHAN_REGISTRY_H_
22
23#include <import_export.h>
24
25#include <atomic>
26#include <chrono>
27#include <condition_variable>
28#include <memory>
29#include <mutex>
30#include <string>
31#include <thread>
32#include <utility>
33#include <vector>
34
35#include <wx/log.h>
36
37#include <trace_helpers.h>
38
56{
57public:
59
61
64
85 template <typename F>
86 bool Register( const std::string& aLabel, F&& aWork )
87 {
88 auto state = std::make_shared<SHARED_STATE>();
89
90 std::lock_guard<std::mutex> lock( m_mutex );
91
92 if( m_shuttingDown )
93 return false;
94
95 reapLocked();
96
97 // Reserve the slot before starting the thread so we don't leak a
98 // joinable std::thread if vector growth throws; emplace the entry
99 // with the state already wired up and then assign m_thread.
100
101 m_entries.emplace_back();
102 ENTRY& entry = m_entries.back();
103 entry.m_label = aLabel;
104 entry.m_created = std::chrono::steady_clock::now();
105 entry.m_state = state;
106
107 try
108 {
109 entry.m_thread = std::thread(
110 [state,
111 work = std::forward<F>( aWork ),
112 label = aLabel]() mutable
113 {
114 try
115 {
116 work();
117 }
118 catch( ... )
119 {
120 wxLogTrace( traceGit,
121 "Orphan git thread [%s] threw an exception",
122 label.c_str() );
123 }
124
125 {
126 std::lock_guard<std::mutex> doneLock( state->m_doneMutex );
127 state->m_done.store( true, std::memory_order_release );
128 }
129
130 state->m_doneCv.notify_all();
131 } );
132 }
133 catch( ... )
134 {
135 m_entries.pop_back();
136 throw;
137 }
138
139 wxLogTrace( traceGit, "Registered orphan git thread [%s]", aLabel.c_str() );
140 return true;
141 }
142
148 size_t TrackedCount() const;
149
163 size_t JoinAll( std::chrono::milliseconds aTimeout );
164
165private:
167 {
168 std::atomic<bool> m_done{ false };
169 std::mutex m_doneMutex;
170 std::condition_variable m_doneCv;
171 };
172
173 struct ENTRY
174 {
175 std::thread m_thread;
176 std::string m_label;
177 std::chrono::steady_clock::time_point m_created;
178 std::shared_ptr<SHARED_STATE> m_state;
179 };
180
181 // Remove finished entries by joining their threads. Must be called
182 // with m_mutex held.
183 void reapLocked();
184
185 mutable std::mutex m_mutex;
186 std::vector<ENTRY> m_entries;
187 bool m_shuttingDown = false;
188};
189
190#endif // KIGIT_ORPHAN_REGISTRY_H_
bool Register(const std::string &aLabel, F &&aWork)
Spawn a tracked orphan thread running aWork.
KIGIT_ORPHAN_REGISTRY(const KIGIT_ORPHAN_REGISTRY &)=delete
std::vector< ENTRY > m_entries
KIGIT_ORPHAN_REGISTRY & operator=(const KIGIT_ORPHAN_REGISTRY &)=delete
const wxChar *const traceGit
Flag to enable Git debugging output.
#define APIEXPORT
Macros which export functions from a DLL/DSO.
#define F(x, y, z)
Definition md5_hash.cpp:15
std::shared_ptr< SHARED_STATE > m_state
std::chrono::steady_clock::time_point m_created
wxLogTrace helper definitions.