Linux kernel running process

how to figure out if process is really running or waiting to run on Linux?

This is purely academic question, I don’t really need to know this information for anything, but I would like to understand kernel a bit more 🙂 According to kernel documentation http://www.tldp.org/LDP/tlk/kernel/processes.html processes in linux kernel have following states:

Running

The process is either running (it is the current process in the system) or it is ready to run (it is waiting to be assigned to one of the system’s CPUs).

Waiting

The process is waiting for an event or for a resource. Linux differentiates between two types of waiting process; interruptible and uninterruptible. Interruptible waiting processes can be interrupted by signals whereas uninterruptible waiting processes are waiting directly on hardware conditions and cannot be interrupted under any circumstances.

Stopped

The process has been stopped, usually by receiving a signal. A process that is being debugged can be in a stopped state.

Zombie

This is a halted process which, for some reason, still has a task_struct data structure in the task vector. It is what it sounds like, a dead process.

As you can see, when I take a snapshot of processes state, using command like ps , I can see, if it’s in Running state, that process either was literally Running or just waiting to be assigned to some CPU by kernel. In my opinion, these 2 states (that are actually both represented by 1 state in task_struct ) are quite different. Why there is no state like «Ready» that would mean the process is «ready to run» but wasn’t assigned to any CPU so far, so that the task_struct would be more clear about the real state? Is it even possible to retrieve this information, or is it secret for whatever reason which process is «literally running» on the CPU?

Источник

LINUX KERNEL INTERNALS

printf(«fork program is starting\n»);
pid = fork();
switch(pid)
case -1:
perror(«fork failed»);
exit(1);
case 0:
message = «This is the child»;
n = 5;
break;
default:
message = «This is the parent»;
n = 3;
break;
>

The parent gets over before the child so we can see the shell prompt appears mixed with the output of child process.

Читайте также:  Установка ubuntu через терминал linux

Now, lets try to finish the child process first.

int main()
pid_t pid;
char *message;
int n;

printf(«fork program starting\n»);
pid = fork();
switch(pid)
case -1:
perror(«fork failed»);
exit(1);
case 0:
message = «This is the child»;
n = 3;
break;
default:
message = «This is the parent»;
n = 5;
break;
>

int main()
pid_t pid;
char *message;
int n;
int exit_code;

printf(«fork program starting\n»);
pid = fork();
switch(pid)
case -1:
exit(1);
case 0:
message = «This is the child»;
n = 5;
exit_code = 37;
break;
default:
message = «This is the parent»;
n = 3;
exit_code = 0;
break;
>

/* This section of the program waits for the child process to finish. */

if(pid) int stat_val;
pid_t child_pid;

printf(«Child has finished: PID = %d\n», child_pid);
if(WIFEXITED(stat_val))
printf(«Child exited with code %d\n», WEXITSTATUS(stat_val));
else
printf(«Child terminated abnormally\n»);
>
exit (exit_code);
>

fork() vs vfork() vs exec() vs system() vs clone()

Let us first see the standard definition of these system calls.

Fork : The fork call is used to duplicate the current process, the new process identical in almost every way except that it has its own PID. The return value of the function fork distinguishes the two processes, zero is returned in the child and PID of child in parent process.

Exec : The exec call is a way to basically replace the entire current process with a new program. It loads the program into the current process space and runs it from the entry point. As a new process is not created, the process identifier (PID) does not change, but the machine code , data , heap , and stack of the process are replaced by those of the new program. exec() replaces the current process with a the executable pointed by the function. Control never returns to the original program unless there is an exec() error. exec system call can be executed as execl, execlp, execle, execv, execvp, execvpe

Vfork: The basic difference between vfork and fork is that when a new process is created with vfork(), the parent process is temporarily suspended, and the child process might borrow the parent’s address space. This strange state of affairs continues until the child process either exits, or calls execve(), at which point the parent process continues.

This means that the child process of a vfork() must be careful to avoid unexpectedly modifying variables of the parent process. In particular, the child process must not return from the function containing the vfork() call, and it must not call exit() (if it needs to exit, it should use _exit(); actually, this is also true for the child of a normal fork()).

Читайте также:  Linux root user deleted

The intent of vfork was to eliminate the overhead of copying the whole process image if you only want to do an exec* in the child. Because exec* replaces the whole image of the child process, there is no point in copying the image of the parent.

if ((pid = vfork()) == 0) <
execl(. NULL); /* after a successful execl the parent should be resumed */
_exit(127); /* terminate the child in case execl fails */
>

For other kinds of uses, vfork is dangerous and unpredictable.

With most current kernels, however, including Linux, the primary benefit of vfork has disappeared because of the way fork is implemented. Rather than copying the whole image when fork is executed, copy-on-write techniques are used.

Clone : Clone, as fork, creates a new process. Unlike fork, these calls allow the child process to share parts of its execution context with the calling process, such as the memory space, the table of file descriptors, and the table of signal handlers.

When the child process is created with clone, it executes the function application fn(arg). (This differs from fork, where execution continues in the child from the point of the original fork call.) The fn argument is a pointer to a function that is called by the child process at the beginning of its execution. The arg argument is passed to the fn function.

When the fn(arg) function application returns, the child process terminates. The integer returned by fn is the exit code for the child process. The child process may also terminate explicitly by calling exit(2) or after receiving a fatal signal.

System : The system () library function uses fork(2) to create a child process that executes the shell command specified in command using execl(3) as follows: execl(«/bin/sh», «sh», «-c», command, (char *) 0); system () returns after the command has been completed.During execution of the command , SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored, in the process that calls system () (these signals will be handled according to their defaults inside the child process that executes command ). If command is NULL, then system () returns a status indicating whether a shell is available on the system

  • In situations where performance is critical and/or memory limited, vfork + exec* can therefore be a good alternative to fork + exec* . The problem is that it is less safe and the man page says vfork is likely to become deprecated in the future.
  • Because memory page tables are not duplicated, vfork is much faster than fork and vfork ‘s execution time is not affected by the amount of memory the parent process uses
  • system() will invoke your systems default command shell, which will execute the command string passed as an argument, that itself may or may not create further processes, that would depend on the command and the system. Either way, at least a command shell process will be created.
  • With system() you can invoke any command, whereas with exec(), you can only invoke an executable file. Shell scripts and batch files must be executed by the command shell.
Читайте также:  Ram usage linux mint

Process Descriptor and the Task Structure

  • The kernel stores the list of processes in a circular doubly linked list called the task list .
  • Process descriptor is nothing but each element of this task list of the type struct task_struct, which is defined in . The process descriptor contains all the information about a specific process.
  • Some texts on operating system design call this list the task array . Because the Linux implementation is a linked list and not a static array, it is called the task list .
  • The task_struct is a relatively large data structure, at around 1.7 kilobytes on a 32-bit machine.
  • This size, however, is quite small considering that the structure contains all the information that the kernel has and needs about a process.
  • The process descriptor contains the data that describes the executing program open files, the process’s address space, pending signals, the process’s state, and much more.
  • This linked list is stored in kernel space.
  • There is one more structure, thread_info which holds more architecture-specific data than the task_struct..

Источник

Оцените статью
Adblock
detector