ThreadViewer.cpp
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* ArmarX is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License version 2 as
6* published by the Free Software Foundation.
7*
8* ArmarX is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16* @package ArmarX::
17* @author Mirko Waechter ( mirko.waechter at kit dot edu)
18* @date 2013
19* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
22
23#include "ThreadViewer.h"
24
26
27#include <QSettings>
28
32
33#include <ArmarXGui/gui-plugins/SystemStateMonitorPlugin/ui_ThreadViewer.h>
34
35#include "ProgressbarDelegate.h"
36#include "RunningTaskModel.h"
37#include "ThreadViewerModel.h"
38
39namespace armarx
40{
42 periodicTaskModel(0), runningTaskModel(0), ui(new Ui::ThreadViewer)
43
44 {
45 ui->setupUi(getWidget());
46
47 periodicTaskModel = new ThreadViewerModel(getWidget());
48
49 ui->threadListView->setModel(periodicTaskModel);
50 ui->threadListView->setItemDelegateForColumn(3,
51 new ProgressbarDelegate(ui->threadListView));
52
53 // No setColumnWidth() here: setResizeMode(Stretch) discards fixed widths
54 // (issue #64.14d).
55 ui->threadListView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
56
57 runningTaskModel = new RunningTaskModel(getWidget());
58
59 ui->runningTaskView->setModel(runningTaskModel);
60 ui->runningTaskView->setItemDelegateForColumn(
61 2, new ProgressbarDelegate(ui->runningTaskView));
62
63 ui->runningTaskView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
64
65 QFont font;
66 font.setPointSize(8);
67 ui->threadListView->setFont(font);
68 ui->runningTaskView->setFont(font);
69
70 connect(this,
71 SIGNAL(threadManagerListUpdated(QStringList)),
72 this,
73 SLOT(updateThreadManagerList(QStringList)));
74 connect(this, SIGNAL(cpuUsageValueUpdated(int)), this, SLOT(cpuUsageValueSet(int)));
75 connect(ui->cbThreadListManager,
76 SIGNAL(currentIndexChanged(QString)),
77 this,
78 SLOT(managedSelectionChanged(QString)));
79 connect(ui->btnRefresh, SIGNAL(clicked()), this, SLOT(triggerThreadManagerListUpdate()));
80 }
81
83 {
84 delete ui;
85 }
86
87 void
88 ThreadViewer::loadSettings(QSettings* settings)
89 {
90 // Restore the previously selected thread-manager; applied in
91 // updateThreadManagerList() once the list has been populated (issue #64.14f).
92 restoredSelection = settings->value("ThreadViewer/selectedManager").toString();
93 }
94
95 void
96 ThreadViewer::saveSettings(QSettings* settings)
97 {
98 settings->setValue("ThreadViewer/selectedManager", ui->cbThreadListManager->currentText());
99 }
100
101 void
105
106 void
108 {
109
111 periodicTask =
112 new PeriodicTask<ThreadViewer>(this, &ThreadViewer::runThreadManagerUpdate, 500);
113 periodicTask->start();
114 }
115
116 void
118 {
119 if (periodicTask)
120 {
121 periodicTask->stop();
122 }
123
124 if (managerUpdateTask)
125 {
126 managerUpdateTask->stop();
127 }
128 }
129
130 void
132 {
133 if (managerUpdateTask && managerUpdateTask->isRunning())
134 {
135 return;
136 }
137
138 ui->btnRefresh->setEnabled(false);
139 ui->btnRefresh->setToolTip("Refreshing manager list...please wait");
140 managerUpdateTask =
142 managerUpdateTask->start();
143 }
144
145 void
147 {
148 std::vector<std::string> managerList;
149 QStringList qManagerList;
150
151 try
152 {
153 if (getIceManager() && getIceManager()->getIceGridSession())
154 managerList = getIceManager()
155 ->getIceGridSession()
156 ->getRegisteredObjectNames<ThreadListInterfacePrx>("*ThreadList");
157
158 for (unsigned int i = 0; i < managerList.size(); ++i)
159 {
160 qManagerList << QString::fromStdString(managerList.at(i));
161 }
162 }
163 catch (...)
164 {
165 // Do not rethrow: this runs in a RunningTask body, where an escaping
166 // exception would tear down the task thread (issue #64.14e). The emit
167 // re-enables the refresh button.
168 emit threadManagerListUpdated(qManagerList);
169 return;
170 }
171
172 emit threadManagerListUpdated(qManagerList);
173 }
174
175 void
177 {
178 const QString lastSelectionText = ui->cbThreadListManager->currentText();
179 ui->cbThreadListManager->clear();
180 ui->cbThreadListManager->addItems(list);
181
182 // A still-pending persisted selection takes priority until its manager actually
183 // appears in the list - it may not have been registered on the first refresh
184 // (issue #64.14f). Once applied, clear it so later refreshes (and the user's own
185 // choices) are respected.
186 int index = -1;
187 if (!restoredSelection.isEmpty())
188 {
189 index = ui->cbThreadListManager->findText(restoredSelection);
190 if (index >= 0)
191 {
192 restoredSelection.clear();
193 }
194 }
195 if (index < 0)
196 {
197 index = ui->cbThreadListManager->findText(lastSelectionText);
198 }
199
200 // >= 0, not > 0: index 0 is a valid entry that the old check silently dropped
201 // (issue #64.14c).
202 if (index >= 0)
203 {
204 ui->cbThreadListManager->setCurrentIndex(index);
205 }
206
207 ui->btnRefresh->setEnabled(true);
208 ui->btnRefresh->setToolTip("Refresh the thread manager list");
209 }
210
211 void
213 {
214 if (selectedString.size() == 0)
215 {
216 return;
217 }
218
219 // Resolve the proxy without holding proxyMutex: getProxy() can block, and holding
220 // the lock across it would stall the periodic update task, freezing the GUI on a
221 // drop-down change (issue #64.14a).
222 auto proxy = getProxy<ThreadListInterfacePrx>(selectedString.toStdString());
223 {
224 std::unique_lock lock(proxyMutex);
225 threadManagerProxy = proxy;
226 }
227 ARMARX_VERBOSE << "new proxy for ThreadViewerModel set: " << selectedString;
228 }
229
230 void
232 {
233
234 ui->cpuUsageProgressBar->setValue(value);
235 }
236
237 void
238 ThreadViewer::runThreadManagerUpdate()
239 {
240 // Copy the proxy under the lock, then release it before any blocking Ice call so
241 // managedSelectionChanged() (GUI thread) never waits on this task's network I/O
242 // (issue #64.14a).
243 ThreadListInterfacePrx proxy;
244 {
245 std::unique_lock lock(proxyMutex);
246 proxy = threadManagerProxy;
247 }
248
249 if (!proxy)
250 {
251 return;
252 }
253
254 try
255 {
256 PeriodicTaskList periodicTaskList = proxy->getPeriodicTasks();
257 RunningTaskList runningTaskList = proxy->getRunningTasks();
258 Ice::Double cpuProcTotalTime = proxy->getCpuUsage();
259 int value = static_cast<int>(cpuProcTotalTime);
260
261 // Qt models must be mutated on the GUI thread; this runs on a PeriodicTask
262 // worker thread (issue #64.8). Target `this` (the controller, which the lambda
263 // dereferences), not getWidget(): Qt cancels a queued call whose target object
264 // is destroyed, so targeting the object the lambda uses avoids a use-after-free.
266 this,
267 [this, periodicTaskList, runningTaskList]()
268 {
269 periodicTaskModel->setPeriodicTaskListData(periodicTaskList);
270 runningTaskModel->setRunningTaskListData(runningTaskList);
271 });
272 emit cpuUsageValueUpdated(value);
273 }
274 catch (...)
275 {
276 // The component may have gone away between ticks. Swallow all Ice exceptions;
277 // the old code caught only three types, so TimeoutException,
278 // ConnectionRefusedException, CloseConnectionException etc. escaped the
279 // PeriodicTask callback (issue #64.14b).
280 }
281 }
282} // namespace armarx
uint8_t index
virtual QPointer< QWidget > getWidget()
getWidget returns a pointer to the a widget of this controller.
IceManagerPtr getIceManager() const
Returns the IceManager.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
The periodic task executes one thread method repeatedly using the time period specified in the constr...
void onInitComponent() override
void managedSelectionChanged(QString selectedString)
void loadSettings(QSettings *settings) override
Load stored manager models.
void saveSettings(QSettings *settings) override
Saves the manager models.
void updateThreadManagerList(QStringList list)
void cpuUsageValueUpdated(int value)
void triggerThreadManagerListUpdate()
void onConnectComponent() override
void threadManagerListUpdated(QStringList list)
void onExitComponent() override
Hook for subclass.
void cpuUsageValueSet(int value)
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:185
ArmarX Headers.
This file offers overloads of toIce() and fromIce() functions for STL container types.
void postToObject(QObject *context, Function &&function)
Run function on the GUI (main) thread's event loop.
std::shared_ptr< Value > value()
Definition cxxopts.hpp:855