KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kigit_orphan_registry.cpp
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, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26
28
29
31{
32 // Any remaining entries represent threads we could not join during
33 // shutdown. Detach them so the OS can clean them up rather than calling
34 // std::thread's destructor on a joinable thread (which would terminate
35 // the process). The per-thread SHARED_STATE is ref-counted and outlives
36 // this registry, so the worker can still safely signal completion.
37
38 std::lock_guard<std::mutex> lock( m_mutex );
39
40 for( ENTRY& entry : m_entries )
41 {
42 if( entry.m_thread.joinable() )
43 entry.m_thread.detach();
44 }
45
46 m_entries.clear();
47}
48
49
51{
52 std::lock_guard<std::mutex> lock( m_mutex );
53 size_t count = 0;
54
55 for( const ENTRY& entry : m_entries )
56 {
57 if( !entry.m_state->m_done.load( std::memory_order_acquire ) )
58 ++count;
59 }
60
61 return count;
62}
63
64
65size_t KIGIT_ORPHAN_REGISTRY::JoinAll( std::chrono::milliseconds aTimeout )
66{
67 const auto deadline = std::chrono::steady_clock::now() + aTimeout;
68
69 // Close the registry so Register() rejects late arrivals, then move
70 // pending entries out and release m_mutex while we wait.
71
72 std::vector<ENTRY> pending;
73
74 {
75 std::lock_guard<std::mutex> lock( m_mutex );
76 m_shuttingDown = true;
77 pending = std::move( m_entries );
78 }
79
80 size_t stuck = 0;
81
82 for( ENTRY& entry : pending )
83 {
84 std::shared_ptr<SHARED_STATE> state = entry.m_state;
85
86 std::unique_lock<std::mutex> doneLock( state->m_doneMutex );
87
88 bool finished = state->m_doneCv.wait_until( doneLock, deadline,
89 [&state]()
90 {
91 return state->m_done.load(
92 std::memory_order_acquire );
93 } );
94
95 doneLock.unlock();
96
97 if( finished )
98 {
99 if( entry.m_thread.joinable() )
100 entry.m_thread.join();
101 }
102 else
103 {
104 wxLogTrace( traceGit,
105 "Orphan git thread [%s] did not finish in time; detaching",
106 entry.m_label.c_str() );
107
108 if( entry.m_thread.joinable() )
109 entry.m_thread.detach();
110
111 ++stuck;
112 }
113 }
114
115 return stuck;
116}
117
118
120{
121 for( auto it = m_entries.begin(); it != m_entries.end(); )
122 {
123 if( it->m_state->m_done.load( std::memory_order_acquire ) )
124 {
125 if( it->m_thread.joinable() )
126 it->m_thread.join();
127
128 it = m_entries.erase( it );
129 }
130 else
131 {
132 ++it;
133 }
134 }
135}
std::vector< ENTRY > m_entries
size_t JoinAll(std::chrono::milliseconds aTimeout)
Join all registered orphan threads, giving them up to aTimeout to finish cooperatively.
size_t TrackedCount() const
Return the number of tracked orphan threads that have not yet finished executing.
const wxChar *const traceGit
Flag to enable Git debugging output.