I'm trying to build an automated testing against my simulated FreeRTOS device
Gtest is running in the main thread, the FreeRTOS Simulation is started from the main Thread within a new std::thread.
The challenge is, that the FreeRTOS Simulation might start several threads as well.
The GTest main thread and the freertos simulation thread communicate via a TCP/IP localhost socket with each other (on a real device this can easily replaced by another socket). For a better overview this is not shown in this demo.
int main(int argc,char *argv[])
{
::testing::InitGoogleTest(&argc, argv);
int res = RUN_ALL_TESTS();
return res;
}
and my testsuite looks like this
#include <gtest/gtest.h>
#include <iostream>
#include <memory>
#include <thread>
#include <FreeRTOS.h>
#include <task.h>
#ifdef WIN32
#include <Windows.h>
#endif //WIN32
class TestFixture : public ::testing::Test
{
protected:
///the Running Simulation
static std::unique_ptr<std::thread> m_pSim;
/**
* #brief Setup this whole testsuite =>only launch Sim once (and not in every test)
*/
static void SetUpTestSuite();
/**
* #brief Trys to kill freertos (Freertos is not designed to be stopped once running)
*/
static void TearDownTestSuite();
};
std::unique_ptr<std::thread> TestFixture::m_pSim;
void TestFixture::SetUpTestSuite()
{
//launch FreeRTOS_Demo starts some FreeRTOS Tasks and calls vTaskStartScheduler()
m_pSim = std::make_unique<std::thread>(&LaunchFreeRTOS_Demo);
}
void TestFixture::TearDownTestSuite()
{
if (m_pSim)
{
/*
* FreeRTOS is not designed to be stopped once started
* detaching the thread will hopefully enable the OS to properly delete the
* FreeRTOS Thread
* */
//stop all running threads
const auto vecTaskInfo = getAllRunningFreeRTOSTasks();
for (const auto& singleTask : vecTaskInfo)
{
vTaskSuspend(singleTask.xHandle);
vTaskDelete(singleTask.xHandle);
}
vTaskSuspendAll();
auto natitveHandle = m_pSim->native_handle();
m_pSim->detach();
if (natitveHandle)
{
#ifdef WIN32
TerminateThread(natitveHandle, 99);
#endif // WIN32
}
}
}
TEST_F(TestFixture, Foo)
{
std::cout << "Running Testclient" << std::endl;
EXPECT_TRUE(true);
}
So my Question: how can I terminate the Test and get the results from GTest. I do not need to shutdown freertos properly since this executable is closed after the test.
What did I try so far:
I tried not to actually close freertos (I left out the
TearDownTestSuite() part)). =>GTest Thread exit properly but the
program seamed to be endlessly waiting for the FreeRTOS Tasks to
terminate. Program does not quit.
The TearDown() Solution posted above =>FreeRTOS Tasks still seam to
be running. Program does not quit
could you help me out here? I know that shooting running threads down is not a nice thing to do, but since freertos is designed as an embedded application it is not designed to be terminated.
Related
I am developing a multithreaded ROS application involving Qt::QThread-inherited objects producing signals triggering ROS publishers in the ROS node activated in the main() function. Qt signals and the event loop are handled by Qt::QCoreApplication How can one properly organize the connection between the application objects and runner functions? In the ordinary application Qt::QCoreApplication.exec() and ros::spin() functions are blocking.
The solution is quite easy. It is needed to install SIGINT signal handler function that will control the sequence of starting and stopping event loops:
// POSIX signal handler prototype section
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
// Qt section
#include <QCoreApplication>
// ROS section
#include <ros/ros.h>
// SIGINT handler function
void handle_shutdown(int s)
{
ROS_INFO("Shutting down node...");
ros::shutdown(); // Step 1: stopping ROS event loop
QCoreApplication::exit(0); // Step 2: stopping Qt event loop
}
int main(int argc, char** args)
{
// SIGINT handler setup
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = handle_shutdown;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
// Instantiating Qt application object
QCoreApplication app(argc, args);
// Instantiating ROS node object
ros::init(argc, args, "witmotion_ros", ros::InitOption::NoSigintHandler);
ros::NodeHandler node("~");
// Running ROS non-blocking event loop
ros::AsyncSpinner spinner(2);
spinner.start();
// Running Qt event loop: blocking call
int result = app.exec();
// Waiting for signal handler's return
ros::waitForShutdown();
// Exit code: from Qt
return result;
}
The option ros::InitOption::NoSigintHandler instructs ROS application object to skip the installation of its own SIGINT handler. This kind of setup allows using freely both Qt signals, events and ROS callbacks without mutual blocks and race conditions. However, the code model is not totally thread-safe, so it is mandatory to handle synchronization of the data in case of bidirectional exchange.
I believe I've found a bug in the Windows' Qt 5 implementation. It doesn't reproduce with Qt 6, so I don't think I should post it to Qt's maintainers now. But still I'd like to ask here (1) if it's a bug indeed (or is my code just incorrect somewhere), and (2) what workaround can I write to avoid this issue, provided that I can't upgrade to Qt 6 right now.
I have a class BackgroundExecutor which owns a QThread and has a function for posting new tasks (std::function instances) to it. In its destructor, BackgroundExecutor calls quit and wait member functions of its thread object.
Things get interesting when one of the posted tasks processed by the background QThread happens to have executed some external QProcess (I think it affects the state of the thread's QEventLoop somehow). In this case, the wait call on a QThread has a chance to hang forever.
The call stack of the main thread looks like this:
ntdll.dll!NtWaitForSingleObject() Unknown
KernelBase.dll!WaitForSingleObjectEx() Unknown
> Qt5Cored.dll!QThread::wait(QDeadlineTimer deadline) Line 630 C++
QThreadAndQProcessBug.exe!BackgroundExecutor::~BackgroundExecutor() Line 87 C++
QThreadAndQProcessBug.exe!RunTest() Line 123 C++
QThreadAndQProcessBug.exe!RunTestMultipleTimes() Line 132 C++
And here's the call stack of the background thread:
win32u.dll!NtUserMsgWaitForMultipleObjectsEx() Unknown
user32.dll!RealMsgWaitForMultipleObjectsEx() Unknown
> Qt5Cored.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 625 C++
Qt5Cored.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 140 C++
Qt5Cored.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> flags) Line 232 C++
Qt5Cored.dll!QThread::exec() Line 547 C++
Qt5Cored.dll!QThread::run() Line 617 C++
Qt5Cored.dll!QThreadPrivate::start(void * arg) Line 407 C++
It's stuck at the line 625 (as of Qt 5.15.2) of "qeventdispatcher_win.cpp", inside the QEventDispatcherWin32::processEvents function: waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);.
The full text of the program which reproduces the issue (though it might take some time - one of my PCs requires only 1000 iterations on average, while the other one might execute 100'000 iterations before the hang would occur):
#include <QCoreApplication>
#include <QTimer>
#include <QObject>
#include <QProcess>
#include <QThread>
#include <functional>
#include <future>
#include <memory>
#include <iostream>
Q_DECLARE_METATYPE(std::function<void()>); // for passing std::function<void()> through Qt's signals
static void EnsureStdFunctionOfVoidMetaTypeRegistered()
{
static std::once_flag std_function_metatype_registered{};
std::call_once(std_function_metatype_registered, []() {
qRegisterMetaType<std::function<void()>>("std::function<void()>");
});
}
class WorkerObject; // worker object that "lives" in a background thread of a BackgroundExecutor
class BackgroundExecutor final
{
public:
BackgroundExecutor();
~BackgroundExecutor();
// posts a new task for the background QThread,
// returns a std::future which can be waited on to ensure the task is done
[[nodiscard]] std::future<void> PostTask(std::function<void()> task);
private:
WorkerObject* _background_worker = nullptr;
QThread* _qt_thread = nullptr;
};
class WorkerObject final : public QObject
{
Q_OBJECT;
public:
WorkerObject()
{
connect(this, &WorkerObject::TaskPosted, this, &WorkerObject::ProcessPostedTask);
}
// can be called from any thread;
// "moves" the task to the background worker thread via Qt's signals/slots mechanism
// so that it could be processed there
void PostTask(const std::function<void()>& task)
{
EnsureStdFunctionOfVoidMetaTypeRegistered();
Q_EMIT TaskPosted(task);
}
private Q_SLOTS:
void ProcessPostedTask(const std::function<void()>& posted_task)
{
std::invoke(posted_task);
}
Q_SIGNALS:
void TaskPosted(const std::function<void()>&);
};
BackgroundExecutor::BackgroundExecutor()
{
{
std::unique_ptr<QThread> qt_thread_safe(new QThread()); // exception safety
_background_worker = new WorkerObject();
_qt_thread = qt_thread_safe.release();
}
_background_worker->moveToThread(_qt_thread);
QObject::connect(_qt_thread, &QThread::finished, _background_worker, &WorkerObject::deleteLater);
QObject::connect(_qt_thread, &QThread::finished, _qt_thread, &QThread::deleteLater);
_qt_thread->start();
}
BackgroundExecutor::~BackgroundExecutor()
{
_qt_thread->quit();
_qt_thread->wait(); // !!! might hang !!!
}
[[nodiscard]] std::future<void> BackgroundExecutor::PostTask(std::function<void()> task)
{
std::shared_ptr task_promise = std::make_shared<std::promise<void>>();
std::future task_future = task_promise->get_future();
std::function<void()> task_wrapper = [task_promise = std::move(task_promise), task = std::move(task)]()
{
std::invoke(task);
task_promise->set_value();
};
_background_worker->PostTask(task_wrapper);
return task_future;
}
static void RunQProcessAndWaitForFinished()
{
QProcess process;
process.setProgram("C:\\Windows\\System32\\cmd.exe");
process.setArguments({ "/C", "C:\\Windows\\System32\\timeout.exe", QString::number(30) });
process.start();
process.waitForStarted(-1);
process.waitForFinished(-1);
}
static void RunTest()
{
BackgroundExecutor executor;
std::future task_future = executor.PostTask([]() {
RunQProcessAndWaitForFinished();
});
task_future.get();
}
static void RunTestMultipleTimes()
{
constexpr int repeat = 500'000;
for (int i = 0; i < repeat; ++i)
{
std::cout << "starting iteration " << i << '\n';
RunTest();
}
std::cout << "all iterations finished" << '\n';
}
int main(int argc, char** argv)
{
QCoreApplication qt_app{ argc, argv };
QTimer::singleShot(
0,
[&]()
{
RunTestMultipleTimes();
qt_app.exit(0);
});
return qt_app.exec();
}
#include "main.moc"
In Qt 5.12.12, all iterations are complete. Did you try this version?
I just split classes into separate files to implicitly include the moc file and I made a .pro file.
QT += core
CONFIG += c++17 console
CONFIG -= app_bundle
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
backgroundexecutor.cpp \
main.cpp \
workerobject.cpp
HEADERS += \
backgroundexecutor.h \
workerobject.h
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
After posting this question, I also ran some tests with Qt 5.12.12 and Qt 5.15.5, as suggested in the comments. I could reproduce the bug in neither of these versions, while in Qt 5.15.2 it continues to reproduce consistently. This could either mean that the bug is really absent in these versions, or that it is much more rarely reproducible there (at least on my PCs) and I didn't try enough.
In any case, I would like to share a workaround which I came up with after consulting one of my colleagues who has more experience with WinAPI than I do. Hope it will also help someone else in the future, if they happen to be stuck with the Qt version where this bug is present.
Here's the code (you can compare it with the original listing from the question using a tool such as WinMerge, or just look at all the parts near the WORKAROUND_FOR_QTHREAD_WAIT macro):
#include <QCoreApplication>
#include <QTimer>
#include <QObject>
#include <QProcess>
#include <QThread>
#include <atomic>
#include <thread>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <cassert>
#include <iostream>
#ifdef _WIN32
#define WORKAROUND_FOR_QTHREAD_WAIT 1
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#endif // _WIN32
Q_DECLARE_METATYPE(std::function<void()>); // for passing std::function<void()> through Qt's signals
static void EnsureStdFunctionOfVoidMetaTypeRegistered()
{
static std::once_flag std_function_metatype_registered{};
std::call_once(std_function_metatype_registered, []() {
qRegisterMetaType<std::function<void()>>("std::function<void()>");
});
}
class WorkerObject; // worker object that "lives" in a background thread of a BackgroundExecutor
class BackgroundExecutor final
{
public:
BackgroundExecutor();
~BackgroundExecutor();
// posts a new task for the background QThread,
// returns a std::future which can be waited on to ensure the task is done
[[nodiscard]] std::future<void> PostTask(std::function<void()> task);
private:
WorkerObject* _background_worker = nullptr;
QThread* _qt_thread = nullptr;
};
class WorkerObject final : public QObject
{
Q_OBJECT;
public:
WorkerObject()
{
connect(this, &WorkerObject::TaskPosted, this, &WorkerObject::ProcessPostedTask);
}
// can be called from any thread;
// "moves" the task to the background worker thread via Qt's signals/slots mechanism
// so that it could be processed there
void PostTask(const std::function<void()>& task)
{
EnsureStdFunctionOfVoidMetaTypeRegistered();
Q_EMIT TaskPosted(task);
}
#if WORKAROUND_FOR_QTHREAD_WAIT
[[nodiscard]] DWORD GetBackgroundThreadID() const
{
while (_windows_thread_id_initialized.load(std::memory_order_acquire) == false)
std::this_thread::yield();
return _windows_thread_id;
}
#endif // WORKAROUND_FOR_QTHREAD_WAIT
public Q_SLOTS:
void InitializeBackgroundThreadID()
{
#if WORKAROUND_FOR_QTHREAD_WAIT
_windows_thread_id = ::GetCurrentThreadId();
_windows_thread_id_initialized.store(true, std::memory_order_release);
#else
assert(false && "shouldn't have been invoked in this configuration");
#endif // WORKAROUND_FOR_QTHREAD_WAIT
}
void ProcessPostedTask(const std::function<void()>& posted_task)
{
std::invoke(posted_task);
}
Q_SIGNALS:
void TaskPosted(const std::function<void()>&);
#if WORKAROUND_FOR_QTHREAD_WAIT
private:
DWORD _windows_thread_id;
std::atomic<bool> _windows_thread_id_initialized{ false };
#endif // WORKAROUND_FOR_QTHREAD_WAIT
};
BackgroundExecutor::BackgroundExecutor()
{
{
std::unique_ptr<QThread> qt_thread_safe(new QThread()); // exception safety
_background_worker = new WorkerObject();
_qt_thread = qt_thread_safe.release();
}
_background_worker->moveToThread(_qt_thread);
#if WORKAROUND_FOR_QTHREAD_WAIT
QMetaObject::invokeMethod(_background_worker, "InitializeBackgroundThreadID", Qt::QueuedConnection);
#endif // WORKAROUND_FOR_QTHREAD_WAIT
QObject::connect(_qt_thread, &QThread::finished, _background_worker, &WorkerObject::deleteLater);
QObject::connect(_qt_thread, &QThread::finished, _qt_thread, &QThread::deleteLater);
_qt_thread->start();
}
BackgroundExecutor::~BackgroundExecutor()
{
_qt_thread->quit();
#if WORKAROUND_FOR_QTHREAD_WAIT
const DWORD background_thread_id = _background_worker->GetBackgroundThreadID();
while (_qt_thread->wait(1'000) == false)
// "awaken" the MsgWaitForMultipleObjectsEx function call in which the background thread got stuck
// by posting a fake "message" to it, so that it would snap out of it, check its exit flag and finish properly
::PostThreadMessage(background_thread_id, WM_NULL, 0, 0);
#else
_qt_thread->wait();
#endif // WORKAROUND_FOR_QTHREAD_WAIT
}
[[nodiscard]] std::future<void> BackgroundExecutor::PostTask(std::function<void()> task)
{
std::shared_ptr task_promise = std::make_shared<std::promise<void>>();
std::future task_future = task_promise->get_future();
std::function<void()> task_wrapper = [task_promise = std::move(task_promise), task = std::move(task)]()
{
std::invoke(task);
task_promise->set_value();
};
_background_worker->PostTask(task_wrapper);
return task_future;
}
static void RunQProcessAndWaitForFinished()
{
QProcess process;
process.setProgram("C:\\Windows\\System32\\cmd.exe");
process.setArguments({ "/C", "C:\\Windows\\System32\\timeout.exe", QString::number(30) });
process.start();
process.waitForStarted(-1);
process.waitForFinished(-1);
}
static void RunTest()
{
BackgroundExecutor executor;
std::future task_future = executor.PostTask([]() {
RunQProcessAndWaitForFinished();
});
task_future.get();
}
static void RunTestMultipleTimes()
{
constexpr int repeat = 500'000;
for (int i = 0; i < repeat; ++i)
{
std::cout << "starting iteration " << i << '\n';
RunTest();
}
std::cout << "all iterations finished" << '\n';
}
int main(int argc, char** argv)
{
QCoreApplication qt_app{ argc, argv };
QTimer::singleShot(
0,
[&]()
{
RunTestMultipleTimes();
qt_app.exit(0);
});
return qt_app.exec();
}
#include "main.moc"
And now for the implementation details.
The basic idea is: the MsgWaitForMultipleObjectsEx(..., QS_ALLINPUT, ...) function call (in which the background thread gets stuck) can be "awakened" by a message posted to this thread's queue, since QS_ALLINPUT also implies QS_POSTMESSAGE as a part of its "wake mask". This can be done by calling PostThreadMessage from the destroying (main) thread in case we've detected that the background one got stuck. And since we don't care about a particular type of a message (and actually don't want to send any "meaningful" message), WM_NULL will do the trick.
So, the destructor of our BackgroundExecutor class should look like this:
BackgroundExecutor::~BackgroundExecutor()
{
_qt_thread->quit();
const DWORD background_thread_id = _background_worker->GetBackgroundThreadID();
while (_qt_thread->wait(1'000) == false)
::PostThreadMessage(background_thread_id, WM_NULL, 0, 0);
}
Now the question is, how do we get this DWORD background_thread_id value. Qt doesn't provide us an easy way of getting it from a QThread object (there is a function currentThreadId, but it is static and returns a DWORD ID of the currently executing thread, thus it's not what we want here). Instead, we will call GetCurrentThreadId from the background thread at some early point of its execution, store it in our WorkerObject, and retrieve in the main thread later.
In order to do that, we can write a new slot InitializeBackgroundThreadID in the WorkerObject class and invoke it via Qt::QueuedConnection from the BackgroundExecutor's constructor after moving the worker object to the background thread (thus ensuring that the slot will be invoked from that thread):
public Q_SLOTS:
void InitializeBackgroundThreadID()
{
_windows_thread_id = ::GetCurrentThreadId();
_windows_thread_id_initialized.store(true, std::memory_order_release);
}
(here, _windows_thread_id is a DWORD member variable of the WorkerObject, while _windows_thread_id_initialized is a std::atomic<bool> guard flag required for cross-thread synchronization via the synchronizes-with relation)
In BackgroundExecutor's constructor:
...
_background_worker->moveToThread(_qt_thread);
QMetaObject::invokeMethod(_background_worker, "InitializeBackgroundThreadID", Qt::QueuedConnection);
...
Now we can implement the getter for this thread ID:
[[nodiscard]] DWORD GetBackgroundThreadID() const
{
while (_windows_thread_id_initialized.load(std::memory_order_acquire) == false)
std::this_thread::yield();
return _windows_thread_id;
}
In practice, by the time the BackgroundExecutor's destructor is called, the thread ID will have been already initialized, so the loop won't spin or call yield at all: it is just needed to guarantee the synchronizes-with relation (the main thread will be guaranteed to read the correct value of _windows_thread_id after it has read true from _windows_thread_id_initialized via a load-acquire operation).
There can be other means of implementing this part, e.g., we could make the DWORD _windows_thread_id member variable an atomic itself, providing it some "invalid" sentry value for the "uninitialized" state (Raymond Chen once wrote zero should be okay for that). But these are just the implementation details, the basic idea still remains the same.
My program crashed and I got following message.
segfault at 10 ip 00007f5a87e1ccd1 sp 00007f5a837d0bd8 error 4 in libpthread-2.17.so[7f5a87e13000+17000]
Then I checked the position where it occurred, and it shows that the problem may occur in pthread_mutex_destroy.
[root#stock-1 tmp]# addr2line -e /lib64/libpthread.so.0 -f 0x9CD1
__GI___pthread_mutex_destroy
:?
As it's the first time I encounter this problem, and I failed to reproduce it in my developing environment, these are all the information I can get.
In this program, there is a main thread and multiple worker threads. Main thread creates worker thread and wait for worker thread to send it a message. Worker thread finishes its task and send main thread a message.
The code is as follow.
#ifndef MESSAGEQUEUE_H_
#define MESSAGEQUEUE_H_
#include <mutex>
#include <future>
#include <queue>
struct CopyResult
{
std::string mediaFile;
std::string type;
std::string status;
long long size;
int totalFileNumber = 0;
int errorType = 0;
std::string errorMessage;
};
template <class T>
class MessageQueue
{
public:
T receive()
{
std::unique_lock<std::mutex> uLock(_mutex);
_condtion.wait(uLock,[this]{return !_messages.empty();});
T msg = std::move(_messages.front());
_messages.pop_front();
return msg;
}
void send(T &&msg)
{
std::lock_guard<std::mutex> uLock(_mutex);
_messages.push_back(std::move(msg));
_condtion.notify_one();
}
private:
std::mutex _mutex;
std::condition_variable _condtion;
std::deque<T> _messages;
};
#endif
main thread
CopyResult result = queue_->receive();
worker thread
queue->send(std::move(result));
I can't figure out what's the problem. Can anyone help?
Well, my guess here without minimal reproducible example is:
You forgot to call (lets assume worker thread is called worker_thread):
if (worker_thread.joinable())
{
worker_thread.join();
}
... which leads to error when mutex is already destroyed outside of worker_thread, but you try to lock this already destroyed mutex inside the worker_thread.
That guess made on your segfault - it's mutex destruction.
P.S. Also let me suggest you run your program in debug build under GDB or similar debugger which is really usefull. It has ability to show you stack trace which may help to detect where you segfaulted and why.
I want to call a user space program from a kernel module periodically.But the kernel program is freezing the system, while I try to load it.
following is the program,
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/jiffies.h>
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/hrtimer.h>
#include <linux/sched.h>
#include <linux/delay.h>
#define TIME_PERIOD 50000
static struct hrtimer hr_timer;
static ktime_t ktime_period_ns;
static enum hrtimer_restart timer_callback(struct hrtimer *timer){
char userprog[] = "test.sh";
char *argv[] = {userprog, "2", NULL };
char *envp[] = {"HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
printk("\n Timer is running");
hrtimer_forward_now(&hr_timer, ktime_period_ns);
printk("callmodule: %s\n", userprog);
call_usermodehelper(userprog, argv, envp, UMH_WAIT_PROC);
return HRTIMER_RESTART;
}
static int __init timer_init() {
ktime_period_ns= ktime_set( 0, TIME_PERIOD);
hrtimer_init ( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
hr_timer.function = timer_callback;
hrtimer_start( &hr_timer, ktime_period_ns, HRTIMER_MODE_REL );
return 0;
}
static int __exit timer_exit(){
int cancelled = hrtimer_cancel(&hr_timer);
if (cancelled)
printk(KERN_ERR "Timer is still running\n");
else
printk(KERN_ERR "Timer is cancelled\n");
}
module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("GPL");
test.sh is a script which just echoes a comment.
I have tested the call_usermodehelper part and timer part individually and it is working fine. But while I am combining the two codes, the system hangs.
Can anybody please help me to solve the problem.
Quick look around strongly suggests that hrtimer callbacks are executed from an irq context, which is expected - how else are you going to get high resoluton?
But this also means you must no block, while your callback can block due to call_usermodehelper regardless of NOWAIT passed.
So it seems you are testing your module on a kernel with debugging disabled, which is fundamentally wrong.
But this is less relevant as the thing you are trying to achieve in the first place looks fundamentally wrong.
I can only recommend you elaborate what is the actual problem. There is absolutely now way that forking + execing has anything to do with something requiring a high resolution timer.
I was wondering how I can run a function when closing the terminal (I'm on Linux) of my Qt Console Application. I have a 'static' class which holds all the variables I need (I know I can use singleton but I like this way better) and it has a function called destroy, this will delete all pointers).
So this is my .cpp of the 'static' class:
#include "engine.h"
logging* engine::m_logging;
tcp_listener* engine::m_tcp_listener;
void engine::initialize()
{
engine::m_logging = new logging();
engine::m_logging->write_line("Initializing Fullmoon Messenger server...");
engine::m_tcp_listener = new tcp_listener();
engine::m_tcp_listener->start("127.0.0.1", 30000);
}
void engine::destroy()
{
delete engine::m_logging;
}
logging* engine::get_logging()
{
return engine::m_logging;
}
And this is my main.cpp:
#include <QCoreApplication>
#include "engine.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
engine::initialize();
return a.exec();
}
How can I call engine::destroy when closing the application? I assume there's a signal for it.
You need to handle the POSIX signal SIGHUP for this.
(Note: POSIX signals are something completely different than Qt signals, so they're not handled with "slots". Don't confuse them.)
Note that your options for what to do in a POSIX signal handler are very limited. The man page signal(7) lists the functions which are safe to be called. In the comments to this answer, Kuba Ober pointed out that you should to stick to the official documentation for handling POSIX signals in Qt applications. But since the process as explained in the documentation is quite complicated, I wrapped it in a reusable class PosixSignalProxy, converting POSIX signals to Qt signals.
If you use this proxy class you just have to write:
PosixSignalProxy<SIGHUP> sighupProxy;
QObject::connect(&sighupProxy, &PosixSignalProxyBase::receivedSignal, []{
engine::destroy();
});
The class is found at the bottom of this post.
Note that only one instance of a PosixSignalProxy can be created for each POSIX signal type. If you need to do multiple things when receiving a signal, you can however connect to the Qt signal multiple times.
Also, you might be interested in similar signals for different external reasons for quitting your application, such as killing it or hitting Ctrl+C in the terminal window.
SIGHUP (as in the example above): when the terminal window was closed (and the parent process was destroyed)
SIGINT: when the user hits Ctrl+C - Note that when you handle this signal you need to quit at the end of the handler since your process is responsible of finally quitting itself. You overwrite this default behavior and have the option not to only cleanup stuff but also to ignore the user's wish to quit the application.
SIGTERM: when the process is killed with e.g. kill (not to be confused with SIGKILL which is a more aggressive way to kill a process; you can't handle that one)
Here is the class definition:
posixsignalproxy.h
#ifndef POSIXSIGNALPROXY_H
#define POSIXSIGNALPROXY_H
#include <QObject>
class QSocketNotifier;
typedef void (*PosixSignalHandlerType) (int);
// Helper base class (no template) - Do not use this class directly.
class PosixSignalProxyBase : public QObject
{
Q_OBJECT
public:
PosixSignalProxyBase(
QObject *parent,
int (&sockets)[2],
int posixSignalNumber,
PosixSignalHandlerType posixSignalHandler,
int posixSignalFlags);
~PosixSignalProxyBase();
signals:
/**
* Qt signal which is emitted right after receiving and handling the POSIX
* signal. In the Qt signal handler (slot) you are allowed to do anything.
*/
void receivedSignal();
protected:
static void staticSignalHandler(int (&sockets)[2]);
private slots:
void handleSignal();
private:
int (&sockets)[2];
QSocketNotifier *notifier;
};
// Actual proxy class, defining its own static proxy signal handler function and sockets.
template <int signum>
class PosixSignalProxy : public PosixSignalProxyBase
{
public:
PosixSignalProxy(QObject *parent = nullptr, int posixSignalFlags = 0) :
PosixSignalProxyBase(parent, mySockets, signum, &posixSignalHandler, posixSignalFlags)
{}
PosixSignalProxy(int posixSignalFlags) :
PosixSignalProxy(nullptr, posixSignalFlags)
{}
static void posixSignalHandler(int) {
PosixSignalProxyBase::staticSignalHandler(mySockets);
}
private:
static int mySockets[2];
};
template <int signum>
int PosixSignalProxy<signum>::mySockets[2];
#endif // POSIXSIGNALPROXY_H
posixsignalproxy.cpp
#include "posixsignalproxy.h"
#include <QSocketNotifier>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
PosixSignalProxyBase::PosixSignalProxyBase(QObject *parent, int (&sockets)[2], int posixSignalNumber, PosixSignalHandlerType posixSignalHandler, int posixSignalFlags) :
QObject(parent),
sockets(sockets)
{
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sockets))
qFatal("PosixSignalProxy: Couldn't create socket pair");
notifier = new QSocketNotifier(sockets[1], QSocketNotifier::Read, this);
connect(notifier, SIGNAL(activated(int)), this, SLOT(handleSignal()));
struct sigaction sa;
sa.sa_handler = posixSignalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = posixSignalFlags;
if (sigaction(posixSignalNumber, &sa, 0) > 0)
qFatal("PosixSignalProxy: Couldn't register POSIX signal handler");
}
PosixSignalProxyBase::~PosixSignalProxyBase()
{
delete notifier;
}
void PosixSignalProxyBase::staticSignalHandler(int (&sockets)[2])
{
char tmp = 1;
::write(sockets[0], &tmp, sizeof(tmp));
}
void PosixSignalProxyBase::handleSignal()
{
notifier->setEnabled(false);
char tmp;
::read(sockets[1], &tmp, sizeof(tmp));
// Here, we're allowed to do Qt stuff.
emit receivedSignal();
notifier->setEnabled(true);
}
You're looking for QCoreApplication::aboutToQuit if you want to use a signal.
Better idea IMO is for engine not to have static functions but to manage its resources properly in its destructor. You can make it a singleton if you want.