why c++ pthread exited by itself without process crash? - c++

I have a process which uses almost 16 threads. On of the thread id getting exited by itself after working for some time (please note process didn't crash). I am not sure how to look for reasons for thread exiting ? I tried using print statement but that doesn't seems to help. Tried capturing through gdb didn't help. If this is some sort of memory corruption then the process should crash and core file should have tell everything (most of the time) but process remains running just the thread exiting is making my job difficult..
Can you please suggest some way to debug this issue ?
-Arpit

I am not sure how to look for reasons for thread exiting
There are only two ways that I can think of for this to happen:
The thread function returns
Something the thread function calls executes syscall(SYS_exit, ...)
You can use (gdb) catch syscall exit and then where to find out where this is happening.
If where shows something similar to this:
(gdb) where
#0 0x00007ffff7bc3556 in __exit_thread () at ../sysdeps/unix/sysv/linux/exit-thread.h:36
#1 start_thread (arg=0x7ffff781c700) at pthread_create.c:478
#2 0x00007ffff7905a8f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:97
then you have case 1, and you need to step through your thread function to find out where it is returning (https://rr-project.org/ may help a lot).
If instead you see something like this:
(gdb) where
#0 syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
#1 0x0000555555554746 in do_work () at t.c:9
#2 0x0000555555554762 in fn (p=0x0) at t.c:15
#3 0x00007ffff7bc3494 in start_thread (arg=0x7ffff781c700) at pthread_create.c:333
#4 0x00007ffff7905a8f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:97
then the culprit is whatever routine called syscall.

Related

Is boost asio timer expected to block on `cancel`?

I observe that the boost::asio::steady_timer is blocking when the cancel is called and the callback provided by async_wait is already executing. Is it expected behavior? Is it configurable? Why in the first place it have to block?
callstack:
#0 __lll_lock_wait () at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
#1 0x00007f4d4c703dbd in __GI___pthread_mutex_lock (mutex=0x20000616f558) at ../nptl/pthread_mutex_lock.c:80
#2 0x000070000086ef75 in boost::asio::detail::posix_mutex::lock (this=0x20000616f558) at /source/boost/include/boost/asio/detail/posix_mutex.hpp:52
#3 0x000070000087036e in boost::asio::detail::conditionally_enabled_mutex::scoped_lock::scoped_lock (this=0x40000623e970, m=...) at /source/boost/include/boost/asio/detail/conditionally_enabled_mutex.hpp:55
#4 0x00007000009ebf7f in boost::asio::detail::epoll_reactor::cancel_timer<boost::asio::detail::chrono_time_traits<std::chrono::_V2::steady_clock, boost::asio::wait_traits<std::chrono::_V2::steady_clock> > > (this=0x20000616f520, queue=..., timer=...,
max_cancelled=18446744073709551615) at /source/boost/include/boost/asio/detail/impl/epoll_reactor.hpp:62
#5 0x00007000009e8322 in boost::asio::detail::deadline_timer_service<boost::asio::detail::chrono_time_traits<std::chrono::_V2::steady_clock, boost::asio::wait_traits<std::chrono::_V2::steady_clock> > >::cancel (this=0x200006188f60, impl=..., ec=...)
at /source/boost/include/boost/asio/detail/deadline_timer_service.hpp:144
#6 0x00007000009e5211 in boost::asio::basic_waitable_timer<std::chrono::_V2::steady_clock, boost::asio::wait_traits<std::chrono::_V2::steady_clock> >::cancel (this=0x20009470cfc8)
at /source/boost/include/boost/asio/basic_waitable_timer.hpp:329
Looks like the problem was due the fact that we are working in multi-process environment. All processes share the same memory, all objects created on this shared memory, including mutexes, threads etc. To function properly in such a case the mutexes used in the system are created with PTHREAD_PROCESS_SHARED attribute. Obviously, asio mutexes are not created with such an attribute so I guess this is the problem with the mutexes getting stuck in unexpected locations. Once the io_context and steady_timer started to execute in only one process it started to work as expected

Reading OpenEXRs sequentially from a Pipe

I am trying to read a stream of EXRs from one pipe, process them and write the results into a different pipe. This this case they are named pipes but they could just as well be stdin and stdout.
My problem occurs when the pipe runs dry. OpenEXR doesn't like trying to read nothing and crashes with the following stack trace.
(gdb) run in.exr out.exr
Starting program: /Users/jon/Library/Developer/Xcode/DerivedData/compressor-abhdftqzleulxsfkpidvcazfowwo/Build/Products/Debug/compressor in.exr out.exr
Reading symbols for shared libraries +++++++++......................................................................................................... done
Reading symbols for shared libraries ............ done
Reading symbols for shared libraries . done
Reading symbols for shared libraries . done
terminate called throwing an exception
Program received signal SIGABRT, Aborted.
0x00007fff90957ce2 in __pthread_kill ()
(gdb) backtrace
#0 0x00007fff90957ce2 in __pthread_kill ()
#1 0x00007fff866f27d2 in pthread_kill ()
#2 0x00007fff866e3a7a in abort ()
#3 0x00007fff8643c7bc in abort_message ()
#4 0x00007fff86439fcf in default_terminate ()
#5 0x00007fff844d61cd in _objc_terminate ()
#6 0x00007fff8643a001 in safe_handler_caller ()
#7 0x00007fff86439fed in unexpected_defaults_to_terminate ()
#8 0x00007fff8643a040 in __cxxabiv1::__unexpected ()
#9 0x00007fff8643aefe in __cxa_call_unexpected ()
#10 0x0000000100008cfb in exr::ReadEXR (pixelBuffer=#0x7fff5fbfee00, is=#0x7fff5fbfeef8) at /Users/jon/Development/compressor/compressor/exr.cpp:47
#11 0x0000000100001c39 in main (argc=4, argv=0x7fff5fbffaa8) at /Users/jon/Development/compressor/compressor/main.cpp:79
I would really like OpenEXR to block the thread until more data becomes available but if there was some method of checking manually to see whether there is more data that would do, so long as it was somewhat robust.
Thanks.
The solution to this problem is indeed to extend Imf::Istream and implement it to block when the input pipe runs dry.
For this specific problem some considerations need to be made like pipes aren't seekable and d o not know their position, they can be worked around however.

infinite abort() in a backrace of a c++ program core dump

I have a strange problem that I can't solve. Please help!
The program is a multithreaded c++ application that runs on ARM Linux machine. Recently I began testing it for the long runs and sometimes it crashes after 1-2 days like so:
*** glibc detected ** /root/client/my_program: free(): invalid pointer: 0x002a9408 ***
When I open core dump I see that the main thread it seems has a corrupt stack: all I can see is infinite abort() calls.
GNU gdb (GDB) 7.3
...
This GDB was configured as "--host=i686 --target=arm-linux".
[New LWP 706]
[New LWP 700]
[New LWP 702]
[New LWP 703]
[New LWP 704]
[New LWP 705]
Core was generated by `/root/client/my_program'.
Program terminated with signal 6, Aborted.
#0 0x001c44d4 in raise ()
(gdb) bt
#0 0x001c44d4 in raise ()
#1 0x001c47e0 in abort ()
#2 0x001c47e0 in abort ()
#3 0x001c47e0 in abort ()
#4 0x001c47e0 in abort ()
#5 0x001c47e0 in abort ()
#6 0x001c47e0 in abort ()
#7 0x001c47e0 in abort ()
#8 0x001c47e0 in abort ()
#9 0x001c47e0 in abort ()
#10 0x001c47e0 in abort ()
#11 0x001c47e0 in abort ()
And it goes on and on. I tried to get to the bottom of it by moving up the stack: frame 3000 or even more, but eventually core dump runs out of frames and I still can't see why this has happened.
When I examine the other threads everything seems normal there.
(gdb) info threads
Id Target Id Frame
6 LWP 705 0x00132f04 in nanosleep ()
5 LWP 704 0x001e7a70 in select ()
4 LWP 703 0x00132f04 in nanosleep ()
3 LWP 702 0x00132318 in sem_wait ()
2 LWP 700 0x00132f04 in nanosleep ()
* 1 LWP 706 0x001c44d4 in raise ()
(gdb) thread 5
[Switching to thread 5 (LWP 704)]
#0 0x001e7a70 in select ()
(gdb) bt
#0 0x001e7a70 in select ()
#1 0x00057ad4 in CSerialPort::read (this=0xbea7d98c, string_buffer=..., delimiter=..., timeout_ms=1000) at CSerialPort.cpp:202
#2 0x00070de4 in CScanner::readResponse (this=0xbea7d4cc, resp_recv=..., timeout=1000, delim=...) at PidScanner.cpp:657
#3 0x00071198 in CScanner::sendExpect (this=0xbea7d4cc, cmd=..., exp_str=..., rcv_str=..., timeout=1000) at PidScanner.cpp:604
#4 0x00071d48 in CScanner::pollPid (this=0xbea7d4cc, mode=1, pid=12, pid_str=...) at PidScanner.cpp:525
#5 0x00072ce0 in CScanner::poll1 (this=0xbea7d4cc)
#6 0x00074c78 in CScanner::Poll (this=0xbea7d4cc)
#7 0x00089edc in CThread5::Thread5Poll (this=0xbea7d360)
#8 0x0008c140 in CThread5::run (this=0xbea7d360)
#9 0x00088698 in CThread::threadFunc (p=0xbea7d360)
#10 0x0012e6a0 in start_thread ()
#11 0x001e90e8 in clone ()
#12 0x001e90e8 in clone ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(Classes and functions names are a bit wierd because I changed them -:)
So, thread #1 is where the stack is corrupt, backtrace of every other (2-6) shows
Backtrace stopped: previous frame identical to this frame (corrupt stack?).
It happends because threads 2-6 are created in the thread #1.
The thing is that I can't run the program in gdb because it runs on an embedded system. I can't use remote gdb server. The only option is examining core dumps that occur not very often.
Could you please suggest something that could move me forward with this? (Maybe something else I can extract from the core dump or maybe somehow to make some hooks in the code to catch abort() call).
UPDATE: Basile Starynkevitch suggested to use Valgrind, but turns out it's ported only for ARMv7. I have ARM 926 which is ARMv5, so this won't work for me. There are some efforts to compile valgrind for ARMv5 though: Valgrind cross compilation for ARMv5tel, valgrind on the ARM9
UPDATE 2: Couldn't make Electric Fence work with my program. The program uses C++ and pthreads. The version of Efence I got, 2.1.13 crashed in a arbitrary place after I start a thread and try to do something more or less complicated (for example to put a value into an STL vector). I saw people mentioning some patches for Efence on the web but didn't have time to try them. I tried this on my Linux PC, not on the ARM, and other tools like valgrind or Dmalloc don't report any problems with the code. So, everyone using version 2.1.13 of efence be prepared to have problems with pthreads (or maybe pthread + C++ + STL, don't know).
My guess for the "infinite' aborts is that either abort() causes a loop (e.g. abort -> signal handler -> abort -> ...) or that gdb can't correctly interpret the frames on the stack.
In either case I would suggest manually checking out the stack of the problematic thread. If abort causes a loop, you should see a pattern or at least the return address of abort repeating every so often. Perhaps you can then more easily find the root of the problem by manually skipping large parts of the (repeating) stack.
Otherwise, you should find that there is no repeating pattern and hopefully the return address of the failing function somewhere on the stack. In the worst case such addresses are overwritten due to a buffer overflow or such, but perhaps then you can still get lucky and recognise what it is overwritten with.
One possibility here is that something in that thread has very, very badly smashed the stack by vastly overwriting an on-stack data structure, destroying all the needed data on the stack in the process. That makes postmortem debugging very unpleasant.
If you can reproduce the problem at will, the right thing to do is to run the thread under gdb and watch what is going on precisely at the moment when the the stack gets nuked. This may, in turn, require some sort of careful search to determine where exactly the error is happening.
If you cannot reproduce the problem at will, the best I can suggest is very carefully looking for clues in the thread local storage for that thread to see if it hints at where the thread was executing before death hit.

Stopping a Thrift server(TSimpleServer)

I have a simple use case for a Thrift Server(TSimpleServer) wherein I have a couple of threads spawned(besides the main thread). One of the newly spawned threads enters the Thrift event loop (i.e server.serve()). Upon receiving a signal in the main thread I invoke server.stop() which is causing the error posted below.
At first I thought it was an uncaught exception. However wrapping both the invocations of server.serve() and server.stop() in try-catch'es didn't help isolate the problem. Any thoughts/suggestions(on what I should be doing)? Most Thrift tutorials/guides/examples seem to talk about server start but don't seem to mention the stop scenario, any pointers/best-practices/suggestions in this regard would be great. Thanks.
Also, I am using thrift-0.7.0.
Error details:
Thrift: Fri Nov 18 21:22:47 2011 TServerTransport died on accept: TTransportExc\
eption: Interrupted
*** glibc detected *** ./build/mc_daemon: munmap_chunk(): invalid poi\
nter: 0x0000000000695f18 ***
Segmentation fault (core dumped)
Also here's the stack-trace:
#0 0x00007fb751c92f08 in ?? () from /lib/libc.so.6
#1 0x00007fb7524bb0eb in apache::thrift::server::TSimpleServer::serve (
this=0x1e5bca0) at src/server/TSimpleServer.cpp:140
#2 0x000000000046ce15 in a::b::server_thread::operator() (
this=0x695f18)
at /path/to/server_thread.cpp:80
#3 0x000000000046c1a9 in boost::detail::thread_data<boost::reference_wrapper<a\
ds::data_load::server_thread> >::run (this=0x1e5bd80)
at /usr/include/boost/thread/detail/thread.hpp:81
#4 0x00007fb7526f2b70 in thread_proxy ()
from /usr/lib/libboost_thread.so.1.40.0
#5 0x00007fb7516fd9ca in start_thread () from /lib/libpthread.so.0
#6 0x00007fb7519fa70d in clone () from /lib/libc.so.6
#7 0x0000000000000000 in ?? ()
Edit 1: I have added pseudo-code for the main thread, the thrift server thread and the background thread.
Edit 2: I seem to have resolved the original issue as noted in my answer below. However this solution leads to two rather undesirable/questionable design choices: (i) I had to introduce a thrift endpoint to enable a mechanism to stop the server (ii) The handler class for the thrift service(which is usually required to instantiate a server object) now requires a means to signal back to the server to stop, introducing a circular dependency of sorts.
Any suggestions on these design issues/choices would be greatly appreciated.
My problem seems to have stemmed from my code/design wherein I had signal-handler code in the main thread invoking stop on the server which was started in a 'server thread'. Changing this behavior(as noted in the pastebin code-snippets) helped resolve this issue.

Python PyGILState_{Ensure/Release} causes segfault while returning to C++ from Python code

UPDATE Well, it looks like adding PyEval_InitThreads() before the call to PyGILState_Ensure() does the trick. In my haste to figure things out I incorrectly attributed my "hanging" to PyEval_InitThreads().
However, after reading some Python documentation I am wondering if this is the correct solution.
It is not safe to call this function when it is unknown which thread (if any) currently has the global interpreter lock.
First of all, I am working on some modified GNU Radio code - particularly a modified gr_bin_statistics_f block. Now, there is a bug report (albeit an old one) which pretty much describes my exact situation.
http://gnuradio.org/redmine/issues/show/199
Now, usrp_spectrum_sense.py which is mentioned in the bug report calls gr_bin_statistics_f (C++) which then calls back to Python periodically to re-tune the USRP (radio).
Here is what happens when the Python code is called:
PyGILState_STATE d_gstate;
d_gstate = PyGILState_Ensure();
// call python code
PyGILState_Release(d_gstate);
So, once we return from the Python code a segmentation fault occurs when PyGILState_Release(d_gstate) is called. While there are differences between my code and the original gr_bin_statistics_f, nothing seems to be remotely related to this.
I read that calling PyEval_InitThreads() before PyGILState_Ensure() has solved the problem for some people, but it just causes my program to hang.
Can anyone shed light on this for me? Or is it simply time to send a message to the GNU Radio mailing list?
Using Python2.7 on Fedora 14 x86_64.
Here is the GDB backtrace:
(gdb) c
Continuing.
[New Thread 0x7fabd3a8d700 (LWP 23969)]
[New Thread 0x7fabd328c700 (LWP 23970)]
[New Thread 0x7fabd2a8b700 (LWP 23971)]
[New Thread 0x7fabd228a700 (LWP 23972)]
[New Thread 0x7fabd1a89700 (LWP 23973)]
[New Thread 0x7fabd1288700 (LWP 23974)]
[New Thread 0x7fabd0a87700 (LWP 23975)]
[New Thread 0x7fabbbfff700 (LWP 23976)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fabbbfff700 (LWP 23976)]
0x00000036b3e0db00 in sem_post () from /lib64/libpthread.so.0
(gdb) bt
#0 0x00000036b3e0db00 in sem_post () from /lib64/libpthread.so.0
#1 0x00000036c1317679 in PyThread_release_lock () from /usr/lib64/libpython2.7.so.1.0
#2 0x00007fabd6159c1f in ~ensure_py_gil_state (this=0x2dc6fc0, x=887000000)
at gnuradio_swig_py_general.cc:5593
#3 gr_py_feval_dd::calleval (this=0x2dc6fc0, x=887000000) at gnuradio_swig_py_general.cc:5605
#4 0x00007fabd77c4b6e in gr_noise_level_f::tune_window (this=0x2db3ca0,
target_freq=) at gr_noise_level_f.cc:97
#5 0x00007fabd77c554b in gr_noise_level_f::work (this=0x2db3ca0, noutput_items=7,
input_items=, output_items=)
at gr_noise_level_f.cc:115
#6 0x00007fabd7860714 in gr_sync_block::general_work (this=0x2db3ca0,
noutput_items=, ninput_items=,
input_items=, output_items=) at gr_sync_block.cc:64
#7 0x00007fabd7846ce4 in gr_block_executor::run_one_iteration (this=0x7fabbbffed90)
at gr_block_executor.cc:299
#8 0x00007fabd7864332 in gr_tpb_thread_body::gr_tpb_thread_body (this=0x7fabbbffed90, block=...)
at gr_tpb_thread_body.cc:49
#9 0x00007fabd785cce7 in operator() (function_obj_ptr=...) at gr_scheduler_tpb.cc:42
#10 operator() (function_obj_ptr=...)
at /home/tja/Research/energy/detector/gnuradio-3.3.0/gruel/src/include/gruel/thread_body_wrapper.h:49
#11 boost::detail::function::void_function_obj_invoker0, void>::invoke (function_obj_ptr=...) at /usr/include/boost/function/function_template.hpp:153
---Type to continue, or q to quit---
#12 0x00007fabd74914ef in operator() (this=)
at /usr/include/boost/function/function_template.hpp:1013
#13 boost::detail::thread_data >::run (this=)
at /usr/include/boost/thread/detail/thread.hpp:61
#14 0x00007fabd725ca55 in thread_proxy () from /usr/lib64/libboost_thread-mt.so.1.44.0
#15 0x00000036b3e06d5b in start_thread () from /lib64/libpthread.so.0
#16 0x00000036b3ae4a7d in clone () from /lib64/libc.so.6
(gdb)
Thanks for looking!
Python expects a certain amount of initialization to be done by the main thread before anything attempts to call back in from a subthread.
If the main thread is an application that is embedding Python, then it should call PyEval_InitThreads() immediately after calling Py_Initialize().
If the main thread is instead the Python interpreter itself (as seems to be the case here), then the module using the multithreaded extension module should include an "import threading" early to ensure that PyEval_InitThreads() is called correctly before any subthreads are spawned.
I ran into this exact problem as well. The documentation for anything relating to threads in CPython is unfortunately patchy at best.
Essentially, you need to do the following:
In your main thread, BEFORE any other threads are spawned, you need to call PyEval_InitThreads(). A good place to do this is right after you call PyInitialize().
Now, PyEval_InitThreads() not only initializes the Python interpreter thread-state, it also implicitly acquires the Global Interpreter Lock. This means, you need to release the lock before you call PyGILEnsure_State() in some other thread, otherwise your program will hang. You can do this with the function PyEval_ReleaseLock().
So basically, in your main thread, before any other threads are launched, you want to say:
PyInitialize();
PyEval_InitThreads();
PyEval_ReleaseLock();
Then, in any additional thread, anytime you use the Python API you need to say:
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
/* ... some code that does things with Python ... */
PyGILState_Release(gstate);