Definition of Process Management

Bundet
Bundet
Nov 3 · 9 min read

Linux manages all processes in the system through checking and changing every task_struct’s data structure that each process has. A list of pointers to all task_struct data structures stored in task vector. The maximum number of processes in the system is limited by the size of the task vector. Linux generally has a task vector with a size of 512 entries. When the process is created, a new task_struct is allocated from system memory and added to the task vector. Linux also supports processes in real time. Such processes must react very quickly to external events and are treated differently from other ordinary processes by the scheduler.

The process will end when it calls exit (). The kernel will determine the release time of the resources owned by the completed process. The do_exit () function will be called upon termination which then calls __exit_mm / files / fs / sighand () which will free up resources. The exit_notify () function will update the relationship between the parent process and child processes, all child processes whose parent ends will be children of the init process. Finally the scheduler will be called to run the new process.

1. Process Descriptors

For the purpose of process management, the kernel maintains information about each process in a process descriptor of type task_struct. Each process descriptor contains information including the status of the process, address space, list of open files, priority process, and so on. Following is the description of the contents:

Fill Process Descriptors

struct task_struct{ volatile long state;
/*-1 unrunnable,
0 runnable,
>0 stopped*/ unsigned long flags;
/* 1 untuk setiap flag proses */ mm_segment_t_addr_limit;
/* ruang alamat untuk thread */ struct exec_domain *exec_domain; long need_resched; long counter; long priority;
/* SMP and runqueue state */ struct task_struct *next_task, *prev_task; struct task_struct *next_run, *prev_run; ...
/* task state */
/* limits */
/* file system info */ /* ipc stuff */
/* tss for this task */
/* filesystem information */
/* open file information */
/* memory management info */
/* signal handlers */ ...
};

Every process in Linux has a status. The process status is an array of mutually exclusive flags. Each process has exactly one state (status) at a time. The status is:

  1. TASK_RUNNING. In this status, the process is being or is ready to be executed by the CPU.
  2. TASK_INTERRUPTIBLE. In this status, the process is waiting for a condition. Interruptions, signals, or the release of resources will wake the process.
  3. TASK_UNINTERRUPTIBLE. In this case, the process is asleep and cannot be awakened by a signal.
  4. TASK_STOPPED. At this state the process is being stopped, for example by a debugger.
  5. TASK_ZOMBIE. At this status the process has stopped, but still has the task_struct data structure in the task vector and still holds resources that are no longer used.

Each process or execution that is scheduled independently has its own process descriptor.

The address of the process descriptor is used to identify the process. In addition, process ID numbers (PIDs) are also used for this purpose. PIDs are 32-bit numbers that uniquely identify each process. Linux limits PIDs from 0–32767 to ensure compatibility with traditional UNIX systems.

Because the process is dynamic, the process descriptor is stored in dynamic memory as well. For this reason, 8KB of memory is also allocated for each process to store the descriptor process and the process stack from kernel mode. The advantage of this is that pointers from the process descriptors of running processes can be accessed quickly using the stack pointer. Additionally, 8KB (EXTRA_TASK_STRUCT) from memory will be cached to bypass the kernel memory allocator when a process is deleted and a new process is created. Both the free_task_struct () and alloc_task_struct () commands will be used to release or allocate 8KB of memory as cache.

The process descriptor also builds a list of processes from all processes that exist in the system. The process list is a doubly-linked list built by the next_task and prev_task sections of the process descriptor. The init_task descriptor (for example: swapper) is at the beginning of the list with its prev_task pointing to the most recent process descriptor included in the list. Whereas the for_each_task () macro is used to scan the entire list.

The process that is scheduled to be executed from the doubly-linked list of processes with TASK_RUNNING status is called runqueue. The prev_run and next_run parts of the process descriptor are used to build the runqueue, with the init_task starting the list. Meanwhile, to manipulate the list in the process descriptor, functions are used: add_to_runqueue (), del_from_runqueue (),

move_first_runqueue (), move_last_runqueue (). The NR_RUNNING macro is used to store the number of executable processes, while the wake_up_process function makes a process executable.

