kwave  18.07.70
WorkerThread.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  libkwave/WorkerThread.cpp - worker thread for Kwave
3  -------------------
4  begin : Sun Apr 06 2008
5  copyright : (C) 2008 by Thomas Eschenbacher
6  email : Thomas.Eschenbacher@gmx.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "config.h"
19 
20 #include <signal.h>
21 #include <stdio.h>
22 
23 #include <QApplication>
24 #include <QtGlobal> // for qWarning()
25 
26 #undef DEBUG_FIND_DEADLOCKS
27 #ifdef DEBUG_FIND_DEADLOCKS
28 #include <execinfo.h> // for backtrace()
29 #endif
30 #include <errno.h>
31 
32 #include "libkwave/Runnable.h"
33 #include "libkwave/WorkerThread.h"
34 
36 #define MAX_ATTEMPTS_TO_STOP 8
37 
39 static bool g_signal_handler_is_in_place = false;
40 
41 //***************************************************************************
42 extern "C" void _dummy_SIGHUP_handler(int);
43 
44 //***************************************************************************
46 {
47  printf("\r\n--- SIGHUP ---\r\n");
48 }
49 
50 //***************************************************************************
52  :QThread(Q_NULLPTR),
53  m_runnable(runnable),
54  m_params(params),
55  m_lock(), m_lock_sighup(),
56  m_should_stop(0),
57  m_tid(pthread_self()),
58  m_owner_tid(pthread_self())
59 {
60  /* NOTE: we assume that this gets called from the GUI thread only */
61  Q_ASSERT(this->thread() == QThread::currentThread());
62  Q_ASSERT(this->thread() == qApp->thread());
63 
64  /* install handler for SIGHUP */
66  /*
67  * NOTE: the old signal handler is lost. But as long as we do not use
68  * SIGHUP in any other place of the application and we need to
69  * have a dummy handler only, that should not matter
70  */
71  signal(SIGHUP, _dummy_SIGHUP_handler);
73  }
74 }
75 
76 //***************************************************************************
78 {
79  if (isRunning()) {
80  qDebug("WorkerThread::~WorkerThread(): waiting for normal shutdown");
81  wait(2000);
82  qDebug("WorkerThread::~WorkerThread(): stopping");
83  stop(2000);
84  }
85  Q_ASSERT(!isRunning());
86 }
87 
88 //***************************************************************************
90 {
91  QMutexLocker lock(&m_lock);
92 
93  // reset the "should stop" command flag
94  m_should_stop = 0;
95 
96  QThread::start();
97 }
98 
99 //***************************************************************************
100 int Kwave::WorkerThread::stop(unsigned int timeout)
101 {
102  QMutexLocker lock(&m_lock);
103  if (!isRunning()) return 0; // already down
104 
105  if (timeout < 1000) timeout = 1000;
106 
107  // set the "should stop" flag
108  m_should_stop = 1;
109 
110  // send one SIGHUP in advance
111  {
112  QMutexLocker _lock(&m_lock_sighup);
113  if (!pthread_equal(m_tid, m_owner_tid))
114  pthread_kill(m_tid, SIGHUP);
115  if (!isRunning()) return 0;
116  }
117 
118  // try to stop cooperatively
119  if (!isRunning()) return 0;
120  wait(timeout/10);
121  if (!isRunning()) return 0;
122 
123  // try to interrupt by HUP signal
124  qWarning("WorkerThread::stop(): sending SIGHUP");
125  for (unsigned int i = 0; i < MAX_ATTEMPTS_TO_STOP; i++) {
126  {
127  QMutexLocker _lock(&m_lock_sighup);
128  if (!isRunning()) return 0;
129  if (!pthread_equal(m_tid, m_owner_tid))
130  pthread_kill(m_tid, SIGHUP);
131  }
132  if (!isRunning()) return 0;
133  wait(timeout/10);
134  if (!isRunning()) return 0;
135  }
136 
137 #ifdef DEBUG_FIND_DEADLOCKS
138  if (running()) {
139  qDebug("WorkerThread::stop(): pthread_self()=%08X",
140  (unsigned int)pthread_self());
141  void *buf[256];
142  size_t n = backtrace(buf, 256);
143  backtrace_symbols_fd(buf, n, 2);
144  }
145 #endif
146 
147  qDebug("WorkerThread::stop(): canceling thread");
148  terminate();
149 
150  return -1;
151 }
152 
153 //***************************************************************************
155 {
156  Q_ASSERT(m_runnable);
157  if (!m_runnable) return;
158 
159  /* get the POSIX thread ID, needed for sending SIGHUP */
160  {
161  QMutexLocker _lock(&m_lock_sighup);
162  m_tid = pthread_self();
163  }
164 
165  /* call the run(...) function */
167 
168  /* avoid sending any SIGHUP by setting the m_tid to "invalid" */
169  {
170  QMutexLocker _lock(&m_lock_sighup);
171  m_tid = m_owner_tid;
172  }
173 }
174 
175 //***************************************************************************
177 {
178  m_should_stop = 1;
179 }
180 
181 //***************************************************************************
183 {
184  return (m_should_stop);
185 }
186 
187 //***************************************************************************
188 //***************************************************************************
WorkerThread(Kwave::Runnable *runnable, QVariant params)
static bool g_signal_handler_is_in_place
#define MAX_ATTEMPTS_TO_STOP
virtual void run_wrapper(const QVariant &params)=0
virtual void cancel()
void _dummy_SIGHUP_handler(int)
virtual int stop(unsigned int timeout=10000)
virtual void start()
virtual void run() Q_DECL_OVERRIDE
Kwave::Runnable * m_runnable
Definition: WorkerThread.h:80
QAtomicInt m_should_stop
Definition: WorkerThread.h:92
virtual ~WorkerThread() Q_DECL_OVERRIDE