linux-get Task status of a PID in C++ - c++

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.

Related

Fork and kill in C++ crashes ubuntu

i have problem with small piece of my code.
void setTimeout(int time)
{
if (fork() == 0) {
pid_t id = getppid();
sleep(time);
if(kill(id, 0) == ESRCH)
return;
cerr << "Time out!" << endl;
kill(id, TIMEOUT);
return;
}
}
When the parent process is running and I don't need to kill him, nothing happens and it close as it should, but if parent process ends before timeout, ubuntu crashes.
Thanks for your time.
After the parent process terminates, getppid will return the process id of the shell that launched it. So you are killing the shell, which is why you drop to the login screen.
See also:
getppid() not returning parent's pid

How to clear a POSIX Message Queue?

I am currently working on a program that does IPC via Posix Message Queues. I now need a function that removes every message of that queue. The problem is: My code deadlocks. Currently I am trying the following:
void clear_mq(std::string queue_name)
{
struct mq_attr mq_attrs = {0, 10, sizeof(uint8_t), 0};
mqd_t mq = ::mq_open(queue_name.c_str(), O_WRONLY | O_CREAT, 00644, &mq_attrs);
if (mq < 0)
{
std::cout << "Error opening Queue" << std::endl;
exit(-1);
}
struct mq_attr num_messages;
if (mq_getattr(mq, &num_messages) == -1)
{
std::cout << "Error!" << std::endl;
exit(-1);
}
while (num_messages.mq_curmsgs > 0)
{
uint8_t buf;
mq_receive(mq, (char *)&buf, sizeof(uint8_t), NULL);
if (mq_getattr(mq, &num_messages) == -1)
{
std::cout << "Error!" << std::endl;
exit(-1);
}
}
mq_close(mq);
}
Can anyone point out what I am doing wrong? I do not understand why the receive is blocking... At that moment when I call clear_mq noone else is in the receive block...
Could be that mq_receive() fails and you end up in a endless loop.
mq_receive() can fail for various reasons, e.g. the buffer provided must at least have the size of the mq-maxsize.
You should check the return value of mq_receive() and exit the loop if it fails.
You IMHO have no deadlock. However, the mq_receive blocks until it receives a message (man mq_receive) because the queue is not open with O_NONBLOCK parameter while mq_open.
Please also ensure you do not neglect the return value of the mq_receive in the loop.
In case someone else has the problem.
When printing the errno I get error 9 (Bad file descriptor), which makes sense cause the message queue is only opened for write but you are trying to read from it. When you open the queue with O_RDWR see mq_open it should work.
A tip for debugging use mq_timedreceive so that you can check the error.

C++ Timed Process

I'm trying to set up some test software for code that is already written (that I cannot change). The issue I'm having is that it is getting hung up on certain calls, so I want to try to implement something that will kill the process if it does not complete in x seconds.
The two methods I've tried to solve this problem were to use fork or pthread, both haven't worked for me so far though. I'm not sure why pthread didn't work, I'm assuming it's because the static call I used to set up the thread had some issues with the memory needed to run the function I was calling (I continually got a segfault while the function I was testing was running). Fork worked initially, but on the second time I would fork a process, it wouldn't be able to check to see if the child had finished or not.
In terms of semi-pseudo code, this is what I've written
test_runner()
{
bool result;
testClass* myTestClass = new testClass();
pid_t pID = fork();
if(pID == 0) //Child
{
myTestClass->test_function(); //function in question being tested
}
else if(pID > 0) //Parent
{
int status;
sleep(5);
if(waitpid(0,&status,WNOHANG) == 0)
{
kill(pID,SIGKILL); //If child hasn't finished, kill process and fail test
result = false;
}
else
result = true;
}
}
This method worked for the initial test, but then when I would go to test a second function, the if(waitpid(0,&status,WNOHANG) == 0) would return that the child had finished, even when it had not.
The pthread method looked along these lines
bool result;
test_runner()
{
long thread = 1;
pthread_t* thread_handle = (pthread_t*) malloc (sizeof(pthread_t));
pthread_create(&thread_handle[thread], NULL, &funcTest, (void *)&thread); //Begin class that tests function in question
sleep(10);
if(pthread_cancel(thread_handle[thread] == 0))
//Child process got stuck, deal with accordingly
else
//Child process did not get stuck, deal with accordingly
}
static void* funcTest(void*)
{
result = false;
testClass* myTestClass = new testClass();
result = myTestClass->test_function();
}
Obviously there is a little more going on than what I've shown, I just wanted to put the general idea down. I guess what I'm looking for is if there is a better way to go about handling a problem like this, or maybe if someone sees any blatant issues with what I'm trying to do (I'm relatively new to C++). Like I mentioned, I'm not allowed to go into the code that I'm setting up the test software for, which prevents me from putting signal handlers in the function I'm testing. I can only call the function, and then deal with it from there.
If c++11 is legit you could utilize future with wait_for for this purpose.
For example (live demo):
std::future<int> future = std::async(std::launch::async, [](){
std::this_thread::sleep_for(std::chrono::seconds(3));
return 8;
});
std::future_status status = future.wait_for(std::chrono::seconds(5));
if (status == std::future_status::timeout) {
std::cout << "Timeout" <<endl ;
} else{
cout << "Success" <<endl ;
} // will print Success
std::future<int> future2 = std::async(std::launch::async, [](){
std::this_thread::sleep_for(std::chrono::seconds(3));
return 8;
});
std::future_status status2 = future2.wait_for(std::chrono::seconds(1));
if (status2 == std::future_status::timeout) {
std::cout << "Timeout" <<endl ;
} else{
cout << "Success" <<endl ;
} // will print Timeout
Another thing:
As per the documentation using waitpid with 0 :
meaning wait for any child process whose process group ID is equal to
that of the calling process.
Avoid using pthread_cancel it's probably not a good idea.