To guarantee its accuracy, the task array will be updated every time a new process is created or deleted. A separate list will track the free elements in the task array. When a process is deleted, the entry is added to the beginning of the list.

Processes with task_interruptible status are divided into classes that are associated with a particular event. The event in question for example: expiration time, availability of resources. For each event or class there is a separate waiting queue. The process will be given a wake up signal when the event that awaits occurs. Here is an example of the waiting queue:

Queue Wait

void sleep_on(struct wait_queue **wqptr) {
struct wait_queue wait; current_state=TASK_UNINTERRUPTIBLE; wait.task=current; add_wait_queue(wqptr, &wait); schedule(); remove_wait_queue(wqptr, &wait); }

The sleep_on () function will enter a process into the desired waiting queue and start the scheduler. When the process gets a signal to wake up, the process will be removed from the waiting queue.

Another part of the process execution context is the hardware context, for example: the contents of registers. The hardware context will be stored by the task state segment and the kernel mode stack. In particular it will save contexts that are not automatically saved by the hardware. Moving between processes involves saving the context of the previous process and the subsequent process. This must be done quickly to prevent wasting CPU time. A new version of Linux replaces this hardware context transfer using software that implements a series of mov instructions to guarantee the validation of stored data and the potential for optimization.

To change the process context the switch_to () macro is used. The macro will replace the process from the process designated by prev_task to next_task. The switch_to () macro is run by schedule () and is one of the kernel routines that is very hardware-dependent. More clearly can be seen in the kernel / sched.c and include / asm — * / system.h.

2. Making Process and Thread

Linux uses the same representation for processes and threads. Simply put, a thread can be said to be a new process that shares the same address with its parent. The difference lies in the time of manufacture. New threads are created with a system call clone that creates a new process with its own identity, but is allowed to share data structures with its parent.

Traditionally, the resources owned by the parent process will be duplicated when creating child processes. Copying this address space is slow, so to overcome this, copies are only made when one of them wants to write at that address. In addition, when they will share the address when they are just reading. This is a lightweight process known as a thread.

Threads created with __clone (). __clone () is a routine from the clone () system call library. __clone has 4 arguments:

  • fn. function to be executed by a new thread
  • arg. pointer to data carried by fn
  • signal flags sent to the parent when the child ends and the division of resources between the child and the parent.
  • child_stack. pointer stack for child processes.

clone () takes the flags and child_stack arguments owned by __clone and then determines the id of the child process that will execute fn with the arg argument.

The child making process can be done with the fork () and vfork () functions. The fork () implementation is the same as the clone () system call with the SIGCHLD sighandler set, all clone flags are cleared which means there is no sharing and child_stack is made 0 which means the kernel will create a stack for children when writing. Whereas vfork () is the same as fork () with additional CLONE_VM and CLONE_VFORK flags set. With vfork (), the parent and child will share the address, and the parent will be blocked until the child is finished.

To start creating a new process, clone () will call the do_fork () function. What do_fork () does:

  • call alloc_task_struct () which will provide 8KB memory space for the process descriptor and kernel mode stack.
  • check the availability of resources to make a new process.
  • find_empty_procees () calls get_free_taskslot () to find a slot in the task array for pointers to the new process descriptor.
  • call copy_files / fm / sighand / mm () to copy resources for children, based on the value of the flags specified by clone ().
  • copy_thread () will initialize the kernel stack from the child process.
  • get a new PID for the child that will be given back to its parent when do_fork () is finished.

Some system processes only run in kernel mode behind the scenes. For this kind of process a kernel thread can be used. Kernel threads only execute kernel functions, i.e. functions that are normally called by normal processes through system calls. Kernel threads are also only executed in kernel mode, in contrast to ordinary processes. The linear address used by the kernel thread is larger than the normal process PAGE_OFFSET that can be up to 4GB in size. The kernel thread is created as follows: int kernel_thread (int (* fn) (void *), void * arg, unsigned long flags); flags = CLONE_SIGHAND, CLONE_FILES, etc.

References

