I am trying to figure out a way to profile in C a process via its child and after a moment the parent process kills its child to stop profiling. I am using perf to profile my application. perf is going to output its result in a file when killed. It looks like this in a bash script :
./run &
perf stat -o perf.data -p <pid_run> &
kill -9 <pid_perf>
What I have done so far :
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
static pid_t perf_id;
void start() {
char *filename="test_data";
char ppid_str[24];
pid_t pid = fork();
if (pid == 0){
pid_t ppid = getppid();
sprintf(ppid_str, "%d",ppid);
char *args[] = {"/usr/bin/perf", "stat","-p",ppid_str,"-o", filename, NULL};
execvp(args[0], args);
}
else {
perf_id = pid
}
}
void stop() {
kill(perf_id,SIGKILL);
}
I have an issue getting the output of perf.
This is an example of code that could run the parent process :
int main() {
start();
int a = 0;
a+=1;
stop();
// ... // There are other instructions after the stop
return 0;
}
I am not getting any output from perf when running this code. I have to kill the parent process to get an output.
If I put a sleep call before killing the child process, then the program will output an empty file.
EDIT :
stat argument is an example in my command, I want also to use the record argument
As mentioned by Zulan, if I use SIGINT instead of SIGKILL, I will get an output, but I can get one only if the main process sleeps for 1 second.
You should send a SIGINT instead of a SIGKILL in order to allow perf to shutdown cleanly and produce a valid output file. The synchronization between the perf child process and the main process will still be imperfect - so if the main process doesn't take significant time as in your example, it is easily possible that no output file is generated at all. This also affects the accuracy of collected data. With the setup of using perf as a child process rather than vice-versa, you cannot really improve it.
the problem is that perf attaches itself to the process and then waits for process termination to print counters. try adding for example the
-I msec
option to perf like -I 1000 to print counters every 1s.
changing your args to execvp to
char *args[] = {"/usr/bin/perf", "stat", "-p",ppid_str,"-o", filename, "-I", "1000", NULL};
and your inc to a loop of something like
while (a < 10) {
a += 1;
sleep(1);
}
while yield results although the file is not properly closed() in this approach.
I would create a small binary that execs perf with a timeout and gracefully closes the file and run that from the child.
Related
So I have this simple program that sleeps for 4 second if the value returned by fork is '0' meaning that the child process is executing, I've tried using sleep in child process but the program is blocked, and flushing standard output isn't working...
code:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[]) {
pid_t value = fork();
if (value == 0) {
sleep(4);
}
printf("Value returned by fork: %d\n", value);
printf("I'm the process N°%d\n", getpid());
return 0;
}
I'm running on Ubuntu 20.04.3 LTS.
Output:
Value returned by fork: 12618
I'm the process N°12617\
farouk#farouk-HP-Pavilion-Desktop-TP01-1xxx:~/sysexp$ Value returned by fork: 0
I'm the process N°12618
To allow this question to have an accepted answer.
The child process is not blocking the shell. The shell gave its prompt and the child wrote some output after the prompt, leaving the cursor at the start of a line without a shell prompt visible — because the shell prompt already appeared earlier.
There are a variety of ways around this.
The simplest is just to type a command such as ps and hit return, noting that the shell executes it, and that the ps output does not list the child process. If you type the ps command quick enough, you might see the child listed in the output before its output appears.
Another is to modify the program so that it waits for all child processes to exit before it exits — using wait() or waitpid(). The same code can be used in the child and the parent since the child will have no children of its own. The call to the wait function will return immediately with a 'no more children' status (error).
You can find extensive discussion of all this in the comments — I've chosen to make this a Community Wiki answer since there was a lot of activity in the comments that identified the gist of this answer.
Write a C program simulating alarm clock. In the main function, you fork a child process,
and the child process sleeps for 5 seconds (the number of seconds is an command line
argument, see below for a sample run) , after which the child process sends the signal
(SIGALRM) to its parent process. The parent process, after forking the child process,
pause, upon receiving the SIGALRM signal, and prints out a message “Ding!”. The
following is a sample run
$ ./alarm 5
alarm application starting
waiting for alarm to go off
<5 second pause>
Ding!
done
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/wait.h>
#include <stdlib.h>
void Dingdong()
{
printf("Ding!");
exit(1);
}
int main(int argc, char *argv[])
{
if(argc!=3)
{
printf("How much seconds you want to sleep the child process\n");
}
int PauseSecond=(argv[1]);
{
if(fork()==0)
{
printf("waiting for alarm to go off\n");
printf("%d second pause",PauseSecond);
sleep(PauseSecond);
kill(getpid(),SIGALRM);
}
else {
printf("Alarm application starting\n", getpid());
signal(SIGALRM,Dingdong);
printf("done");
}
}
}
Here's what's keeping it from working at all:
int PauseSecond=(argv[1]); That puts the address of the first argument in PauseSecond, which will usually be some really big number. You probably wanted to parse the value of the first argument instead. You need to use something like atoi or strtol on it to do that.
You're calling getpid() after forking, so the child is sending the signal to itself instead of to the parent. Either call getpid() before the fork and save it to a variable, or call getppid() instead.
The parent process is finishing execution and exiting before the child process's sleep ends. You can add the pause() function to the parent process to make it wait for a signal handler to run.
If you want done to print, you can't call exit from the signal handler.
Just fixing the above will get the program sort of working, but there's other things you should consider fixing too:
Since you're not using argv[2] for anything, you should see if argc is 2 instead of 3.
If there aren't enough arguments, you should exit/return instead of continuing and trying to use one that's not there.
You should either put a \n on the end of "%d second pause" or do a manual fflush, or you won't see that until after the sleep.
printf("Alarm application starting\n", getpid()); Your format string won't actually show the result of that getpid().
If you do want to exit from the signal handler, you need to use _Exit, not exit, as the latter isn't async-signal-safe.
So when i invoke this program without sudo. It works fine.
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char** argv)
{
if(fork() == 0) execvp(argv[1], &argv[1]);
// else wait(NULL);
}
But with sudo (when i need to input my password) it gives an odd output:
pasha#skynet:~$ sudo ./a.out bash
[sudo] password for pasha:
pasha#skynet:~$ root#skynet:~#
Then on any input the terminal terminates. Further it only happens on a newly spawned terminal. And when the parent waits for the child the problem with sudo disappears.
Can someone explain why ?
why this happens
You are forking your process, so there are two processes now.
One process is the parent, the process run by your shell, like shell -> fork() -> exec(sudo) -> exec(./a.out). The parent terminates, because fork returns with nonzero and then main() reaches closing }. main by default returns 0. So shell sees that your program terminated with exit status 0. And your shell greets you with a new pasha#skynet:~$ prompt line after your program is done.
The other process is the child, run from your program where fork returned zero, like shell -> fork() -> exec(sudo) -> exec(./a.out) -> fork() -> exec(bash). The child process is bash, it prints root#skynet:~# (it was run after sudo) and waits for input.
Those two processes are running at the same time - ie. your shell (from which you executed sudo ./a.out) and the newly bash run from your program. Both those programs try to read and write to the same input and output at the same time.
The child process, ie. bash, needs to have exclusive control over the input in the terminal. So the child process bash executes tcsetpgrp. But your shell is that one that is controlling your terminal, not the child process. So the child process either receives signal SIGTTOU or maybe SIGTTIN upon trying to read from the input. Then the child bash executed the default handler for the signals - it terminates.
Running sudo bash & from your shell would cause a similar problem to the one that your program causes.
Your program is correct; try it out with "ls" instead of "bash",
$ ./a.out ls -al /tmp
The reason why it does not seem to work with bash is that bash
expect the process to be the group leader of the terminal foreground
process
group, which
it isn't.
That said, while the program is correct, it's severe lack of error
handling is offending :-). For example, when calling a program that
does not exist, execvp() returns with an error (as opposed to not
returning at all) which is ignored. With the effect that ... well
... you can only guess if it worked.
$ ./a.out frobozzzzz
$ # (hm)
Here's my incarnation of it. Longer. Handling errors. Seeing how it
went after child terminated.
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
int main(int argc, char** argv)
{
int status;
pid_t pid, terminated;
pid = fork();
if (pid == -1 /*unlikely*/) {
perror("fork()");
exit(EXIT_FAILURE);
}
if (pid == 0 /*child*/) {
if (execvp(argv[1], &argv[1]) != 0) { // when argv[1] is no
// progrm in path
perror("execvp()");
exit(EXIT_FAILURE);
}
else
assert(!"not getting here because successful exec() never returns");
}
// optional: wait for child to terminate, and print diagnostics
terminated = waitpid(pid, &status, 0);
if (terminated == -1) {
perror("waitpid()");
exit(EXIT_FAILURE);
}
if (terminated == pid) { // how come those not be equal?
if (WIFEXITED(status))
fprintf(stderr, "child terminated with exit status %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
fprintf(stderr, "child terminated by %d\n", WTERMSIG(status));
else
fprintf(stderr, "see \"man waidpid\" for what that could be\n");
}
return 0;
}
I'm wondering if there's a way to start process suspended?
Similar to CreateProcess + CREATE_SUSPENDED in windows:
CreateProcessA(
NULL,
CmdLine,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED,
NULL,
"C:\\Windows\\System32\\",
&si,
&pi);
ptrace seems to support PTRACE_ATTACH only, there's no way to start a process and suspend it directly, any ideas?
EDIT
I need to be able to catch process like this,
int main()
{
exit(0);
}
So the shell approach will not work, as the process quits really fast.
One possible approach would be to take process details as an input in a process, fork, and in child before exec-ing the process, send stop signal to self.
Sample code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
main()
{
int pid;
//Note: Replace argv_list with corresponding binary and arguments
//Can also get these values as command line argument from main(argc, argv)
char *argv_list[] = {"/usr/bin/ls","-lrt", "/", NULL};
if((pid=fork())==0)
{
printf("Child Executing\n");
//Send STOP signal to self to suspend
kill(getpid(), SIGSTOP);
//Sleep for stop signal handler to suspend current process
sleep(1);
//This line should start to execute only after CONT signal is sent.
execv(argv_list[0],argv_list);
}
else
{
printf("Child PID:%d, Parent continuing\n", pid);
}
printf("\n***Main - Exiting\n");
exit(0);
}
There is no one to one comparison for shell but here is which is similar in terms of spinning a process and then suspending it and then starting it again.
###to start a process:
#!/bin/bash
function_some_proc() {
echo "hi"
# if this is too fast you can always use "sleep" to add some time
}
function_some_proc &
FOO_PID=$!
echo "--"
echo $FOO_PID
echo "--"
###then to suspend
kill -STOP <PID>
#to resume
kill -CONT <PID>
The article Creating suspended processes provides an excellent answer to this question. Note that there are problems with this article. Scott Knight, the author of the article, obviously did not bother to confirm that his code examples will actually compile. The parent function refers to a mysterious pid variable.
A complete working example can be found in my StartSuspended project. My StartSuspended project compiles on Microsoft Windows and GNU/Linux. See StartSuspendedPlatformPosix.cpp for the GNU/Linux implementation.
I used the following functions in the GNU/Linux implementation.
ptrace
execvp
waitpid
fork
I'm working on a C program in Xcode on OSX.
The (parent) program has to launch a new (child) process which receives its input via stdin and outputs results to stdout. So the parent writes data to the child process's stdin and the parent reads results from the child process's stdout.
On Windows I use CreateProcess to do the above, but I'm not sure how it's done on OSX in C.
I believe I'm supposed to use exec to start the process, but I don't see how I redirect stdin and stdout of the executable (child process) which exec starts. And from reading the manual it also looks like the child process will become the parent process if I use exec. The child and parent process has to run in parallel so that the parent process can write and read to the child process when it needs to.
Is there a kind OSX C expert out there who could give me a brief example of how the above is done?
Thanks
EDIT
I think I understand. But if the child process is an infinite while-loop which waits for input on stdin, then it won't turn into a "zombie", right?
The child process basically does this:
1. Read data from stdin (i.e. blocked until data is received)
2. Process data
3. Write result to stdout
4. Goto 1
After I read your post, I found this page:
http://www.jukie.net/~bart/snippets/popenRWE/popenRWE.c.html
However, I'm having a problem getting my .exe (child process) to launch
In a terminal, I would start the .exe like this:
./myApp.exe someParam1 someParam2 someParam3
The API looks like this:
popenRWE(int *rwepipe, const char *exe, const char *const argv[])
I'm guessing that the second argument should be:
const char* exe = "./myApp.exe";
and that the third argument should be:
char* p0 = "./myApp.exe";
char* p1 = "someParam1";
char* p2 = "someParam2";
char* p3 = "someParam3";
char** argv[4] = {p0, p1,p2,p3};
Am I right?
I'm including the source of a small library I've written a while ago. That should get you started. Fork / pipe / exec isn't really that easy (especially with all the variants of exec) and it took me a while too. So here goes:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include "limbo.h"
int out_pipe[2], err_pipe[2];
int run_command(char *argv[], int *out_length, int *err_length){
pid_t pid;
int status = 0;
struct stat out_stat, err_stat;
pipe(out_pipe); //create a pipe
pipe(err_pipe);
if(!(pid = fork())) //spawn child
{
// Child. Close the read end of the pipe
close(out_pipe[0]);
close(err_pipe[0]);
// redirect stdout and stderr to the write end of the pipe
dup2(out_pipe[1], STDOUT_FILENO);
dup2(err_pipe[1], STDERR_FILENO);
status = execv(argv[0], argv); //child will terminate here
}
//Only parent gets here. Close write end of the pipe
close(out_pipe[1]);
close(err_pipe[1]);
//or wait for the child process to terminate
waitpid(pid, &status, 0);
fstat(out_pipe[0], &out_stat);
fstat(err_pipe[0], &err_stat);
*out_length = (int) out_stat.st_size;
*err_length = (int) err_stat.st_size;
return status;
}
int read_buffers(char *out_buffer, int out_length, char *err_buffer, int err_length){
out_buffer[read(out_pipe[0], out_buffer, out_length)] = 0;
err_buffer[read(err_pipe[0], err_buffer, err_length)] = 0;
return 0;
}
The comments in the code should help you to understand the code. Feel free to reuse.
Edit
In response to your comment:
The waitpid() call makes the parent process wait for the termination of the child process. If you want both processes to run in parallel, you need to get rid of waitpid() in the place that I use it. But be careful: without a call to one of the wait functions your child process will become a zombie once it finishes. It is your responsibility to keep an eye on your child process and to wait for it so the process can be cleaned up by the kernel.