How to get pid of process executed with system() command in c++

When we use system() command, program wait until it complete but I am executing a process using system() and using load balance server due to which program comes to next line just after executing system command. Please note that that process may not be complete.
system("./my_script");
// after this I want to see whether it is complete or not using its pid.
// But how do i Know PID?
IsScriptExecutionComplete();
Simple answer: you can't.
The purpose of system() is to block when command is being executed.
But you can 'cheat' like this:
pid_t system2(const char * command, int * infp, int * outfp)
{
int p_stdin[2];
int p_stdout[2];
pid_t pid;
if (pipe(p_stdin) == -1)
return -1;
if (pipe(p_stdout) == -1) {
close(p_stdin[0]);
close(p_stdin[1]);
return -1;
}
pid = fork();
if (pid < 0) {
close(p_stdin[0]);
close(p_stdin[1]);
close(p_stdout[0]);
close(p_stdout[1]);
return pid;
} else if (pid == 0) {
close(p_stdin[1]);
dup2(p_stdin[0], 0);
close(p_stdout[0]);
dup2(p_stdout[1], 1);
dup2(::open("/dev/null", O_RDONLY), 2);
/// Close all other descriptors for the safety sake.
for (int i = 3; i < 4096; ++i)
::close(i);
setsid();
execl("/bin/sh", "sh", "-c", command, NULL);
_exit(1);
}
close(p_stdin[0]);
close(p_stdout[1]);
if (infp == NULL) {
close(p_stdin[1]);
} else {
*infp = p_stdin[1];
}
if (outfp == NULL) {
close(p_stdout[0]);
} else {
*outfp = p_stdout[0];
}
return pid;
}
Here you can have not only PID of the process, but also it's STDIN and STDOUT. Have fun!
Not an expert on this myself, but if you look at the man page for system:
system() executes a command specified in command by calling /bin/sh -c command, and returns after the command has been completed
You can go into the background within the command/script you're executing (and return immediately), but I don't think there's a specific provision in system for that case.
Ideas I can think of are:
Your command might return the pid through the return code.
Your code might want to look up the name of the command in the active processes (e.g. /proc APIs in unix-like environments).
You might want to launch the command yourself (instead of through a SHELL) using fork/exec
As the other answers said, std::system blocks until complete anyway. However, if you want to run the child process async and you are ok with boost you can use boost.process (ref):
#include <boost/process.hpp>
namespace bp = boost::process;
bp::child c(bp::search_path("echo"), "hello world");
std::cout << c.id() << std::endl;
// ... do something with ID ...
c.wait();
You can check exit status of your command by following code :
int ret = system("./my_script");
if (WIFEXITED(ret) && !WEXITSTATUS(ret))
{
printf("Completed successfully\n"); ///successful
}
else
{
printf("execution failed\n"); //error
}

waitpid/wexitstatus returning 0 instead of correct return code