This book is presented from the Joint Working Group 21–28 IKI-20230 Even Semester 2002/2003, by the Joint Working Group 21–28 IKI-20230 Even Semester 2002/2003, for anyone who wants to learn the Operating System. The book’s drafting team is as follows:

Group 21 (Coordinator)

Dhani Yuliarso, Fernan, Hanny Faristin, Melanie Tedja, Paramanandana DM, Widya Yuwanda.

Group 22 (Chapter 1)

Budiono Wibowo, Agus Setiawan, Baya UHS, Budi A. Azis Dede Junaedi, Heriyanto, Muhammad Rusdi.

Group 23 (Chapter 2)

Indra Agung, Ali Khumaidi, Arifullah, Baihaki AS, Christian KF Daeli, Eries Nugroho, Eko Seno P., Habrar, Haris Sahlan.

Group 24 (Chapter 3)

Adzan Wahyu Jatmiko, Agung Pratomo, Dedy Kurniawan, Samiaji Adisasmito, Zidni Agni.

Group 25 (Chapter 4)

Nasrullah, Amy S. Indrasari, Ihsan Wahyu, Inge Evita Putri, Muhammad Faizal Ardhi, Muhammad Zaki Rahman, N. Rifka N. Liputo, Nelly, Nur Indah, R. Ayu P., Sita AR

Group 26 (Chapter 5)

Rakhmad Azhari, Adhe Aries, Adityo Pratomo, Aldiantoro Nugroho, Framadhan A., Pelangi, Satrio Baskoro Y.

Group 27 (Chapter 6)

Teuku Amir FK, Alex Hendra Nilam, Anggraini W., Ardini Ridhatillah, R. Ferdy Ferdian, Ripta Ramelan, Suluh Legowo, Zulkifli.

Group 28 (Chapter 7)

Operating System: IKI-20230 Lecture Material by the Joint Working Group 21–28 IKI-20230 Even Semester 2002/2003

$ Revision: 1.3.0.0 $ Edition

Published September 30, 2003

Copyright (2003) © 2003 by Work Group Affiliation 21–28 IKI-20230 Evening Semester 2002/2003.

Please copy, distribute and / or, modify parts of the document — $ Revision: 1.3.0.0 $ — — composed by the Working Group 21–228 IKI-20230 Even Semester 2002/2003, in accordance with the provisions of the “GNU Free Documentation License version 1.1 “or later version of the FSF (Free Software Foundation); without the “Invariant” section, without the “Front-Cover” text, and without the “Back-Cover” text. Appendix A contains a complete copy of the license. This provision does NOT apply to parts and / or quotations not composed by Joint Working Groups 21–28 IKI-20230 Even Semester 2002/2003.

Revision Note

Revisi 1.3 30–09–2003 Revised by: RMS46

This revision was edited by Rahmat M. Samik-Ibrahim: continuing to improve layout and indexing.

Revisi 1.2 17–09–2003 Revised by: RMS46

This revision was edited by Rahmat M. Samik-Ibrahim: continuing improvements.

Revisi 1.1 01–09–2003 Revised by: RMS46

This revision was edited by Rahmat M. Samik-Ibrahim: to improve the structure of SGML, without too much changing the contents of the book.

Revisi 1.0 27–05–2003 Revised by: RMS46

Recompile, and do a little tidying.

Revision 0.21.4 05–05–2003 Revised by: Group 21 File tidying and adding entities.

Revision 0.21.3 29–04–2003 Revised by: Group 21 Changes by perfecting the file name.

Revision 0.21.2 24–04–2003 Revised by: Group 21

Change the Preface.

Revision 0.21.1 21–04–2003 Revised by: Group 21

Add Bibliography and Index.

Revision 0.21.0 26–03–2003 Revised by: Group 21 Initiating the Operating System lecture group work.

Christiono H, Arief Purnama LK, Arman Rahmanto, Fajar, Muhammad Ichsan, Rama P. Tardan, Unedo Sanro Simon.

Bundet

Written by

Bundet

Bundet is a reflection of failure in managing ideas and mixing them to put an end to brain noise — bundet.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade