I would like to get the number of ALL running processes and ALL running threads of my Linux system. I need this information IN a C application. From the terminal, I can get his info with
$ ps -A --no-headers | wc -l
for processes and
$ ps -AL --no-headers | wc -l
for processes including tasks.
I didn't find this info in /proc.
Any suggestions?
The ps examples in your question don't really give you the information you're asking about: the first lists all the processes on your system, not just those spawned by a particular program, and similarly the second lists the number of threads in every process.
If you want to find information about threads spawned by a particular process, you can look in /proc under /proc/<pid>/task. For example, here is a process with a single thread:
bash-4.4$ ls /proc/15355/task/
15355
And here's one that has three threads (in addition to the main thread):
bash-4.4$ ls /proc/15295/task/
15295 15296 15297 15298
The corresponding ps -L output for that process looks like:
bash-4.4$ ps -L -p 15295
PID LWP TTY TIME CMD
15295 15295 pts/4 00:00:00 python
15295 15296 pts/4 00:00:00 python
15295 15297 pts/4 00:00:00 python
15295 15298 pts/4 00:00:00 python
Getting the number of running processes from /proc takes a little more work, since Linux only maintains information about a process' parent, rather than it's children. That means you would need to scan through /proc and find every process for which the parent is your target process...and then repeat recursively for each of those processes.
You can use something like pstree to get this information, of course, but that output isn't really designed to be machine parseable.
Every running process has a corresponding directory /proc/<pid>. You can use that to count the number of running processes (by counting all sub-directories of /proc that are numeric).
Inside each of these directories you can check /proc/<pid>/status to get information about the process. Specifically, the line Threads: <cnt> gives you the number of threads for that process.
Refer to man proc for more info on the /proc (pseudo) file system.
The simplest is to parse the output of commands using popen.
The following:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void parse_output(char *buf, size_t bufsize, const char cmd[])
{
assert(buf != NULL);
assert(cmd != NULL);
FILE *fp;
// add dynamic allocation here
memset(buf, 0, bufsize);
if ((fp = popen(cmd, "r")) == NULL) {
printf("Error opening pipe!\n");
exit(-__LINE__);
}
// worst speed ever. And strlen is called twice...
while (fgets(&buf[strlen(buf)], bufsize - strlen(buf), fp) != NULL);
if(pclose(fp)) {
printf("Command not found or exited with error status\n");
exit(-__LINE__);
}
}
int main() {
char buf[256];
long num;
parse_output(buf, sizeof(buf), "ps -A --no-headers | wc -l");
if (sscanf(buf, "%ld", &num) != 1) {
exit(-__LINE__);
}
printf("Number of processes: %ld\n", num);
parse_output(buf, sizeof(buf), "ps -AL --no-headers | wc -l");
if (sscanf(buf, "%ld", &num) != 1) {
exit(-__LINE__);
}
printf("Number of processes including tasks: %ld\n", num);
}
will output on my system:
$ gcc 1.c && ./a.out
Number of processes: 241
Number of processes includeing tasks: 867
Related
I compiled and install a new version of the kernel and now I have to make the new kernel support two new primitives, I explain more below
I have this file, mysystemcalls-test.c where I get the process and do forks in a for iteration. This is my test file.
//mysyscalls-test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <mysyscalls.h>
#define NCHILDREN 10
int main()
{
int pids[NCHILDREN], i;
int original_parent = getpid();
printf ("before fork: current number of children: %ld\n", getnchildren(1));
for (i=0; i<NCHILDREN; i++) {
pids[i] = fork();
if (pids[i] == 0) {
while (getppid() == original_parent);
exit(0);
}
}
printf("after fork: current number of children: %ld\n", getnchildren(1));
for(i=0; i<NCHILDREN; i++)
printf("pids[%d]:%d\tgetcpid(%d,1):%ld\n" ,i,pids[i],i,getcpid(i,1));
return 0;
}
The real problem is in the second file, mysyscalls.h I can't make the right call for the child process.
//mysyscalls.h
long getnchildren (int debug){
int children;
children = pids[i];
return children;
}
long getcpid (int order, int debug){
int childrenid;
childrenid = getpid();
return childrenid;
}
I don't know how to call these pids in the mysyscalls.h file. I searched and tested some code that I found here but I don't have an exact answer for my problem. I wrote that code but isn't working, it return the same pid.
It's supposed that long getnchildren returns the number of child processes that the calling process has, at the moment the primitive is called.
long getcpid returns the pid of the child of the calling process, at position order in the list of its children.
Get your own pid with getpid.
Iterate through all directories in /proc that start with a digit.
For each such directory, open the status file.
Read all the lines until you find the PPid line.
If the PPid matches the value from getpid, add this directory name to your array.
That will get you the IDs of every process whose parent process is this process.
This outlines a simple way to do some common functions involving for PIDs. If I were you, I would circumvent trying to do this in C. More trouble than its worth, IMO.
#!/bin/bash
# getting children generally resolves nicely at some point
get_child() {
echo $(pgrep -laP $1 | awk '{print $1}')
}
# recursively getting parents isn't that useful,
# so single use function
get_parent() {
echo $(ps -o ppid= -p 36700)
}
get_children() {
__RET=$(get_child $1)
__CHILDREN=
while [ -n "$__RET" ]; do
__CHILDREN+="$__RET "
__RET=$(get_child $__RET)
done
__CHILDREN=$(echo "${__CHILDREN}" | xargs | sort)
echo "${__CHILDREN}"
}
get_children $1
FILE *fp;
char path[1024];
char command[1024];
sprintf(command, "/bin/bash /get_pids.sh %d", getpid());
fp = popen(command, "r");
while (fgets(path, sizeof(path), fp) != NULL) {
// children are listed here
printf("%s", path);
}
pclose(fp);
I've been trying to cook up an unholy one-liner for David Schwartz's method, but I think it is a fully cursed solution. Some other bash-abuser can take a crack at it.
Here is a C program which operates finding specific properties like CPU bus info by consecutive calls of lshw (to access total hardware list with respective properties) and grep (to select just a relevant point among lshw results):
char *strCombine(char *str1, char *str2, int n)
{
int i = strlen(str2);
int j = 0;
if((str2 = (char *) realloc(str2, (i + n + 1))) == NULL)
perror(0);
while(j < n && str1[j])
{
str2[i] = str1[j];
i++;
j++;
}
str2[i] = 0;
return (str2);
}
int main()
{
pid_t parent;
char buf[1000] = {0};
char *str;
char *argv[6] = {"/usr/bin/lshw", "-C", "CPU", "|", "grep", "bus info"};
int fd[2];
int ret;
if(pipe(fd) == -1)
{
perror(NULL);
return -1;
}
parent = fork();
if(parent == 0)
{
close(fd[1]);
while((ret = read(fd[0], buf, 1000)))
str = strCombine(buf, str, ret);
close(fd[0]);
}
else
{
close(fd[0]);
execv(argv[0], argv);
close(fd[1]);
wait(0);
}
wait(0);
printf("%s", str);
return 0;
}
In this code grep is expected to follow lshw since both go executed by invoking execv. However, this pipeline doesn't work because lshw usage reference gets printed out in terminal (running on Ubuntu 18.04 LTS) instead of bus info needed originally. What makes this program failed to show just info that matters and what way must I try to set up pipeline?
The vertical bar is not a parameter you use to separate commands, as the execve(2) system call will load a program into the virtual space of one process only. You need to create two processes, one per command you want to execute, and communicate them so input from one goes to output from the other. I think also you'll be interested in the output of the last command, so you need to do two redirections (one from the first command to the second, and one from the output of the second command to a pipe descriptor), two forks, and two exec's in order to do this.
First the good news, you can do all this stuff with a simple call to popen(3) without the nitty gritties of making forks and execs while redirecting i/o from individual commands. Just use this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *cmd = "/usr/bin/lshw -C CPU | grep 'bus info'";
int n = 0;
char line[1000];
/* f will be associated to the output of the pipeline, so you can read from it.
* this is stated by the "r" of the second parameter */
FILE *f = popen(cmd, "r");
if (!f) {
perror(cmd);
exit(EXIT_FAILURE);
}
/* I read, line by line, and process the output,
* printing each line with some format string, but
* you are free here. */
while (fgets(line, sizeof line, f)) {
char *l = strtok(line, "\n");
if (!l) continue;
printf("line %d: [%s]\n", ++n, l);
}
/* once finished, you need to pclose(3) it. This
* makes program to wait(2) for child to finish and
* closing descriptor */
pclose(f);
}
If you need to mount such a pipeline you'll end having to
redirections from first command to second, from second to
parent process, and fork/exec both processes yourself.
In this approach, you handle a subshell to do the piping
and redirection work for you, and just you get a FILE * descriptor to read upon.
(if I find some time, I'll show you a full example of a chain of N commands with redirections to pipe them, but I cannot promise, as I have to write the code)
NOTE
fork() returns the pid of the child process to the parent, and 0 to the child process itself. I don't understand why you have a variable named parent where you store the value received from fork(). If it is nonzero (and non-negative) it represents the pid of a child process. You need two, as you need two processes. In the example I post, you create three processes (you ask a subshell to mount the pipeline for you, so you have a subshell you instruct to create two more processes, to execute your command) If you had to mount all this paraphernalia, you'd also to wait(2) for the children to finish (this is done in pclose(3) call)
I have a little program to spawn a process (only one) repeatedly, while overprinting its output in the same place. I use it as some kind of htop program when I try to see e.g. the output of ls -l (showing a file growing as it is being filled) or the output of df command. It starts the program, makes one fork, redirects the output of it to a pipe and gets the output of the command to count the number of lines output (to emit an escape sequence to put the cursor on top of the listing, and to emit a clear to the end of line after each output line, so shorter lines dont get blurred by longer ones. It shows you how to deal with forks and exec system calls, and you can use as example on how to do the things the brave way. But having popen(3) I think is the solution to your problem. If you want to have a look to my cont program, just find it here.
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.
Given a process' pid, how can I determine if the process is paused (with SIGSTOP) or running?
I'm using OS X, so I don't have a /proc directory.
This is how you do it:
#include <stdio.h>
#include <sys/sysctl.h>
#include <stdlib.h>
#include <string.h>
#define IS_RUNNING(proc) ((proc->kp_proc.p_stat & SRUN) != 0)
#define ERROR_CHECK(fun) \
do { \
if(fun) { \
goto ERROR; \
}\
} while(0)
struct kinfo_proc *proc_info_for_pid(pid_t pid) {
struct kinfo_proc *list = NULL;
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
size_t size = 0;
ERROR_CHECK(sysctl(mib, sizeof(mib) / sizeof(*mib), NULL, &size, NULL, 0));
list = malloc(size);
ERROR_CHECK(sysctl(mib, sizeof(mib) / sizeof(*mib), list, &size, NULL, 0));
return list;
ERROR:
if(list) {
free(list);
}
return NULL;
}
int main() {
pid_t pid = 1000;
struct kinfo_proc *proc_info = proc_info_for_pid(pid);
if(proc_info) {
printf("Is running: %d\n", IS_RUNNING(proc_info));
} else {
printf("Could not stat process!");
return 1;
}
return 0;
}
It's not a great answer, but it IS an answer.. you can run ps aux (from within your program) and see if the STAT column is T (stopped). Just checked that on mountain lion.
Not sure how it figures it out.
I think I'm getting closer with the kvm_* functions:
Get other process' argv in OS X using C
also
kvm_getargv()
http://www.daemon-systems.org/man/kvm_getproc2.3.html
and the source for PS: http://bxr.su/o/bin/ps/ps.c
In man ps you can read about T state of the process:
T Marks a stopped process.
To determine if the process is stopped, running ps j will show you T flag in stat column.
In Bash to show all current stopped processes, run: jobs -s (see help jobs). To kill them run: kill $(jobs -sp).
If these processes aren't attached to the current shell, to show all stopped processes, this command may help:
ps wuax | awk '$8 ~ "T"'
Here is command to resume all stopped processes:
kill -CONT $(ps wuax | awk 'NR>1 && $8 ~ "T" {print $2}')
To kill these processes instead, replace -CONT with -9.
If you have paused processes, they won't show as stopped (with T), so to resume them, use the following command instead:
pkill -CONT -u $UID
or for a specific process (such as Chrome), try:
kill -CONT $(pgrep Chrome)
My program is as follow:
//... init fd[2] as pipe ...
if (child==0){
close(fd[1]);
dup2(fd[0], 0);
execlp("/bin/sh","sh",NULL);
} else {
close(fd[0]);
char *line; int nbytes=100; int bytes=0;
line=(char*) malloc(nbytes+1);
while ( (bytes = getline((char **)&line,&nbytes,stdin))!= -1 ){
write(fd[1],line, bytes);
}
}
This run OK, however when I try to replace exec("/bin/sh","sh",NULL) with exec("/bin/sh","sh","-i",NULL) to force an interactive shell, my program stop after executing the first command.
I'm new to pipe so please help me understand the reason and make interactive shell work... I also feel that my code to read line and pass to the child pipe is a bit odd.. is there any better way to achieve the same behavior ?
You should close(fd[0]); after the dup2() in the child. If you supply an absolute or relative path like "/bin/sh", there's no point in using execlp(); it will only do a PATH-based search for a bare filename (program name). The cast in the call to getline() should be unnecessary; avoid such casts whenever possible. You should include at least exit(1); after execlp() just in case it fails; a diagnostic message would be a good idea too. You should close(fd[1]); after the loop in the parent to indicate EOF to the child. (Just for once, it doesn't matter if you don't detect the error return from malloc(); it is legitimate to pass the address of a pointer where the pointer holds NULL to the getline() function, and it will then try to allocate memory itself. Of course, if the main program fails to allocate memory, it is highly likely that getline() will also fail to allocate memory.)
Those changes lead to:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
int fd[2];
pid_t child;
if (pipe(fd) != 0)
perror("pipe");
else if ((child = fork()) < 0)
perror("fork");
else if (child == 0)
{
close(fd[1]);
dup2(fd[0], 0);
close(fd[0]);
execl("/bin/sh", "sh", NULL);
perror("oops");
exit(1);
}
else
{
close(fd[0]);
size_t nbytes = 100;
int bytes = 0;
char *line = (char*)malloc(nbytes+1);
while ((bytes = getline(&line, &nbytes, stdin)) != -1)
{
write(fd[1], line, bytes);
}
close(fd[1]);
}
return(0);
}
This compiles without complaint under stringent compilation flags:
gcc -O3 -g -std=c99 -Wall -Wextra xf.c -o xf
When run (on Mac OS X 10.7.3) with the code above (invoking sh without the -i option), things behave reasonably sanely. You can type commands and the shell executes them. You can type 'exit' and the shell exits, but the program you wrote (which I called xf) doesn't exit until I type a new command. It then exits because of a SIGPIPE signal as it writes to the now readerless pipe. There is no prompt from this shell because its standard input is not a terminal (it is a pipe).
When the sub-shell is run with the -i option, then there seems to be a fight between the job control shells about which shell is in charge of the terminal. When I run it, I get:
$ ps -f
UID PID PPID C STIME TTY TIME CMD
503 381 372 0 Wed08PM ttys001 0:00.07 -sh
503 21908 381 0 9:32PM ttys001 0:00.01 sh
$ ./xf
sh-3.2$
[1]+ Stopped(SIGTTIN) ./xf
$
$ ps -f
UID PID PPID C STIME TTY TIME CMD
503 381 372 0 Wed08PM ttys001 0:00.07 -sh
503 21908 381 0 9:32PM ttys001 0:00.01 sh
503 22000 21908 0 9:36PM ttys001 0:00.00 ./xf
503 22001 22000 0 9:36PM ttys001 0:00.00 sh -i
$ ls
awk.data osfile-keep.c pthread-2.c send.c xf
const-stuff.c perl.data pthread-3.c so.8854855.sql xf.c
fifocircle.c piped-merge-sort.c quine.c strandsort.c xf.dSYM
madump.c powa.c recv.c unwrap.c xxx.sql
makefile pthread-1.c regress.c vap.c yyy.sql
$ jobs
[1]+ Stopped(SIGTTIN) ./xf
$ fg %1
./xf
exit
$
(The initial -sh is the login shell for my terminal window. In that, I've run sh to get a sub-shell, and I've set the prompt PS1='$ ' to make the prompt distinctive.)
AFAICT, the sh-3.2$ prompt comes from the sh -i shell. The parent shell seems to be reading input, and has dumped the xf program into the background, which is not very civilized of it. The ps -f output doesn't show the ps command, which is a nuisance. I did manage to get the ls command to show up in a ps listing in one run, and it was the child of the original shell, not the sh -i run by xf. When I bring xf into the foreground, it immediately exits (presumably it reads 0 bytes from standard input, which indicates EOF, and so getline() returns -1, and everything shuts up shop. The exit is from the sh -i; it echoes it. It never got any input because the sh shell took command instead of letting xf have control of the terminal. That's pretty excruciatingly messy. I'm not sure why it happens like that, but it feels to me like it shouldn't happen like that.