Windows handling CTRL+C in different thread? - c++

Here is a simple application that handled CTRL+C signal both on linux and windows:
#include <QtCore/QCoreApplication>
#include <QDebug>
#include <QThread>
void SigIntHandler()
{
qDebug()<<"SigInt ThreadID: "<<QThread::currentThreadId();
qApp->quit();
}
#ifdef __linux__
#include <signal.h>
void unix_handler(int s)
{
//svakako je SIGINT, ali da ne javlja warning da se s ne koristi
if (s==SIGINT)
SigIntHandler();
}
#else
#include <windows.h>
BOOL WINAPI WinHandler(DWORD CEvent)
{
switch(CEvent)
{
case CTRL_C_EVENT:
SigIntHandler();
break;
}
return TRUE;
}
#endif
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//kod za hvatanje CTRL+C - unix i windows
#ifdef __linux__
signal(SIGINT, &unix_handler);
#else
SetConsoleCtrlHandler((PHANDLER_ROUTINE)WinHandler, TRUE);
#endif
qDebug()<<"Main ThreadID: "<<QThread::currentThreadId();
return a.exec();
}
After compiling and running it on linux (Debian Squeeze), I get following output:
/Test-build-desktop$ ./Test
Main ThreadID: 140105475446560
^CSigInt ThreadID: 140105475446560
/Test-build-desktop$ ./Test
Main ThreadID: 140369579480864
^CSigInt ThreadID: 140369579480864
/Test-build-desktop$ ./Test
Main ThreadID: 140571925509920
^CSigInt ThreadID: 140571925509920
And that's what I've expected (SigIntHandler method runs on main thread). But when I compile and execute same code on Windows 7, I get this:
d:\Test-build-desktop\debug>Test.exe
Main ThreadID: 0x5a8
SigInt ThreadID: 0x768
d:\Test-build-desktop\debug>Test.exe
Main ThreadID: 0x588
SigInt ThreadID: 0x1434
d:\Test-build-desktop\debug>Test.exe
Main ThreadID: 0x1170
SigInt ThreadID: 0xc38
As you can see, here SigIntHandler method is executed in different thread then main ... And that creates me many problems. So my question is - is it possible to force SigIntHandler to run in main thread on windows ? Am I maybe catching siging wrong ?
Thanks !!

From MSDN topic HandlerRoutine:
A HandlerRoutine function is an application-defined function used with the SetConsoleCtrlHandler function. A console process uses this function to handle control signals received by the process. When the signal is received, the system creates a new thread in the process to execute the function.
So, the answer is: this is impossible.

Read the following link for an interesting take on this: http://blogs.msdn.com/b/oldnewthing/archive/2008/07/28/8781423.aspx

Related

libuv: uv_timer_stop() does not stop and reset the timer

The uv_timer_stop() does not appear to stop and reset the timer. How can I stop and reset the timer correctly?
#include <iostream>
#include <thread>
#include <unistd.h> // usleep
#include <uv.h>
uv_loop_t *loop;
uv_timer_t timer_req;
float timerSeconds = 2.0f;
float sleepSeconds = 1.0f;
void run() {
while (true) uv_run(loop, UV_RUN_DEFAULT);
}
void timerCallback(uv_timer_t* handle) {
std::cout << "Callback" << std::endl;
}
int main() {
loop = uv_default_loop();
std::thread t(run);
uv_timer_init(loop, &timer_req);
while (true) {
std::cout << "sleep" << std::endl;
uv_timer_start(&timer_req, timerCallback, 1000*timerSeconds, 0);
usleep(1000*1000*sleepSeconds);
uv_timer_stop(&timer_req);
};
return 0;
}
output on Debian Linux with libuv1-dev 1.24.1:
$ g++ main.cc -o main `pkg-config --libs libuv`
$ ./main
sleep
sleep
sleep
sleep
sleep
Callback
sleep
^C
Expected output: The timer is set to call the callback after two seconds (float timerSeconds = 2.0f). But we stop (and restart) the timer after every second (float sleepSeconds=1.0f), so the timer should never run long enough for the callback to be executed and the output should show only the 'sleep' messages, instead of the 'Callback' message. That is, it should be:
$ g++ main.cc -o main `pkg-config --libs libuv`
$ ./main
sleep
[...]
I've tried:
stopping the timer inside the callback
reinitialising the timer every time: using uv_timer_init() inside the while loop, before calling uv_timer_start()
Why I am doing this: I'm writing a program to detect the long-press of a button (a short-press of a button triggers a different action). There is a callback to detect a button-press, and a button-depress. The button-press should start the timer, and button-depress should stop the timer. If the button has been pressed down long enough (two seconds), the timer callback executes, and if we reach this callback, then we know that the button has been long-pressed.

How can new gnome terminal receive command in C

I have tried to write a program that run in ubuntu terminal .Program will open a new gnome terminal and run command in that new terminal to open new abcd.txt using vim.And then when i Ctrl+C in the first terminal which run the program ,new gnome terminal will shut vim down and have an announcement in the first terminal
I have tried system("`gnome-terminal`<< vim abcd.txt");
and this system("vim abcd.txt>>`gnome-terminal`");
but the new one terminal cannot recieve command
My full code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
int loop=1;
void DEF()
{
system("kill -9 pidof vim");
loop=0;
}
void *subthreads(void *threadid)
{
loop=1;
long tid;
tid=(long)threadid;
system("`gnome-terminal`<< vim abcd.txt");
signal(SIGINT,DEF);
while(loop){}
pthread_exit(NULL);
}
void main()
{
int loop=1;
pthread_t threads;
int check;
long tID;
check= pthread_create(&threads,NULL,&subthreads,(void*)tID);
while(loop){}
printf("Ctrl+C is pressed!\n");
}
Not sure what you are trying to achieve in the end. But here are a few ideas, starting from your code:
The terminal command (in system()) should be something like Mark Setchell pointed out, like for example system("gnome-terminal -e vim file.txt");
The system() command is blocking further execution of your code, so the call to signal() is not happening until you terminate the system() call.
pidof is not working on my Linux system. I would use pkill <program>. Still, that would kill all running instances of , for example vim or your terminal.
You are declaring the variable loop in the global scope first and then redeclaring it in main(). If you really want to use it as a global variable, it should just be loop=1 in main().
You are not using the variable tid for anything.
Here is an improved version of your program, with additional printf calls to explain to the user what is happening. I also used xterm and nano because I don't have gnome-terminal, and I didn't want to interfere with my running instance of vim. But it still is maybe not exactly what you are trying to do. The main problem is that system("xterm -e sh &") is blocking and when you press Ctrl-C, that system call will terminate xterm so that the def() function will do nothing when it is called later.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
int loop = 1;
void def()
{
printf("In def\n");
system("pkill xterm");
loop=0;
}
void *subthreads(void *threadid)
{
printf("Starting subthread\n");
loop = 1;
long tid;
tid = (long)threadid;
signal(SIGINT, def);
system("xterm -e sh -c nano &"); // Note: xterm will still exit when you press Ctrl-C
printf("Terminal exited in subthread\n");
while (loop);
printf("Exited loop in subthread\n");
pthread_exit(NULL);
}
void main()
{
pthread_t threads;
int check;
long tID;
check = pthread_create(&threads, NULL, &subthreads, (void*)tID);
printf("In main after thread creation\n");
while (loop);
printf("Ctrl+C is pressed!\n");
}
Another option is to use fork() instead of pthread to split into a separate process. (Note that processes are like separate applications while threads are processor threads in the same application.)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
void def()
{
system("pkill nano");
printf("def(): Killed nano\n");
}
int subprocess()
{
signal(SIGINT, def);
pid_t parent_id = getpid(); // Get process ID of main process
fork(); // Fork into two identical copies of the running app.
if (getpid() != parent_id) { // The part in the if block is only done in the second process!
system("xterm -e sh -c nano &");
printf("subprocess(): system call ended in forked process\n");
exit(0);
}
}
int main()
{
subprocess();
printf("Entering while loop in main process\n");
while (1);
printf("Exited main thread\n");
}
The one flaw with this version is the same as the previous one: when Ctrl-C is pressed, xterm/nano is killed and def() will subsequently do nothing except catch any Ctrl-C done afterwards.
If you explain further what your final goal is, maybe I can give some suggestions.
Like, why do you want to start vim in a terminal from a C application and then kill vim? Do you want to kill the whole terminal or only vim?

How run gtest and make sure sigabrt never happens

