I am trying to check for a running server process in a Boost UTF global fixture.
I am doing this with a call to system in my fixture constructor like this...
class MyTestFixture
{
public:
MyTestFixture();
~MyTestFixture() ;
};
MyTestFixture::MyTestFixture()
{
int rc = system("pidof myserver > /dev/null");
if ( rc != 0 )
{
cout << "myserver not running so cannot continue" << endl;
fflush (stdout) ;
sleep(10);
exit(4) ;
}
cout << "fixture setup ok!" << endl ;
}
BOOST_GLOBAL_FIXTURE( MyTestFixture );
BOOST_AUTO_TEST_CASE( pgmiia_main_test1 )
{
// some test code...
}
When "myserver" is running ok everything is fine, but when it isnt I get a crash.
and it doesnt go into the if section and exit.
Strangely if I run it in gdb with myserver not running, it does go into my exit branch as I expect.
I'm a bit new to Boost UTF. I am doing this with a dynamic link.
Any ideas?
Jon
As far as I remember, pidof -s 'proc_name' returns 0 if the proc_name is not running and PID otherwise. Since system should return the retval of the called process, you are actually testing if the process is running: rc != 0, whereas rc == 0 tests if the process is not running. Not sure if the issue somehow relates to the Boost specifics.
Related
As part of my automated test suite, I have a C++ Program (A) that executes a command line Process (B) using CreateProcess().
The process only terminates when it receives a SIGINT signal (for reasons outside of my control).
I can terminate the process (B) from (A) using CloseHandle() and/or TerminateProcess(), however, this does not call the destructor of (B), preventing it from closing gracefully (writing stuff to disk and closing DB connections) and causing the tests to fail.
What is the best approach to gracefully close (B), allowing it clean up after itself? Should I be using a helper executable with IPC, a remote thread...?
I have tried the solutions in these SA questions:
Can I send a ctrl-C (SIGINT) to an application on Windows? (If I detach my console the test suite fails)
How do I send ctrl+c to a process in c#? (Modified for C+)
How to get GenerateConsoleCtrlEvent to work with cmd.exe
Edit: #Remy Lebeau is right I should have posted some code:
Current Approach:
Close the process handle. This kills the process immediately.
PROCESS_INFORMATION process_info;
... // CreateProcess()
CloseHandle(process.hProcess);
CloseHandle(process.hThread);
Approach 2:
Detach the current console and then re-attach. This causes the initial test suite to fail.
PROCESS_INFORMATION process_info;
... // CreateProcess
DWORD thisConsoleId = GetCurrentProcessId();
bool consoleDetached = (FreeConsole() != FALSE);
if (AttachConsole(process_info.dwProcessId)) {
std::cout << "Attached process to console" << std::endl;
SetConsoleCtrlHandler(NULL, true);
if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)) {
std::cout << "Ctrl-c sent to process" << std::endl;
} else {
std::cout << "Could not send ctrl-c (" << GetLastError() << ")" << std::endl;
}
FreeConsole();
} else {
std::cout << "Unable to attach process to console (" << GetLastError() << ")" << std::endl;
}
if (consoleDetached) {
// Create a new console if previous was deleted by OS
if (AttachConsole(thisConsoleId)) {
int errorCode = GetLastError();
// 31=ERROR_GEN_FAILURE
if (errorCode == 31) {
AllocConsole();
}
}
}
Approach 3:
Attach to console without freeing. This kills everything including the test suite.
PROCESS_INFORMATION process_info;
... // CreateProcess
AttachConsole(process_info.dwProcessId);
SetConsoleCtrlHandler(NULL, TRUE);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
I have a programm which I want to get a PID of a task and returns its status (running,stoped and...) and its exit status (dead,zombie and..)
I know C# and java but does not know about linux and C++ much,This is what I have found ...
#include<linux/kernel.h>
#include<linux/syscalls.h>
asmlinkage int sys_pidstat(int pid){
int status = 0;
int rtn = kill(pid, 0);
if (rtn == -1 && errno == ESRCH)
{
return 0;
}
rtn = waitpid(pid, &status, WNOHANG | WUNTRACED | WCONTINUED);
if (rtn == 0) // still live
{
return 0;
}
std::cout << "Probably success. Errno: " << errno << ". StrError: " << strerror(errno) << std::endl;
if (WIFEXITED(status))
{
return 1;
}
return 0;
;
}
I found that waitpid may return the status..But could not mpliment it..waitpid needs a pid as input...What should I give as pid?
It would be great if some one helps me and gives me some hints how to do it?
Thank you so much
waitpid() waits for a child process to terminate. It has nothing to do with the status of some arbitrary process that has no relation whatsover to this process.
The thing about Linux is that it's not some mysterious black box, whose workings are a deep held secret. If someone wants to know how to do something at Linux, all they have to do is look at the source.
I'm sure you know how to use the ps command, which does exactly what you're trying to do.
You can look at the source code of the ps command on https://gitlab.com/procps-ng/procps and see how ps does this, then do the same thing yourself.
Is there a way to execute a binary from my C++ program without a shell? Whenever I use system my command gets run via a shell.
You need to:
fork the process
call one of the "exec" functions in the child process
(if necessary) wait for it to stop
For example, this program runs ls.
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
// for example, let's "ls"
int ls(const char *dir) {
int pid, status;
// first we fork the process
if (pid = fork()) {
// pid != 0: this is the parent process (i.e. our process)
waitpid(pid, &status, 0); // wait for the child to exit
} else {
/* pid == 0: this is the child process. now let's load the
"ls" program into this process and run it */
const char executable[] = "/bin/ls";
// load it. there are more exec__ functions, try 'man 3 exec'
// execl takes the arguments as parameters. execv takes them as an array
// this is execl though, so:
// exec argv[0] argv[1] end
execl(executable, executable, dir, NULL);
/* exec does not return unless the program couldn't be started.
when the child process stops, the waitpid() above will return.
*/
}
return status; // this is the parent process again.
}
int main() {
std::cout << "ls'ing /" << std::endl;
std::cout << "returned: " << ls("/") << std::endl;
return 0;
}
And the output is:
ls'ing /
bin dev home lib lib64 media opt root sbin srv tmp var
boot etc initrd.img lib32 lost+found mnt proc run selinux sys usr vmlinuz
returned: 0
I used popen, fgets and pclose functions to execute external command line program and redirect its output.
I am launching a command using system api (I am ok with using this api with C/C++). The command I pass may hang at times and hence I would like to kill after certain timeout.
Currently I am using it as:
system("COMMAND");
I want to use it something like this:
Run a command using a system independent API (I don't want to use CreateProcess since it is for Windows only) Kill the process if it does not exit after 'X' Minutes.
Since system() is a platform-specific call, there cannot be a platform-independent way of solving your problem. However, system() is a POSIX call, so if it is supported on any given platform, the rest of the POSIX API should be as well. So, one way to solve your problem is to use fork() and kill().
There is a complication in that system() invokes a shell, which will probably spawn other processes, and I presume you want to kill all of them, so one way to do that is to use a process group. The basic idea is use fork() to create another process, place it in its own process group, and kill that group if it doesn't exit after a certain time.
A simple example - the program forks; the child process sets its own process group to be the same as its process ID, and uses system() to spawn an endless loop. The parent process waits 10 seconds then kills the process group, using the negative value of the child process PID. This will kill the forked process and any children of that process (unless they have changed their process group.)
Since the parent process is in a different group, the kill() has no effect on it.
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
int main() {
pid_t pid;
pid = fork();
if(pid == 0) { // child process
setpgid(getpid(), getpid());
system("while true ; do echo xx ; sleep 5; done");
} else { // parent process
sleep(10);
printf("Sleep returned\n");
kill(-pid, SIGKILL);
printf("killed process group %d\n", pid);
}
exit(0);
}
There is no standard, cross-platform system API. The hint is that they are system APIs! We're actually "lucky" that we get system, but we don't get anything other than that.
You could try to find some third-party abstraction.
Check below C++ thread based attempt for linux. (not tested)
#include <iostream>
#include <string>
#include <thread>
#include <stdio.h>
using namespace std;
// execute system command and get output
// http://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c
std::string exec(const char* cmd) {
FILE* pipe = popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
std::string result = "";
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
return result;
}
void system_task(string& cmd){
exec(cmd.c_str());
}
int main(){
// system commad that takes time
string command = "find /";
// run the command in a separate thread
std::thread t1(system_task, std::ref(command));
// gives some time for the system task
std::this_thread::sleep_for(chrono::milliseconds(200));
// get the process id of the system task
string query_command = "pgrep -u $LOGNAME " + command;
string process_id = exec(query_command.c_str());
// kill system task
cout << "killing process " << process_id << "..." << endl;
string kill_command = "kill " + process_id;
exec(kill_command.c_str());
if (t1.joinable())
t1.join();
cout << "continue work on main thread" << endl;
return 0;
}
I had a similar problem, in a Qt/QML development: I want to start a bash command, while continuing to process events on the Qt Loop, and killing the bash command if it takes too long.
I came up with the following class that I'm sharing here (see below), in hope it may be of some use to people with a similar problem.
Instead of calling a 'kill' command, I call a cleanupCommand supplied by the developper. Example: if I'm to call myscript.sh and want to check that it won't last run for more than 10 seconds, I'll call it the following way:
SystemWithTimeout systemWithTimeout("myScript.sh", 10, "killall myScript.sh");
systemWithTimeout.start();
Code:
class SystemWithTimeout {
private:
bool m_childFinished = false ;
QString m_childCommand ;
int m_seconds ;
QString m_cleanupCmd ;
int m_period;
void startChild(void) {
int rc = system(m_childCommand.toUtf8().data());
if (rc != 0) SYSLOG(LOG_NOTICE, "Error SystemWithTimeout startChild: system returned %d", rc);
m_childFinished = true ;
}
public:
SystemWithTimeout(QString cmd, int seconds, QString cleanupCmd)
: m_childFinished {false}, m_childCommand {cmd}, m_seconds {seconds}, m_cleanupCmd {cleanupCmd}
{ m_period = 200; }
void setPeriod(int period) {m_period = period;}
void start(void) ;
};
void SystemWithTimeout::start(void)
{
m_childFinished = false ; // re-arm the boolean for 2nd and later calls to 'start'
qDebug()<<"systemWithTimeout"<<m_childCommand<<m_seconds;
QTime dieTime= QTime::currentTime().addSecs(m_seconds);
std::thread child(&SystemWithTimeout::startChild, this);
child.detach();
while (!m_childFinished && QTime::currentTime() < dieTime)
{
QTime then = QTime::currentTime();
QCoreApplication::processEvents(QEventLoop::AllEvents, m_period); // Process events during up to m_period ms (default: 200ms)
QTime now = QTime::currentTime();
int waitTime = m_period-(then.msecsTo(now)) ;
QThread::msleep(waitTime); // wait for the remaning of the 200 ms before looping again.
}
if (!m_childFinished)
{
SYSLOG(LOG_NOTICE, "Killing command <%s> after timeout reached (%d seconds)", m_childCommand.toUtf8().data(), m_seconds);
int rc = system(m_cleanupCmd.toUtf8().data());
if (rc != 0) SYSLOG(LOG_NOTICE, "Error SystemWithTimeout 164: system returned %d", rc);
m_childFinished = true ;
}
}
I do not know any portable way to do that in C nor C++ languages. As you ask for alternatives, I know it is possible in other languages. For example in Python, it is possible using the subprocess module.
import subprocess
cmd = subprocess.Popen("COMMAND", shell = True)
You can then test if COMMAND has ended with
if cmd.poll() is not None:
# cmd has finished
and you can kill it with :
cmd.terminate()
Even if you prefere to use C language, you should read the documentation for subprocess module because it explains that internally it uses CreateProcess on Windows and os.execvp on Posix systems to start the command, and it uses TerminateProcess on Windows and SIG_TERM on Posix to stop it.
I am working on a C and C++ app that uses some graphical engine to handle gtk windows (Opencv/highgui). This app does some minor output to stdout/cout.
On Windows, starting this kind of app from the desktop automatically opens a console, showing the user what is been written on standard output, either with "printf()" or "std::cout".
On Linux, if I start it from a previously opened console, no trouble. But if I start it through the desktop (double-click), then linux doesn't open an associated console, and data written on stdout/cout is lost.
Seems that this is the normal behaviour on Linux (?).
I would like to automatically open a console from my app, when compiled on a linux platform.
This seems like a dupe of this one, the point is, it doesn't work! I have at present the following code:
#ifndef __WIN32
filebuf* console = new filebuf();
console->open( "/dev/tty", ios::out );
if( !console->is_open() )
cerr << "Can't open console" << endl;
else
cout.ios::rdbuf(console);
#endif
(cerr is redirected in a file using freopen() )
I keep getting "Can't open console". I tried replacing the console name:
console->open( "/dev/console", ios::out );
but that didn't change.
Am I in the right direction? What can I try next? Should I try to open specifically the terminal application (xterm)? But then, how could I "connect" that console with my app?
Solution 1
Very simple solution you might not like: have a script that runs your application in a terminal using gnome-terminal -x <your_program> <your_args>. Double-clicking the script will open the terminal.
Solution 2
A bit more involved solution add a '--noconsole' argument to your application. If the argument is present, just run your application. If '--noconsole' is not present:
if( fork() == 0 ) {
execlp("gnome-terminal", "gnome-terminal", "-x", argv[0], "--noconsole", NULL );
} else {
exit( 0 );
}
This creates a child process in which it runs the application in gnome-terminal using the --noconsole arugment. Makes sense? A bit hacky, but hey, it works.
Solution 3
This one is the trickiest solution, but in some ways more elegant. The idea is to redirect our stdout to a file and create a terminal running tail -f <file_name> --pid=<parent_pid>. This prints the output of the parent process and terminates when the parent dies.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
// Create terminal and redirect output to it, returns 0 on success,
// -1 otherwise.
int make_terminal() {
char pidarg[256]; // the '--pid=' argument of tail
pid_t child; // the pid of the child proc
pid_t parent; // the pid of the parent proc
FILE* fp; // file to which output is redirected
int fn; // file no of fp
// Open file for redirection
fp = fopen("/tmp/asdf.log","w");
fn = fileno(fp);
// Get pid of current process and create string with argument for tail
parent = getpid();
sprintf( pidarg, "--pid=%d", parent );
// Create child process
child = fork();
if( child == 0 ) {
// CHILD PROCESS
// Replace child process with a gnome-terminal running:
// tail -f /tmp/asdf.log --pid=<parent_pid>
// This prints the lines outputed in asdf.log and exits when
// the parent process dies.
execlp( "gnome-terminal", "gnome-terminal", "-x", "tail","-f","/tmp/asdf.log", pidarg, NULL );
// if there's an error, print out the message and exit
perror("execlp()");
exit( -1 );
} else {
// PARENT PROCESS
close(1); // close stdout
int ok = dup2( fn, 1 ); // replace stdout with the file
if( ok != 1 ) {
perror("dup2()");
return -1;
}
// Make stdout flush on newline, doesn't happen by default
// since stdout is actually a file at this point.
setvbuf( stdout, NULL, _IONBF, BUFSIZ );
}
return 0;
}
int main( int argc, char *argv[]) {
// Attempt to create terminal.
if( make_terminal() != 0 ) {
fprintf( stderr, "Could not create terminal!\n" );
return -1;
}
// Stuff is now printed to terminal, let's print a message every
// second for 10 seconds.
int i = 0;
while( i < 10 ) {
printf( "iteration %d\n", ++ i );
sleep( 1 );
}
return 0;
}
Your examples all "open" a console - in the sense that one opens a file. This doesn't do anything to a gui. If you want to do that you will have to open a gtk window and direct the output to it.