1 /* Copyright (C) 2002 The gtkmm Development Team
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <glibmmconfig.h>
18 #ifndef GLIBMM_DISABLE_DEPRECATED
19
20 #include <glibmm/threadpool.h>
21 #include <glibmm/exceptionhandler.h>
22 #include <glibmm/threads.h>
23 #include <glib.h>
24 #include <list>
25
26 namespace Glib
27 {
28
29 // internal
30 class ThreadPool::SlotList
31 {
32 public:
33 SlotList();
34 ~SlotList() noexcept;
35
36 // noncopyable
37 SlotList(const ThreadPool::SlotList&) = delete;
38 ThreadPool::SlotList& operator=(const ThreadPool::SlotList&) = delete;
39
40 sigc::slot<void>* push(const sigc::slot<void>& slot);
41 sigc::slot<void> pop(sigc::slot<void>* slot_ptr);
42
43 void lock_and_unlock();
44
45 private:
46 Glib::Threads::Mutex mutex_;
47 std::list<sigc::slot<void>> list_;
48 };
49
SlotList()50 ThreadPool::SlotList::SlotList()
51 {
52 }
53
~SlotList()54 ThreadPool::SlotList::~SlotList() noexcept
55 {
56 }
57
58 sigc::slot<void>*
push(const sigc::slot<void> & slot)59 ThreadPool::SlotList::push(const sigc::slot<void>& slot)
60 {
61 Threads::Mutex::Lock lock(mutex_);
62
63 list_.emplace_back(slot);
64 return &list_.back();
65 }
66
67 sigc::slot<void>
pop(sigc::slot<void> * slot_ptr)68 ThreadPool::SlotList::pop(sigc::slot<void>* slot_ptr)
69 {
70 sigc::slot<void> slot;
71
72 {
73 Threads::Mutex::Lock lock(mutex_);
74
75 std::list<sigc::slot<void>>::iterator pslot = list_.begin();
76 while (pslot != list_.end() && slot_ptr != &*pslot)
77 ++pslot;
78
79 if (pslot != list_.end())
80 {
81 slot = *pslot;
82 list_.erase(pslot);
83 }
84 }
85
86 return slot;
87 }
88
89 void
lock_and_unlock()90 ThreadPool::SlotList::lock_and_unlock()
91 {
92 mutex_.lock();
93 mutex_.unlock();
94 }
95
96 } // namespace Glib
97
98 namespace
99 {
100
101 static void
call_thread_entry_slot(void * data,void * user_data)102 call_thread_entry_slot(void* data, void* user_data)
103 {
104 try
105 {
106 Glib::ThreadPool::SlotList* const slot_list =
107 static_cast<Glib::ThreadPool::SlotList*>(user_data);
108
109 sigc::slot<void> slot(slot_list->pop(static_cast<sigc::slot<void>*>(data)));
110
111 slot();
112 }
113 catch (Glib::Threads::Thread::Exit&)
114 {
115 // Just exit from the thread. The Thread::Exit exception
116 // is our sane C++ replacement of g_thread_exit().
117 }
118 catch (...)
119 {
120 Glib::exception_handlers_invoke();
121 }
122 }
123
124 } // anonymous namespace
125
126 namespace Glib
127 {
128
ThreadPool(int max_threads,bool exclusive)129 ThreadPool::ThreadPool(int max_threads, bool exclusive)
130 : gobject_(nullptr), slot_list_(new SlotList())
131 {
132 GError* error = nullptr;
133
134 gobject_ = g_thread_pool_new(&call_thread_entry_slot, slot_list_, max_threads, exclusive, &error);
135
136 if (error)
137 {
138 delete slot_list_;
139 slot_list_ = nullptr;
140 Glib::Error::throw_exception(error);
141 }
142 }
143
~ThreadPool()144 ThreadPool::~ThreadPool() noexcept
145 {
146 if (gobject_)
147 g_thread_pool_free(gobject_, 1, 1);
148
149 if (slot_list_)
150 {
151 slot_list_->lock_and_unlock();
152 delete slot_list_;
153 }
154 }
155
156 void
push(const sigc::slot<void> & slot)157 ThreadPool::push(const sigc::slot<void>& slot)
158 {
159 sigc::slot<void>* const slot_ptr = slot_list_->push(slot);
160
161 GError* error = nullptr;
162 g_thread_pool_push(gobject_, slot_ptr, &error);
163
164 if (error)
165 {
166 slot_list_->pop(slot_ptr);
167 Glib::Error::throw_exception(error);
168 }
169 }
170
171 void
set_max_threads(int max_threads)172 ThreadPool::set_max_threads(int max_threads)
173 {
174 GError* error = nullptr;
175 g_thread_pool_set_max_threads(gobject_, max_threads, &error);
176
177 if (error)
178 Glib::Error::throw_exception(error);
179 }
180
181 int
get_max_threads() const182 ThreadPool::get_max_threads() const
183 {
184 return g_thread_pool_get_max_threads(gobject_);
185 }
186
187 unsigned int
get_num_threads() const188 ThreadPool::get_num_threads() const
189 {
190 return g_thread_pool_get_num_threads(gobject_);
191 }
192
193 unsigned int
unprocessed() const194 ThreadPool::unprocessed() const
195 {
196 return g_thread_pool_unprocessed(gobject_);
197 }
198
199 bool
get_exclusive() const200 ThreadPool::get_exclusive() const
201 {
202 g_return_val_if_fail(gobject_ != nullptr, false);
203
204 return gobject_->exclusive;
205 }
206
207 void
shutdown(bool immediately)208 ThreadPool::shutdown(bool immediately)
209 {
210 if (gobject_)
211 {
212 g_thread_pool_free(gobject_, immediately, 1);
213 gobject_ = nullptr;
214 }
215
216 if (slot_list_)
217 {
218 slot_list_->lock_and_unlock();
219 delete slot_list_;
220 slot_list_ = nullptr;
221 }
222 }
223
224 // static
225 void
set_max_unused_threads(int max_threads)226 ThreadPool::set_max_unused_threads(int max_threads)
227 {
228 g_thread_pool_set_max_unused_threads(max_threads);
229 }
230
231 // static
232 int
get_max_unused_threads()233 ThreadPool::get_max_unused_threads()
234 {
235 return g_thread_pool_get_max_unused_threads();
236 }
237
238 // static
239 unsigned int
get_num_unused_threads()240 ThreadPool::get_num_unused_threads()
241 {
242 return g_thread_pool_get_num_unused_threads();
243 }
244
245 // static
246 void
stop_unused_threads()247 ThreadPool::stop_unused_threads()
248 {
249 g_thread_pool_stop_unused_threads();
250 }
251
252 } // namespace Glib
253
254 #endif // GLIBMM_DISABLE_DEPRECATED
255