I need a gtest that will pass if sigabrt doesn't happen, but need to know if it does happen, or fail the test. How would I do that?
I was thinking of this sort of thing:
TEST_F(TestTest, testSigabrtDoesntHappen)
{
MyObject &myObject = MyObject::instance();
for(int i=0; i<2; i++){
myObject.doWork(); //this will sigabrt on the second try, if at all
ASSERT_TRUE(myObject);
}
ASSERT_TRUE(myObject);
}
So assuming a sigabrt would exit out of the test if it occurs, then we would get 3 test passes otherwise. Any other ideas?
Not on Window:
::testing::KilledBySignal(signal_number) // Not available on Windows.
You should look the guide.
It seems like that for me (not tested) :
TEST_F(TestTest, testSigabrtDoesntHappen)
{
MyObject &myObject = MyObject::instance();
for(int i=0; i<2; i++){
EXPECT_EXIT(myObject.doWork(), ::testing::KilledBySignal(SIGBART)), "Regex to match error message");
ASSERT_TRUE(myObject);
}
ASSERT_TRUE(myObject);
}
On Window:
You'll have to handle signal yourself with this kind of code:
// crt_signal.c
// compile with: /EHsc /W4
// Use signal to attach a signal handler to the abort routine
#include <stdlib.h>
#include <signal.h>
#include <tchar.h>
void SignalHandler(int signal)
{
if (signal == SIGABRT) {
// abort signal handler code
} else {
// ...
}
}
int main()
{
typedef void (*SignalHandlerPointer)(int);
SignalHandlerPointer previousHandler;
previousHandler = signal(SIGABRT, SignalHandler);
abort(); //emit SIGBART ?
}
doc
But seriously if you have one time get a SIGBART running your code, there are some problems with your code that you have to remove before release the software.
But if you really want to debug your code (with googletest), use this with your debugger:
foo_test --gtest_repeat=1000 --gtest_break_on_failure
You can add others option to it, again : check the doc :)

Reading console output of a detached process

Hi I am firing a detached process from Qt using QProcess. I want to read the console output of the process in a QString. Here is the code
#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QProcess proc;
proc.startDetached("C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\powershell.exe",
QStringList() << "/c" << "c:\\Qt\\Qt5.3.0\\Tools\\QtCreator\\bin\\tryScript\\firstBatch.bat");
proc.waitForFinished();
qDebug() << proc.readAllStandardOutput();
return a.exec();
}
QProcess::startDetached is not a member function, its a static function, so
proc.startDetached(...)
is equivalent to :
QProcess::startDetached(...)
Hence there's no state or output in your proc variable for the detached process. Use the start() method if you want to start the process as a subprocess of your application and read its output.

gdb 7.0, signal SIGCONT doesn't break from a pause() call

I'd built a version of gdb 7.0 for myself after being pointed to a new feature, and happened to have that in my path still.
Attempting to step through some new code, I'd added a pause() call, expecting to be able to get out like so:
(gdb) b 5048
Breakpoint 1 at 0x2b1811b25052: file testca.C, line 5048.
(gdb) signal SIGCONT
Continuing with signal SIGCONT.
Breakpoint 1, FLUSH_SUDF_TEST (h=#0x2b1811b061c0) at testca.C:5048
5048 rc = h.SAL_testcaFlushPagesByUDF( uPrimary - 1, uPrimary ) ;
(that was with the system gdb, version 6.6).
With gdb 7.0 I never hit the post-pause() breakpoint when I try this. With the various multi process debugging changes in gdb 7, does anybody know if signal handling has to be handled differently and how?
The pause() function does not return unless a signal handler is called (see the specification and the man page).
To make it return after your program receives SIGCONT, you must install an handler for SIGCONT. Try and see using the following example:
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
volatile int caught_signal = 0;
void handler(int sig)
{
caught_signal = sig;
}
int main()
{
signal(SIGCONT, handler);
pause();
printf("Caught signal: %d, %s\n",
caught_signal, strsignal(caught_signal));
return 0;
}
The behavior is correct with gdb 7.0: pause() completely ignores ignored signals (like SIGCHLD, returns on caught signals (SIGCONT), and no signal is delivered when the continue command is issued.
(gdb) break 17
Breakpoint 1 at 0x80484b3: file pause.c, line 17.
(gdb) continue
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x0012d422 in __kernel_vsyscall ()
(gdb) signal SIGCHLD
Continuing with signal SIGCHLD.
^C
Program received signal SIGINT, Interrupt.
0x0012d422 in __kernel_vsyscall ()
(gdb) signal SIGCONT
Continuing with signal SIGCONT.
Breakpoint 1, main () at pause.c:17
17 printf("Caught signal: %d, %s\n",
(gdb)