KiCad PCB EDA Suite
Loading...
Searching...
No Matches
model_import_queue.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 as published by
8 * the Free Software Foundation; either version 3 of the License, or (at your option)
9 * 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/old-licenses/gpl-3.0.html
19 */
20
22
23#include <atomic>
24#include <condition_variable>
25#include <mutex>
26#include <optional>
27#include <thread>
28#include <utility>
29
31{
33 {
34 std::atomic_bool canceled{ false };
35 };
36
37 struct JOB
38 {
39 std::string fileName;
41 std::uint64_t generation = 0;
43 };
44
46 {
47 worker = std::thread(
48 [this]
49 {
50 Run();
51 } );
52 }
53
54 std::uint64_t Submit( std::string aFileName, const MODEL_IMPORT_OPTIONS& aOptions, COMPLETION aCompletion )
55 {
56 // The displaced job is destroyed after the lock is released, because its completion can
57 // own arbitrary host state.
58 std::optional<JOB> displaced;
59 std::uint64_t submitted = 0;
60
61 {
62 std::lock_guard<std::mutex> lock( mutex );
63
64 if( !stopping )
65 {
67 activeCancellation->canceled = true;
68
69 submitted = ++generation;
70 displaced = std::move( pending );
71 pending = JOB{ std::move( aFileName ), aOptions, submitted, std::move( aCompletion ) };
72 }
73 }
74
75 if( submitted )
76 condition.notify_one();
77
78 return submitted;
79 }
80
81 void Cancel()
82 {
83 std::lock_guard<std::mutex> lock( mutex );
84 pending.reset();
85
87 activeCancellation->canceled = true;
88 }
89
90 void Stop()
91 {
92 std::lock_guard<std::mutex> stopLock( stopMutex );
93
94 {
95 std::lock_guard<std::mutex> lock( mutex );
96
97 if( !stopping )
98 {
99 stopping = true;
100 pending.reset();
101
103 activeCancellation->canceled = true;
104 }
105 }
106
107 condition.notify_one();
108
109 if( worker.joinable() )
110 worker.join();
111 }
112
113 void Run() noexcept
114 {
115 try
116 {
117 for( ;; )
118 {
119 JOB job;
120 std::shared_ptr<CANCELLATION> cancellation = std::make_shared<CANCELLATION>();
121
122 {
123 std::unique_lock<std::mutex> lock( mutex );
124 condition.wait( lock,
125 [this]
126 {
127 return stopping || pending.has_value();
128 } );
129
130 if( stopping )
131 return;
132
133 job = std::move( *pending );
134 pending.reset();
135 activeCancellation = cancellation;
136 }
137
138 Process( std::move( job ), cancellation );
139 }
140 }
141 catch( ... )
142 {
143 std::lock_guard<std::mutex> lock( mutex );
144 activeCancellation.reset();
145 stopping = true;
146 pending.reset();
147 }
148 }
149
150 void Process( JOB aJob, const std::shared_ptr<CANCELLATION>& aCancellation ) noexcept
151 {
152 aJob.options.cancellationContext = aCancellation.get();
153 aJob.options.isCanceled = []( void* aContext ) noexcept
154 {
155 return static_cast<CANCELLATION*>( aContext )->canceled.load();
156 };
157
158 MODEL_IMPORT_RESULT result = ImportModel( aJob.fileName, aJob.options );
159
160 {
161 std::lock_guard<std::mutex> lock( mutex );
162 activeCancellation.reset();
163
164 if( stopping )
165 return;
166 }
167
168 try
169 {
170 aJob.completion( aJob.generation, std::move( result ) );
171 }
172 catch( ... )
173 {
174 }
175 }
176
177 std::mutex stopMutex;
178 std::mutex mutex;
179 std::condition_variable condition;
180 std::optional<JOB> pending;
181 std::shared_ptr<CANCELLATION> activeCancellation;
182 std::uint64_t generation = 0;
183 bool stopping = false;
184 std::thread worker;
185};
186
187
192
193
198
199
200std::uint64_t S3D::MODEL_IMPORT_QUEUE::Submit( std::string aFileName, const MODEL_IMPORT_OPTIONS& aOptions,
201 COMPLETION aCompletion )
202{
203 return m_state->Submit( std::move( aFileName ), aOptions, std::move( aCompletion ) );
204}
205
206
208{
209 m_state->Cancel();
210}
211
212
214{
215 m_state->Stop();
216}
217
218
220{
221 std::lock_guard<std::mutex> lock( m_state->mutex );
222 return m_state->generation;
223}
void Cancel()
Abandon the pending and running requests without stopping the worker.
std::function< void(std::uint64_t aGeneration, MODEL_IMPORT_RESULT aResult)> COMPLETION
void Shutdown()
Abandon everything and join the worker.
std::uint64_t Submit(std::string aFileName, const MODEL_IMPORT_OPTIONS &aOptions, COMPLETION aCompletion)
Supersede any pending or running request with aFileName.
std::uint64_t CurrentGeneration() const
The generation of the most recent Submit(), for hosts that track staleness themselves.
std::shared_ptr< STATE > m_state
KICAD_3D_IMPORT_API MODEL_IMPORT_RESULT ImportModel(const std::string &aFileName, const MODEL_IMPORT_OPTIONS &aOptions={}) noexcept
Import and flatten one model without invoking GUI facilities.
STL namespace.
std::shared_ptr< CANCELLATION > activeCancellation
std::uint64_t Submit(std::string aFileName, const MODEL_IMPORT_OPTIONS &aOptions, COMPLETION aCompletion)
void Process(JOB aJob, const std::shared_ptr< CANCELLATION > &aCancellation) noexcept
wxString result
Test unit parsing edge cases and error handling.