Hy,
i have a gtkmm application, which does some async network-requests, to ask the server for additional properties of the gtk-widgets.
This means for example, that the application should be able to change the label of a widget.
In this example I have created a new widget based on Gtk::ToggleButton.
But I found out that sometimes the gtkmm-application crashes with a segfault. When debuging with gdb I always get the line where i set the label.
For better understanding, I have created a MWE which does the label-changes in a loop, to simulate lots of async-calls:
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
#include <iostream>
#include <thread>
#include <mutex>
#include <gtkmm/application.h>
#include <gtkmm/window.h>
#include <gtkmm/togglebutton.h>
class led_label_t : public Gtk::ToggleButton {
public:
using value_list_t = std::vector<Glib::ustring>;
using lock_t = std::lock_guard<std::mutex>;
led_label_t(Glib::ustring label = "<no data>", bool mnemonic = false)
: Gtk::ToggleButton(std::move(label), std::move(mnemonic)),
_values{"SEL1", "SEL2"} {}
protected:
virtual void on_toggled(void) override {
std::cout << "Clicked Button." << std::endl;
lock_t lock(_mtx);
value_changed(_values[get_active()]);
}
virtual void value_changed(Glib::ustring& value) {
std::string path;
if (get_active()) {
path =
"/usr/share/icons/Adwaita/16x16/emblems/emblem-important.png";
} else {
path = "/usr/share/icons/Adwaita/16x16/emblems/emblem-default.png";
}
remove(); // remove previous label
std::cout << "Changed Label of led_label: "
<< ", value: " << value << std::endl;
add_pixlabel(path, value);
}
private:
mutable std::mutex _mtx;
value_list_t _values;
};
int main(void) {
auto app = Gtk::Application::create();
Gtk::Window window;
window.set_default_size(200, 200);
led_label_t inst{};
inst.show();
window.add(inst);
auto f = [&inst, &window]() {
using namespace std::chrono_literals;
boost::asio::io_service io;
{ //wait for startup
boost::asio::steady_timer t{io, 100ms};
t.wait();
}
bool toggle = true;
for (auto i = 0; i < 2000; i++) {
std::cout << "i=" << i << std::endl;
//wait until next simulated button click
boost::asio::steady_timer t{io, 1ms};
t.wait();
inst.set_active(toggle);
toggle = !toggle;
}
};
std::thread c1(f);
std::thread w([&app, &window]() { app->run(window); });
c1.join();
window.hide();
w.join();
return EXIT_SUCCESS;
}
To compile this example, I use following command:
g++ main.cpp -o main `pkg-config --cflags --libs gtkmm-3.0` -Wall -pedantic -Wextra -Werror -Wcast-qual -Wcast-align -Wconversion -fdiagnostics-color=auto -g -O0 -std=c++14 -lboost_system -pthread
I am using GCC 4.9.2 and libgtkmm-3.14 (both standard debian jessie)
The segfault I get is the following:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffe7fff700 (LWP 7888)]
0x00007ffff6288743 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
(gdb) bt
#0 0x00007ffff6288743 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#1 0x00007ffff6288838 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#2 0x00007ffff6267ce9 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#3 0x00007ffff627241b in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#4 0x00007ffff63a1601 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#5 0x00007ffff63a154c in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#6 0x00007ffff63a26b8 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#7 0x00007ffff644d5ff in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#8 0x00007ffff644d9b7 in gtk_widget_realize ()
from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#9 0x00007ffff644dbe8 in gtk_widget_map ()
from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#10 0x00007ffff621c387 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#11 0x00007ffff626270f in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#12 0x00007ffff46bf474 in ?? ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#13 0x00007ffff46d9087 in g_signal_emit_valist ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#14 0x00007ffff46d99df in g_signal_emit ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#15 0x00007ffff644db99 in gtk_widget_map ()
from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#16 0x00007ffff64506d8 in gtk_widget_set_parent ()
from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#17 0x00007ffff6217a9b in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#18 0x00007ffff79a44eb in Gtk::Container_Class::add_callback(_GtkContainer*, _GtkWidget*) () from /usr/lib/x86_64-linux-gnu/libgtkmm-3.0.so.1
#19 0x00007ffff46c253b in g_cclosure_marshal_VOID__OBJECTv ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#20 0x00007ffff46bf474 in ?? ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#21 0x00007ffff46d9087 in g_signal_emit_valist ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#22 0x00007ffff46d99df in g_signal_emit ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#23 0x00007ffff6261aa5 in gtk_container_add ()
from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#24 0x000000000040b0b5 in led_label_t::value_changed (this=0x7fffffffe2a0,
value=...) at main.cpp:38
#25 0x000000000040afb1 in led_label_t::on_toggled (this=0x7fffffffe2a0)
at main.cpp:24
#26 0x00007ffff7a18af0 in Gtk::ToggleButton_Class::toggled_callback(_GtkToggleButton*) () from /usr/lib/x86_64-linux-gnu/libgtkmm-3.0.so.1
#27 0x00007ffff46bf245 in g_closure_invoke ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#28 0x00007ffff46d083b in ?? ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#29 0x00007ffff46d9778 in g_signal_emit_valist ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#30 0x00007ffff46d99df in g_signal_emit ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#31 0x00007ffff63ecb4d in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#32 0x00007ffff798a4a0 in Gtk::Button_Class::clicked_callback(_GtkButton*) ()
from /usr/lib/x86_64-linux-gnu/libgtkmm-3.0.so.1
#33 0x00007ffff46bf474 in ?? ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#34 0x00007ffff46d9087 in g_signal_emit_valist ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#35 0x00007ffff46d99df in g_signal_emit ()
from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#36 0x00007ffff63ec936 in gtk_toggle_button_set_active ()
from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#37 0x0000000000405e12 in <lambda()>::operator()(void) const (
__closure=0x74f4f8) at main.cpp:73
#38 0x000000000040811a in std::_Bind_simple<main()::<lambda()>()>::_M_invoke<>(std::_Index_tuple<>) (this=0x74f4f8) at /usr/include/c++/4.9/functional:1700
#39 0x0000000000407fa9 in std::_Bind_simple<main()::<lambda()>()>::operator()(void) (this=0x74f4f8) at /usr/include/c++/4.9/functional:1688
#40 0x0000000000407e9e in std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> >::_M_run(void) (this=0x74f4e0) at /usr/include/c++/4.9/thread:115
#41 0x00007ffff3f47970 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#42 0x00007ffff37650a4 in start_thread (arg=0x7fffe7fff700)
at pthread_create.c:309
#43 0x00007ffff349a04d in clone ()
at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
Maybe the Interesting line of this is
#24: 0x000000000040b0b5 in led_label_t::value_changed (this=0x7fffffffe2a0,
value=...) at main.cpp:38)
this is the line where add_pixlabel(path, value); is called.
What am I doing wrong here?
Attention:
This segfault doesn't come always, I found out, that on my desktop-machine I get the error once every 10 calls. (Intel i7-3xxx)
And on my laptop I get the error nearly every call (Intel i5-3xxx)
Now I have found a solution, based on the answer of #user4581301. He was right, that gtkmm doesn't support multithreading. (To be more precise, libsigc++ and sigc::trackable are not thread-safe)
However, care is required when writing programs based on gtkmm using
multiple threads of execution, arising from the fact that libsigc++,
and in particular sigc::trackable, are not thread-safe.
Quote from gtkmm documentation.
Therefore I have used Glib::Dispatcher, to execute the set_label() - method in the context of the gtkmm-Main-Loop of the window.
Here is the code, that did not segfault anymore on my machine(s) (even with many retries)
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
#include <cassert>
#include <iostream>
#include <thread>
#include <mutex>
#include <gtkmm/application.h>
#include <gtkmm/window.h>
#include <gtkmm/togglebutton.h>
#include <glibmm/dispatcher.h>
#define LOG() \
std::cout << (std::chrono::system_clock::now() - start).count() << " " \
<< std::this_thread::get_id() << ": "
auto start = std::chrono::system_clock::now();
class led_label_t : public Gtk::ToggleButton {
public:
using value_list_t = std::vector<Glib::ustring>;
using lock_t = std::lock_guard<std::mutex>;
using action_queue_t = std::vector<Glib::ustring>;
led_label_t(Glib::ustring label = "<no data>", bool mnemonic = false)
: Gtk::ToggleButton(std::move(label), std::move(mnemonic)),
_values{"SEL1", "SEL2"} {}
void set_dispatcher(Glib::Dispatcher* dp) {
_dp = dp;
_dp->connect([this](void) { dispatcher_task(); });
}
protected:
virtual void on_toggled(void) override {
LOG() << "Clicked Button." << std::endl;
{
lock_t lock(_action_mtx);
auto value = _values[get_active()];
_action_queue.push_back({value});
LOG() << "Added label into queue " << value << std::endl;
if (_action_queue.size() > 1) {
return;
}
}
_dp->emit();
}
void dispatcher_task(void) {
Glib::ustring label;
for (;;) {
{
lock_t lock(_action_mtx);
if (_action_queue.size() == 0) {
return;
}
label = *_action_queue.begin();
_action_queue.erase(_action_queue.begin());
}
set_label(label);
LOG() << "Set the label " << label << std::endl;
}
}
private:
mutable std::mutex _action_mtx;
action_queue_t _action_queue;
value_list_t _values;
Glib::Dispatcher* _dp;
};
int main(void) {
auto app = Gtk::Application::create();
Gtk::Window window;
window.set_default_size(200, 200);
led_label_t inst{};
inst.show();
window.add(inst);
auto f = [&inst, &window]() {
using namespace std::chrono_literals;
boost::asio::io_service io;
{ // wait for startup
boost::asio::steady_timer t{io, 100ms};
t.wait();
}
bool toggle = true;
for (auto i = 0; i < 200000; i++) {
// wait until next simulated button click
boost::asio::steady_timer t{io, 250us};
t.wait();
LOG() << "i=" << i << std::endl;
inst.set_active(toggle);
toggle = !toggle;
LOG() << "finished" << std::endl;
}
};
std::thread c1(f);
std::thread w([&app, &window, &inst]() {
Glib::Dispatcher dp;
inst.set_dispatcher(&dp);
app->run(window);
});
c1.join();
window.hide();
w.join();
return EXIT_SUCCESS;
}
Accessing and changing UI components from multiple threads is always tricky. UIs need to be fast and responsive to user input, so they can't hang around for background tasks to complete. As a result UI components are rarely protected by mutex or other synchronization. You write, it happens. Except when something else gets in the way.
If you write from two threads... Ooops.
You're half way through a write when another thread reads... Ooops.
Say for example Thread 4 is part way through writing a new string into the label when a screen refresh is triggered. If the backend for label is a c-style string, the terminating NULL may have been overwritten and the label write runs off the end into bad RAM.
All sorts of things could go wrong, and some will be survivable or, worse, look like it. You're better off having all of the UI management in one thread and have the other threads queue updates to the UI thread. Start by looking into Model View Controller and then try related patterns if needed.
Related
I am using a C++ logging library on a FreeBSD 10 machine and I am running into trouble closing threads when receiving a sigint.
A created a GitHub project for testing purposes (link). If you build it on FreeBSD 10, execute it and press [ctrl+c] it will terminate. You can find the build commands I use below.
$ git clone git#github.com:tijme/free-bsd-thread-bug.git
$ cd free-bsd-thread-bug && mkdir -p cmake-build-debug && cd cmake-build-debug
$ cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER="/usr/local/bin/gcc6" -DCMAKE_CXX_COMPILER="/usr/local/bin/g++6"
$ make -dA
$ ./FreeBSDThreadBug
Code I used (can also be found in the GitHub repository)
/* main.cpp */
#include "Example.h"
#include <iostream>
#include <csignal>
#include <thread>
#include <chrono>
Example* example = new Example();
void onSignal(int signum)
{
delete example;
exit(0);
}
int main() {
signal(SIGINT, onSignal);
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
return 0;
}
/* Example.h */
#ifndef FREEBSDTHREADBUG_EXAMPLE_H
#define FREEBSDTHREADBUG_EXAMPLE_H
#include <thread>
#include <iostream>
#include <chrono>
class Example {
public:
Example();
~Example();
std::thread threadHandle;
void threadFunction();
};
#endif //FREEBSDTHREADBUG_EXAMPLE_H
/* Example.cpp */
#include "Example.h"
#include <thread>
#include <chrono>
Example::Example()
{
std::cout << "Main: starting thread" << std::endl;
threadHandle = std::thread(&Example::threadFunction, this);
std::cout << "Main: thread started" << std::endl;
}
Example::~Example()
{
std::cout << "THIS ID: " << std::this_thread::get_id() << std::endl;
std::cout << "THREAD ID: " << threadHandle.get_id() << std::endl;
std::cout << "Main: joining thread" << std::endl;
threadHandle.join();
std::cout << "Main: thread joined" << std::endl;
}
void Example::threadFunction() {
std::cout << "Thread: starting to sleep" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(2500));
std::cout << "Thread: sleep finished" << std::endl;
}
Correct output (on e.g. MacOS Sierra):
As you can see the ID's of the threads are different, as expected.
$ ./FreeBSDThreadBug
Main: starting thread
Main: thread started
Thread: starting to sleep
^C
THIS ID: 0x7fffa428a3c0
THREAD ID: 0x70000c044000
Main: joining thread
Thread: sleep finished
Main: thread joined
Wrong output (termination, on FreeBSD 10.3):
The thread ID's are the same here, which is pretty weird.
$ ./FreeBSDThreadBug
Main: starting thread
Main: thread started
Thread: starting to sleep
^C
THIS ID: 0x801c06800
THREAD ID: 0x801c06800
Main: joining thread
terminate called after throwing an instance of 'std::system_error'
what(): Resource deadlock avoided
Abort (core dumped)
Core dump
Core was generated by `FreeBSDThreadBug'.
Program terminated with signal SIGABRT, Aborted.
#0 0x00000008012d335a in thr_kill () from /lib/libc.so.7
[Current thread is 1 (LWP 100146)]
(gdb) bt full
#0 0x00000008012d335a in thr_kill () from /lib/libc.so.7
No symbol table info available.
#1 0x00000008012d3346 in raise () from /lib/libc.so.7
No symbol table info available.
#2 0x00000008012d32c9 in abort () from /lib/libc.so.7
No symbol table info available.
#3 0x0000000800ad8afd in __gnu_cxx::__verbose_terminate_handler () at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/vterminate.cc:95
terminating = true
t = <optimized out>
#4 0x0000000800ad5b48 in __cxxabiv1::__terminate (handler=<optimized out>) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/eh_terminate.cc:47
No locals.
#5 0x0000000800ad5bb1 in std::terminate () at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/eh_terminate.cc:57
No locals.
#6 0x0000000800ad5dc8 in __cxxabiv1::__cxa_throw (obj=obj#entry=0x80200e0a0, tinfo=0x800dd0bc0 <typeinfo for std::system_error>, dest=0x800b073b0 <std::system_error::~system_error()>)
at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/libsupc++/eh_throw.cc:87
globals = <optimized out>
#7 0x0000000800b04cd1 in std::__throw_system_error (__i=11) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/src/c++11/functexcept.cc:130
No locals.
#8 0x0000000800b0792c in std::thread::join (this=0x801c5c058) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/src/c++11/thread.cc:139
__e = <optimized out>
#9 0x00000000004016fc in Example::~Example (this=0x801c5c058, __in_chrg=<optimized out>) at /root/FreeBSDThreadBug/Example.cpp:18
No locals.
#10 0x00000000004010b7 in onSignal (signum=2) at /root/FreeBSDThreadBug/main.cpp:11
No locals.
#11 0x000000080082fb4a in ?? () from /lib/libthr.so.3
No symbol table info available.
#12 0x000000080082f22c in ?? () from /lib/libthr.so.3
No symbol table info available.
#13 <signal handler called>
No symbol table info available.
#14 0x00000008012efb5a in _nanosleep () from /lib/libc.so.7
No symbol table info available.
#15 0x000000080082cc4c in ?? () from /lib/libthr.so.3
No symbol table info available.
#16 0x000000000040155d in std::this_thread::sleep_for<long, std::ratio<1l, 1000l> > (__rtime=...) at /usr/local/lib/gcc6/include/c++/thread:322
__s = {__r = 2}
__ns = {__r = 500000000}
__ts = {tv_sec = 1, tv_nsec = 126917539}
#17 0x000000000040177a in Example::threadFunction (this=0x801c5c058) at /root/FreeBSDThreadBug/Example.cpp:24
No locals.
#18 0x0000000000402432 in std::__invoke_impl<void, void (Example::* const&)(), Example*>(std::__invoke_memfun_deref, void (Example::* const&)(), Example*&&) (
__f=#0x801c5e050: (void (Example::*)(Example * const)) 0x40172c <Example::threadFunction()>, __t=<unknown type in /root/FreeBSDThreadBug/cmake-build-debug/FreeBSDThreadBug, CU 0x552f, DIE 0xb2d7>)
at /usr/local/lib/gcc6/include/c++/functional:227
No locals.
#19 0x00000000004023bf in std::__invoke<void (Example::* const&)(), Example*>(void (Example::* const&)(), Example*&&) (__fn=#0x801c5e050: (void (Example::*)(Example * const)) 0x40172c <Example::threadFunction()>,
__args#0=<unknown type in /root/FreeBSDThreadBug/cmake-build-debug/FreeBSDThreadBug, CU 0x552f, DIE 0xb2d7>) at /usr/local/lib/gcc6/include/c++/functional:251
No locals.
#20 0x0000000000402370 in std::_Mem_fn_base<void (Example::*)(), true>::operator()<Example*>(Example*&&) const (this=0x801c5e050,
__args#0=<unknown type in /root/FreeBSDThreadBug/cmake-build-debug/FreeBSDThreadBug, CU 0x552f, DIE 0xb2d7>) at /usr/local/lib/gcc6/include/c++/functional:604
No locals.
#21 0x000000000040233b in std::_Bind_simple<std::_Mem_fn<void (Example::*)()> (Example*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) (this=0x801c5e048) at /usr/local/lib/gcc6/include/c++/functional:1391
No locals.
#22 0x0000000000402289 in std::_Bind_simple<std::_Mem_fn<void (Example::*)()> (Example*)>::operator()() (this=0x801c5e048) at /usr/local/lib/gcc6/include/c++/functional:1380
No locals.
#23 0x0000000000402268 in std::thread::_State_impl<std::_Bind_simple<std::_Mem_fn<void (Example::*)()> (Example*)> >::_M_run() (this=0x801c5e040) at /usr/local/lib/gcc6/include/c++/thread:196
No locals.
#24 0x0000000800b0769f in std::execute_native_thread_routine (__p=0x801c5e040) at /wrkdirs/usr/ports/lang/gcc6/work/gcc-6.3.0/libstdc++-v3/src/c++11/thread.cc:83
__t = std::unique_ptr<std::thread::_State> containing 0x801c5e040
#25 0x000000080082a855 in ?? () from /lib/libthr.so.3
No symbol table info available.
#26 0x0000000000000000 in ?? ()
No symbol table info available.
Backtrace stopped: Cannot access memory at address 0x7fffdfffe000
System information
$ freebsd-version
10.3-RELEASE
$ /usr/local/bin/gcc6 --version
gcc6 (FreeBSD Ports Collection) 6.3.0
$ /usr/local/bin/g++6 --version
g++6 (FreeBSD Ports Collection) 6.3.0
$ cmake --version
cmake version 3.7.2
The original issue I created can be found on GitHub (link), however there is no fix yet.
I hope someone will be able to help me fix this issue. Thanks in advance.
That's not a bug, that's a feature.
You don't get a guarantee about where your signal is going to be delivered, and the set of things you're allowed to do in a signal handler is restricted.
See sigaction(3) for details about what you can do (and you can't do anything else). Your program is doing many things that are not allowed in a signal handler.
The correct thing to do is to signal something else in your program and return from the signal handler. An example technique for doing that is the "self pipe trick". Create a pipe and keep a handle to both ends. Read from one end in your normal I/O processing. If you get a signal, in the signal handler, write a byte to the other end of the pipe and return. When the byte is read from the pipe you know the signal has arrived and you can do extended processing safely.
Update:
As Michael Burr has pointed out, you can block particular threads from receiving particular signals using pthread_sigmask(3). However, to fix the underlying problem here you still need to not do the work in the signal handler.
I used msys64 - mingw32 (on Windows 7, 64 bit) to build a 3rd party library (libosmscout) using a supplied makefile. I was primarily interested in one particular example from the library (Demos/src/DrawMapCairo). With makefile complete library was built successfuly, including demos. Example console application of interest works fine.
My intention however is to make my own application using Code::Blocks IDE, which would use functionality of the example app. Therefore I tried to build the example in Code::Blocks (New project -> console application, GCC 5.1 MinGW). After a while I managed to get a successful build with 0 errors/warnings. But the application doesn't work, it crashes with sigsegv fault. "cout debugging" and stepping into in debugger suggest that the issue seems to be (or start) at line
osmscout::DatabaseRef database(new osmscout::Database(databaseParameter));
Source code with main() :
#includes...
static const double DPI=96.0;
int main(int argc, char* argv[])
{
std::string map;
std::string style;
std::string output;
size_t width,height;
double lon,lat,zoom;
if (argc!=9) {
std::cerr << "DrawMap <map directory> <style-file> <width> <height> <lon> <lat> <zoom> <output>" << std::endl;
return 1;
}
map=argv[1];
style=argv[2];
//next 6 lines not exactly as in source, but for shorter code:
osmscout::StringToNumber(argv[3],width);
osmscout::StringToNumber(argv[4],height);
sscanf(argv[5],"%lf",&lon);
sscanf(argv[6],"%lf",&lat);
sscanf(argv[7],"%lf",&zoom);
output=argv[8];
osmscout::DatabaseParameter databaseParameter;
osmscout::DatabaseRef database(new osmscout::Database(databaseParameter));
osmscout::MapServiceRef mapService(new osmscout::MapService(database));
if (!database->Open(map.c_str())) {
std::cerr << "Cannot open database" << std::endl;
return 1;
}
osmscout::StyleConfigRef styleConfig(new osmscout::StyleConfig (database->GetTypeConfig()));
if (!styleConfig->Load(style)) {
std::cerr << "Cannot open style" << std::endl;
}
cairo_surface_t *surface;
cairo_t *cairo;
surface=cairo_image_surface_create(CAIRO_FORMAT_RGB24,width,height);
if (surface!=NULL) {
cairo=cairo_create(surface);
if (cairo!=NULL) {
osmscout::MercatorProjection projection;
osmscout::MapParameter drawParameter;
osmscout::AreaSearchParameter searchParameter;
osmscout::MapData data;
osmscout::MapPainterCairo painter(styleConfig);
drawParameter.SetFontSize(3.0);
projection.Set(lon,
lat,
osmscout::Magnification(zoom),
DPI,
width,
height);
std::list<osmscout::TileRef> tiles;
mapService->LookupTiles(projection,tiles);
mapService->LoadMissingTileData(searchParameter,*styleConfig,tiles);
mapService->ConvertTilesToMapData(tiles,data);
if (painter.DrawMap(projection,
drawParameter,
data,
cairo)) {
if (cairo_surface_write_to_png(surface,output.c_str())!=CAIRO_STATUS_SUCCESS) {
std::cerr << "Cannot write PNG" << std::endl;
}
}
cairo_destroy(cairo);
}
else {
std::cerr << "Cannot create cairo cairo" << std::endl;
}
cairo_surface_destroy(surface);
}
else {
std::cerr << "Cannot create cairo surface" << std::endl;
}
return 0;
}
How can I find exactly what the problem is and solve it? What's really puzzling me is that the same code built with makefile works just fine.
EDIT:
After running GDB (Gnu Debugger, gdb32.exe) and then bt (backtrace) I get the following output:
[New Thread 3900.0x538]
Program received signal SIGSEGV, Segmentation fault.
0x777ec159 in ntdll!RtlDecodeSystemPointer ()
from C:\Windows\SysWOW64\ntdll.dll
(gdb)
(gdb) bt
#0 0x777e3c28 in ntdll!RtlQueryPerformanceCounter ()
from C:\Windows\SysWOW64\ntdll.dll
#1 0x00000028 in ?? ()
#2 0x00870000 in ?? ()
#3 0x777ec1ed in ntdll!RtlDecodeSystemPointer ()
from C:\Windows\SysWOW64\ntdll.dll
#4 0x777ec13e in ntdll!RtlDecodeSystemPointer ()
from C:\Windows\SysWOW64\ntdll.dll
#5 0x777e3541 in ntdll!RtlQueryPerformanceCounter ()
from C:\Windows\SysWOW64\ntdll.dll
#6 0x00000010 in ?? ()
#7 0x00000028 in ?? ()
#8 0x008700c4 in ?? ()
#9 0x77881dd3 in ntdll!RtlpNtEnumerateSubKey ()
from C:\Windows\SysWOW64\ntdll.dll
#10 0x7783b586 in ntdll!RtlUlonglongByteSwap ()
from C:\Windows\SysWOW64\ntdll.dll
#11 0x00870000 in ?? ()
#12 0x777e3541 in ntdll!RtlQueryPerformanceCounter ()
from C:\Windows\SysWOW64\ntdll.dll
#13 0x00000010 in ?? ()
#14 0x00000000 in ?? ()
(gdb)
What does this error mean and how to find what caused it to correct the fault?
I'm working on a program that only needs to use SDL to get screen resolutions when needed. I'd like to start the SDL init, get what I need, then close it. But I'm having trouble because when I start the SDL is takes over the single interrupt handle, I can't even set it to SIG_IGN...
I have a main method that creates a QApplication and a mainWidget.
While running, a function in the mainWidget starts an SDL instance using the following code:
bool MainWidget::getSomeSdlInformation()
{
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
SDL_SetMainReady();
SDL_Init(0);
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
qDebug() << "SDL_Init failed: " << QString::fromUtf8(SDL_GetError());
SDL_Quit();
return false;
}
signal(SIGINT, SIG_DFL);
// Get the needed video information
// Quit SDL
SDL_Quit();
return true;
}
After I "Quit SDL" I'd like to return the csignal interrupt back to QT, such that when a user presses control-c the program closes gracefully.
I'm having some trouble figuring our how to return control of the handle back to QT.
Here is an a crash log from preforming the control-c operation on my existing implementation:
Program received signal SIGSEGV, Segmentation fault.
__GI___pthread_mutex_lock (mutex=0x7fffffffd2f0) at ../nptl/pthread_mutex_lock.c:66
66 ../nptl/pthread_mutex_lock.c: No such file or directory.
(gdb) bt
#0 __GI___pthread_mutex_lock (mutex=0x7fffffffd2f0) at ../nptl/pthread_mutex_lock.c:66
#1 0x00007ffff48070da in XrmQGetResource () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#2 0x00007ffff47e4a42 in XGetDefault () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#3 0x00007ffff43ab0d0 in _XcursorGetDisplayInfo () from /usr/lib/x86_64-linux-gnu/libXcursor.so.1
#4 0x00007ffff43ab1a9 in XcursorGetDefaultSize () from /usr/lib/x86_64-linux-gnu/libXcursor.so.1
#5 0x00007ffff43ad435 in XcursorLibraryLoadCursor () from /usr/lib/x86_64-linux-gnu/libXcursor.so.1
#6 0x00007ffff706ed5c in ?? () from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#7 0x00007ffff706f485 in QCursor::handle() const () from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#8 0x00007ffff707b364 in ?? () from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#9 0x00007ffff7080398 in QWidgetPrivate::create_sys(unsigned long, bool, bool) () from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#10 0x00007ffff703231d in QWidget::create(unsigned long, bool, bool) () from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#11 0x00007ffff703a86a in QWidget::setVisible(bool) () from /usr/lib/x86_64-linux-gnu/libQtGui.so.4
#12 0x0000000000421270 in show (this=0x7fffffffda60) at /usr/include/qt4/QtGui/qwidget.h:497
#13 main (argc=1, argv=) at /home/jeff/Dev/openmw/apps/launcher/main.cpp:55
I can't figure out why the code below is causing Segmentation Faults.
If I remove the call to pushLock.lock() and .unlock(), it runs fine.
#include <mutex>
#include <queue>
class FunctionQueue{
public:
FunctionQueue();
~FunctionQueue();
void pushInt(int);
private:
std::mutex pushLock;
int currentPushQueue;
std::queue<int> instructionQueues[2];
};
FunctionQueue::FunctionQueue(){
instructionQueues[0] = std::queue<int>();
instructionQueues[1] = std::queue<int>();
// pushLock.unlock();
}
FunctionQueue::~FunctionQueue(){}
void FunctionQueue::pushInt(int newArgument){
pushLock.lock();
instructionQueues[currentPushQueue].push(newArgument);
pushLock.unlock();
}
int main(int argc, char* argv[]){
FunctionQueue testQueue;
testQueue.pushInt(10);
}
The output from a gdb BackTrace was the very unhelpful:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x00007ffff347a291 in ?? () from /lib/x86_64-linux-gnu/libdl.so.2
#2 0x00007ffff347a6d7 in ?? () from /lib/x86_64-linux-gnu/libdl.so.2
#3 0x00007ffff347a198 in dlsym () from /lib/x86_64-linux-gnu/libdl.so.2
#4 0x00007ffff7904b3e in ?? () from /usr/lib/nvidia-331/libGL.so.1
#5 0x00007ffff78e8db4 in ?? () from /usr/lib/nvidia-331/libGL.so.1
#6 0x00007ffff7dea0fd in ?? () from /lib64/ld-linux-x86-64.so.2
#7 0x00007ffff7dea223 in ?? () from /lib64/ld-linux-x86-64.so.2
#8 0x00007ffff7ddb30a in ?? () from /lib64/ld-linux-x86-64.so.2
#9 0x0000000000000001 in ?? ()
#10 0x00007fffffffe8a6 in ?? ()
#11 0x0000000000000000 in ?? ()
Any help you can give would be excellent.
Thanks in advance.
Completely remove the commented out code in the constructor of your class as that shouldn't be there in the first place since you haven't locked anything. Problems with this are:
1. You haven't initialized or assigned the member variable 'currentPushQueue' to any value so this code:
instructionQueues[currentPushQueue].push(newArgument);
is completely wrong unless currentPushQueue is assigned.
2. You aren't using mutexs as they are meant to be used, which is with the provided wrappers (std::unique_lock/std::lock_guard).
Try this code and respond please:
#include <mutex>
#include <queue>
class FunctionQueue
{
public:
FunctionQueue();
~FunctionQueue();
void pushInt(int);
private:
std::mutex pushLock;
int currentPushQueue = 0; // Set this variable somehow
std::queue<int> instructionQueues[2];
};
FunctionQueue::FunctionQueue()
{
instructionQueues[0] = std::queue<int>();
instructionQueues[1] = std::queue<int>();
}
FunctionQueue::~FunctionQueue() {}
void FunctionQueue::pushInt(int newArgument)
{
std::unique_lock<std::mutex> mutexLock(pushLock);
instructionQueues[currentPushQueue].push(newArgument);
// Unlocks automatically
}
int main(int argc, char* argv[])
{
FunctionQueue testQueue;
testQueue.pushInt(10);
}
I have encountered a strange problem with boost::asio::io_service::run. Sometimes this run function seems to eat the whole cpu(100%), and sometimes not. I am not very clear about the pattern.
the relevant code:
class Asio {
public:
Asio() :
io_service_(new boost::asio::io_service),
run_() {}
void Start() {
if (!asio_thread_.joinable()) {
run_ = true;
asio_thread_ = std::thread([=] {
Run();
});
}
}
boost::asio::io_service* io_service() { return io_service_.get(); }
protected:
void Run() {
for (;;) {
boost::system::error_code ec;
io_service()->run(ec);
if (run_) {
io_service()->reset();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
} else {
break;
}
}
}
protected:
std::unique_ptr<boost::asio::io_service> io_service_;
std::thread asio_thread_;
std::atomic<bool> run_;
};
When the run function runs normally, below is the callstack
#0 0x00000035f74e9163 in epoll_wait () from /lib64/libc.so.6
#1 0x0000000000b3f6ef in boost::asio::detail::epoll_reactor::run(bool, boost::asio::detail::op_queue<boost::asio::detail::task_io_service_operation>&) ()
#2 0x0000000000b40111 in boost::asio::detail::task_io_service::do_run_one(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&, boost::asio::detail::task_io_service_thread_info&, boost::system::error_code const&) ()
#3 0x0000000000b3feaf in boost::asio::detail::task_io_service::run(boost::system::error_code&) ()
#4 0x0000000000b403fd in boost::asio::io_service::run(boost::system::error_code&) ()
#5 0x0000000000b3ddc1 in Asio::Run() ()
When the run function behaves abnormally, below is the callstack:
#0 0x00000031bbee53c9 in syscall () from /lib64/libc.so.6
#1 0x00007f831d1d3d68 in std::chrono::_V2::steady_clock::now() () from /usr/local/gcc48/lib64/libstdc++.so.6
#2 0x0000000000b45b6d in boost::asio::detail::chrono_time_traits<std::chrono::_V2::steady_clock, boost::asio::wait_traits<std::chrono::_V2::steady_clock> >::now() ()
#3 0x0000000000b45608 in boost::asio::detail::timer_queue<boost::asio::detail::chrono_time_traits<std::chrono::_V2::steady_clock, boost::asio::wait_traits<std::chrono::_V2::steady_clock> > >::get_ready_timers(boost::asio::detail::op_queue<boost::asio::detail::task_io_service_operation>&) ()
#4 0x0000000000b3f5d7 in boost::asio::detail::timer_queue_set::get_ready_timers(boost::asio::detail::op_queue<boost::asio::detail::task_io_service_operation>&) ()
#5 0x0000000000b3f815 in boost::asio::detail::epoll_reactor::run(bool, boost::asio::detail::op_queue<boost::asio::detail::task_io_service_operation>&) ()
#6 0x0000000000b40111 in boost::asio::detail::task_io_service::do_run_one(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&, boost::asio::detail::task_io_service_thread_info&, boost::system::error_code const&) ()
#7 0x0000000000b3feaf in boost::asio::detail::task_io_service::run(boost::system::error_code&) ()
#8 0x0000000000b403fd in boost::asio::io_service::run(boost::system::error_code&) ()
#9 0x0000000000b3ddc1 in Asio::Run() ()
In both cases, there're some pending handlers in the io_service, so the io_service::run should not return and should be wait for the event to happen.
Any advise is welcome.
I did further check, it's seems it's due to the boost::asio::steady_timer used. The usage of steady_timer involves the usage of the following pattern:
boost::asio::steady_timer timer;
timer.expires_at(some_expiry, error_code)
timer.async_wait((=)(boost::system::error_code ec) {
// some operation
timer.expires_at(new_expiry, error_code);
timer.asyn_wait(...);
});
Where the timer is wrapped in a shared pointer, and it's safe to copy into the lamda function.