Sistem Çağrısı (System Call) Nedir?
System Call ile kernel içindeki bir kod parçası çalıştırılır. Açıklaması şöyle.
1. Jump Table İle Subroutine Çağırmak
Bu yöntem çok eskiden kullanılıyormuş. Açıklaması şöyle
Bu yöntem özellikle Intel tarafından tercih ediliyormuş. 8086 ile de mecburi hale gelmiş. Açıklaması şöyle.
Açıklaması şöyle.
Linux üzerinde sistem çağrısı yapmak için Kernel 2.5'ten önce INT 0x80 (Interrupt) kullanılıyordu.
Aşağıdaki cümleyi buradan aldım
Yeni çekirdeklerde x86 mimarisi için SYSENTER/SYSEXIT talimatları kullanılıyor.
Aşağıdaki şekilde INT 0x80 kullanımını görmek mümkün.
C Kütüphanesi
Tabiki sistem çağrısı artık modern diller vasıtasıyla genellikle bir kütüphanenin arkasına gizlenmiş durumda. Örneğin aşağıdaki şekildeki glibc (GNU C kütüphanesi) gibi.
Hatta glibc içindeki read/write gibi metodlar bile bir seviye daha soyutlama kullanıyorlar. Açıklaması şöyle.
how does the processor know an instruction is making a system call sorusunda ise bazı sistem çağrılarını hızlandırmak içinse vsyscall (virtual system call) yapısının kullanıldığından bahsediliyor. Örneğin gettimeofday bir sistem çağrısını olmasına rağmen, belli bir adreseteki sayfaya sabitlendiği için CPU, kernel moduna geçmeden daha hızlı olarak çağırılabiliyor.
Sistem Çağrısında CPU Kernel Moduna Geçer
Sistem çağrısının başlaması için ilk önce CPU'nun user modundan kernel moduna geçmesi gerekmektedir. CPU modlarını öğrenmek için CPU modes başlıklı yazıya bakabilirsiniz. CPU modları ayrıca genellikle Ring'ler ile ilişkilendirilmiştir. Örneğin kernel mod Ring 0'ı kullanırken Device Driver kodu kernel içinde olsa bile Ring 1'i kullanabilir. Bu sadece bir örnekti, Windows NT ve Unix genellikle sadece Ring 0 ve Ring 3'ü kullanırlar.
Dolayısıyla bir sistem çağrısı (system call) en basit ve hiçbir bloke olma durumunu içermiyorsa aslında sadece CPU'nun mod değiştirmesi olarak düşünülebilir. Aşağıda buradan aldığım ve daha rahat anlaşılsın diye kırptığım bir şekil ile bunu görmek mümkün. Kırmızı renk ile temsil edilen çizgilerde kernel kendi context'i içindeki kod parçasını mod değiştirerek çalıştırıyor.
Örneğin şimdiki zamanı isteyen bir kernel metodunu çağırıyor olsaydık, kernel önce user mod yazmaçlarını muhafaza edecek, daha sonra kendi içindeki kodu çağıracak ve daha sonra cevabı bizim yazmaçlarımızdan birine veya hafızada bir yere yazacaktı. Burada dikkat edilmesi gereken nokta işletim sisteminin bizim yazılımımıza hiç bir zaman kesme yapmadığını farz ediyoruz. Bu durumda context switch yapılmasına da - yani bir programdan başka programa geçişe - gerek kalmıyor.
Thread
Bir thread'in sistem çağrısı yapıp yapmadığını görmek için (örneğin read/write) ps komutunu kullanabiliriz.
Örnek
Şöyle yaparız.
System Call ile kernel içindeki bir kod parçası çalıştırılır. Açıklaması şöyle.
Sistem Çağrısı İçin YöntemlerAn operating system can access a system's hardware directly, but a user program is not given direct access to the hardware. This is done so that the kernel can keep the system safe and secure from malicious user programs. But often, a user program requires some information from the hardware (e.g., from a web camera to show you the picture), but it cannot get the information directly. So, it requests the operating system to supply it the information. This request is made by using an appropriate system call.
1. Jump Table İle Subroutine Çağırmak
Bu yöntem çok eskiden kullanılıyormuş. Açıklaması şöyle
...coming from 8-bit systems that accessed system services by calling subroutines through a jump table. This simple system seems to give the same benefits from indirection as using software interrupts on x86. An example of such a system is the kernel (or "Kernal", for Commodore purists) used on Commodore's 8-bit machines.2. Interrupt Çağırmak
Additionally, the reliance on software interrupts might be a reason for why the transition to using Protected mode, and accessing more than 640KiB of memory, was so slow and difficult for MS-DOS users.
Bu yöntem özellikle Intel tarafından tercih ediliyormuş. 8086 ile de mecburi hale gelmiş. Açıklaması şöyle.
Using INT comes not only natural due the way the 8086 is designed, but was as well intended by Intel as OS entry point, much like a Super Visor Call (SVC) on /360 type mainframes:x86 INT 0x20 - DOS İçindi
Açıklaması şöyle.
Access to the DOS API was done through the INT 21h x86 instruction.x86 INT 0x80 - Eski Linux Kernelleri İçindi
Linux üzerinde sistem çağrısı yapmak için Kernel 2.5'ten önce INT 0x80 (Interrupt) kullanılıyordu.
Aşağıdaki cümleyi buradan aldım
Mesela dosya açmak için 5 numaralı sistem çağrısı yapılırdı. EAX'e 5, dosya ismine pointer EBX'e, bayraklar ECX'e, dosya açma modları EDX'e yazılır ve sistem çağrısı yapılırdı.Most Unix systems and derivatives do not use software interrupts, with the exception of interrupt 0x80, used to make system calls. This is accomplished by entering a 32-bit value corresponding to a kernel function into the EAX register of the processor and then executing INT 0x80.
Yeni çekirdeklerde x86 mimarisi için SYSENTER/SYSEXIT talimatları kullanılıyor.
Aşağıdaki şekilde INT 0x80 kullanımını görmek mümkün.
C Kütüphanesi
Tabiki sistem çağrısı artık modern diller vasıtasıyla genellikle bir kütüphanenin arkasına gizlenmiş durumda. Örneğin aşağıdaki şekildeki glibc (GNU C kütüphanesi) gibi.
Hatta glibc içindeki read/write gibi metodlar bile bir seviye daha soyutlama kullanıyorlar. Açıklaması şöyle.
....the syscall functions you use (read(), write(), ...) are all libc wrappers around the real syscalls, even the generic syscall() function.glibc kütüphanesinin devre dışı bırakarak direkt sistem çağrısı yapmak mümkün. Yöntem ise inline assembly. Açıklaması şöyle.
The only way of manually calling a syscall without passing through the C library (and therefore without doing symbol resolution) other than compiling statically is to use inline assembly. You can take a look at man 2 syscall to see which registers and instructions to use. On ARM AArch64 for example you can invoke a syscall by loading the syscall number in the register x8, parameters in x0 through x5, and then executing the svc #0 instruction.Sistem Çağrısını Hızlandırmak
how does the processor know an instruction is making a system call sorusunda ise bazı sistem çağrılarını hızlandırmak içinse vsyscall (virtual system call) yapısının kullanıldığından bahsediliyor. Örneğin gettimeofday bir sistem çağrısını olmasına rağmen, belli bir adreseteki sayfaya sabitlendiği için CPU, kernel moduna geçmeden daha hızlı olarak çağırılabiliyor.
Sistem Çağrısında CPU Kernel Moduna Geçer
Sistem çağrısının başlaması için ilk önce CPU'nun user modundan kernel moduna geçmesi gerekmektedir. CPU modlarını öğrenmek için CPU modes başlıklı yazıya bakabilirsiniz. CPU modları ayrıca genellikle Ring'ler ile ilişkilendirilmiştir. Örneğin kernel mod Ring 0'ı kullanırken Device Driver kodu kernel içinde olsa bile Ring 1'i kullanabilir. Bu sadece bir örnekti, Windows NT ve Unix genellikle sadece Ring 0 ve Ring 3'ü kullanırlar.
Dolayısıyla bir sistem çağrısı (system call) en basit ve hiçbir bloke olma durumunu içermiyorsa aslında sadece CPU'nun mod değiştirmesi olarak düşünülebilir. Aşağıda buradan aldığım ve daha rahat anlaşılsın diye kırptığım bir şekil ile bunu görmek mümkün. Kırmızı renk ile temsil edilen çizgilerde kernel kendi context'i içindeki kod parçasını mod değiştirerek çalıştırıyor.
Örneğin şimdiki zamanı isteyen bir kernel metodunu çağırıyor olsaydık, kernel önce user mod yazmaçlarını muhafaza edecek, daha sonra kendi içindeki kodu çağıracak ve daha sonra cevabı bizim yazmaçlarımızdan birine veya hafızada bir yere yazacaktı. Burada dikkat edilmesi gereken nokta işletim sisteminin bizim yazılımımıza hiç bir zaman kesme yapmadığını farz ediyoruz. Bu durumda context switch yapılmasına da - yani bir programdan başka programa geçişe - gerek kalmıyor.
Thread
Bir thread'in sistem çağrısı yapıp yapmadığını görmek için (örneğin read/write) ps komutunu kullanabiliriz.
Örnek
Şöyle yaparız.
ps -p<pid> -o stat
Çıktıda şu değerleri görüyorsak thread sistem çağrısındadır.D uninterruptible sleep (usually IO)
S interruptible sleep (waiting for an event to complete)