I have the helper function below, used to execute a command and get the return value on posix systems. I used to use popen, but it is impossible to get the return code of an application with popen if it runs and exits before popen/pclose gets a chance to do its work.
The following helper function creates a process fork, uses execvp to run the desired external process, and then the parent uses waitpid to get the return code. I'm seeing odd cases where it's refusing to run.
When called with wait = true, waitpid should return the exit code of the application no matter what. However, I'm seeing stdout output that specifies the return code should be non-zero, yet the return code is zero. Testing the external process in a regular shell, then echoing $? returns non-zero, so it's not a problem w/ the external process not returning the right code. If it's of any help, the external process being run is mount(8) (yes, I know I can use mount(2) but that's besides the point).
I apologize in advance for a code dump. Most of it is debugging/logging:
inline int ForkAndRun(const std::string &command, const std::vector<std::string> &args, bool wait = false, std::string *output = NULL)
{
std::string debug;
std::vector<char*> argv;
for(size_t i = 0; i < args.size(); ++i)
{
argv.push_back(const_cast<char*>(args[i].c_str()));
debug += "\"";
debug += args[i];
debug += "\" ";
}
argv.push_back((char*)NULL);
neosmart::logger.Debug("Executing %s", debug.c_str());
int pipefd[2];
if (pipe(pipefd) != 0)
{
neosmart::logger.Error("Failed to create pipe descriptor when trying to launch %s", debug.c_str());
return EXIT_FAILURE;
}
pid_t pid = fork();
if (pid == 0)
{
close(pipefd[STDIN_FILENO]); //child isn't going to be reading
dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd
dup2(pipefd[STDOUT_FILENO], STDERR_FILENO);
if (execvp(command.c_str(), &argv[0]) != 0)
{
exit(EXIT_FAILURE);
}
return 0;
}
else if (pid < 0)
{
neosmart::logger.Error("Failed to fork when trying to launch %s", debug.c_str());
return EXIT_FAILURE;
}
else
{
close(pipefd[STDOUT_FILENO]);
int exitCode = 0;
if (wait)
{
waitpid(pid, &exitCode, wait ? __WALL : (WNOHANG | WUNTRACED));
std::string result;
char buffer[128];
ssize_t bytesRead;
while ((bytesRead = read(pipefd[STDIN_FILENO], buffer, sizeof(buffer)-1)) != 0)
{
buffer[bytesRead] = '\0';
result += buffer;
}
if (wait)
{
if ((WIFEXITED(exitCode)) == 0)
{
neosmart::logger.Error("Failed to run command %s", debug.c_str());
neosmart::logger.Info("Output:\n%s", result.c_str());
}
else
{
neosmart::logger.Debug("Output:\n%s", result.c_str());
exitCode = WEXITSTATUS(exitCode);
if (exitCode != 0)
{
neosmart::logger.Info("Return code %d", (exitCode));
}
}
}
if (output)
{
result.swap(*output);
}
}
close(pipefd[STDIN_FILENO]);
return exitCode;
}
}
Note that the command is run OK with the correct parameters, the function proceeds without any problems, and WIFEXITED returns TRUE. However, WEXITSTATUS returns 0, when it should be returning something else.
Probably isn't your main issue, but I think I see a small problem. In your child process, you have...
dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd
dup2(pipefd[STDOUT_FILENO], STDERR_FILENO); //but wait, this pipe is closed!
But I think what you want is:
dup2(pipefd[STDOUT_FILENO], STDOUT_FILENO);
dup2(pipefd[STDOUT_FILENO], STDERR_FILENO);
close(pipefd[STDOUT_FILENO]); //now that it's been dup2'd for both, can close
I don't have much experience with forks and pipes in Linux, but I did write a similar function pretty recently. You can take a look at the code to compare, if you'd like. I know that my function works.
execAndRedirect.cpp
I'm using the mongoose library, and grepping my code for SIGCHLD revealed that using mg_start from mongoose results in setting SIGCHLD to SIG_IGN.
From the waitpid man page, on Linux a SIGCHLD set to SIG_IGN will not create a zombie process, so waitpid will fail if the process has already successfully run and exited - but will run OK if it hasn't yet. This was the cause of the sporadic failure of my code.
Simply re-setting SIGCHLD after calling mg_start to a void function that does absolutely nothing was enough to keep the zombie records from being immediately erased.
Per #Geoff_Montee's advice, there was a bug in my redirect of STDERR, but this was not responsible for the problem as execvp does not store the return value in STDERR or even STDOUT, but rather in the kernel object associated with the parent process (the zombie record).
#jilles' warning about non-contiguity of vector in C++ does not apply for C++03 and up (only valid for C++98, though in practice, most C++98 compilers did use contiguous storage, anyway) and was not related to this issue. However, the advice on reading from the pipe before blocking and checking the output of waitpid is spot-on.
I've found that pclose does NOT block and wait for the process to end, contrary to the documentation (this is on CentOS 6). I've found that I need to call pclose and then call waitpid(pid,&status,0); to get the true return value.