17 Nisan 2020 Cuma

Linux Sinyalleri

Sinyaller Neden Lazımdı
Açıklaması şöyle. Yani esas çıkış noktaları ana bir process'in çocuk process'lere sinyal göndermesi.
Signals are/were the primary way for a "supervisor" process to control a "supervised" project - e.g. init wanting to stop a process at system shutdown, a shell wanting to notify a subprocess of something. They were never really the primary way for cooperating processes to communicate - a shell pipeline communicates via pipes, not via signals. In particular here, signals convey essentially no information beyond their type - if you actually wanted to communicate a non-trivial amount of information, you needed a separate method to actually pass that information, whether that be a pipe, shared memory, a temporary file or whatever else.
Gönderilebilecek sinyaller
Gönderilebilecek sinyalleri gösteren bir şekli buradan aldım. kill -l komutu ile listelenebilir.
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX
How is a signal "delivered" in Linux?
Açıklaması şöyle. Yani signal gönderilirse, kernel execution location olarak signal handler'ı gösteriyor. Böylece thread signal handler'ı çalıştırıyor
A signal handler is just a function within a given process' address space. This function is executed whenever the signal is received. There's nothing special about it (although there are certain actions that should not be performed within a signal handler), and it does not reside in a special thread.

While signals are often described as being software interrupts, they aren't actually asynchronous.* When a signal is sent to a process, the kernel adds it to the process' pending signal set. It doesn't cause anything to happen immediately. The signal will only actually do anything at the next context switch back to userspace (whether that's a syscall returning or the scheduler switching to that process). If a process were to, for whatever reason, never switch from kernel to user, the signal would be kept in the pending signal set and never acted upon.†

When a process establishes a signal handler, it gives the kernel an address to a function. When the process is to receive a signal, the next context switch from kernelspace to userspace will not restore the execution context from before the process entered the kernel (usually, the context is saved when entering the kernel and restored upon exiting it). Instead, it will "restore" execution at the location of the signal handler. When the signal handler returns, it executes code which calls rt_sigreturn(), which restores the real execution context, allowing the process to continue where it left off.

When a process has multiple threads (i.e. there are multiple processes in a given thread group), the signal is sent to one of the threads in the thread group at random. This is because threads typically share memory and many other resources and run the same code.
Açıklaması şöyle. Yani signal handler içinde race condition olabileceği için dikkatli olmak lazım. Normalde signal rastgele bir thread'e gönderilir. Ancak tgkill ile thread seçilebilir.
The kernel doesn't start a new thread to execute a signal handler. It executes the signal handler on an existing thread. We could say that the signal is delivered to that particular thread. Basically, the thread drops whatever it was doing before, and executes the signal handler. After the signal handler returns, it goes back to what it was doing before. (forest's answer goes into more detail about how exactly the kernel schedules this.) But a key difference between this and an ordinary function call is that you don't have control over when it happens. So for example, on a platform where 32-bit accesses are atomic and 64-bit accesses are not, it's possible that the thread is in the middle of writing to a int64_t variable when the signal handler invocation occurs. Therefore, even in a single-threaded program, the signal handler must guard against "the thread racing against itself", so to speak. Consequently, the set of operations you can perform safely inside a signal handler is very limited.

The sender of a signal can choose to send it to a particular thread, for example by calling tgkill, or target an entire process. When a signal is sent to a process, the kernel selects one of the threads in the process to deliver it to. See What happens to a multithreaded Linux process if it gets a signal?

Note that if the behaviour of the signal is to terminate the recipient (e.g. SIGKILL, or SIGTERM with the default handler) then the entire process terminates even if you direct it at a particular thread.

Real Time Sinyaller - Uygulamanın Kendi Amacı İçin Kullandığı Sinyaller
Tanımı şöyle
Unlike standard signals, real-time signals have no predefined meanings: the entire set of real-time signals can be used for application-defined purposes.
Linux toplamda 32 real time sinyal destekliyor. 34 (SIGRTMIN) 'ten başlar 64'e (SIGRTMAX) kadar gider. 

Aslında bu real time sinyaller 32 ve 33 te dahil. Ancka 32 ve 33 no'lu sinyaller NPTL kütüphanesi içinde kullanıldığı için, SIGRTMIN yukarıda da görülebildiği gibi 34'ten başlayacak şekilde ayarlanıyor. Açıklaması şöyle.
Real-time Signals

Linux supports real-time signals as originally defined in the POSIX.1b real-time extensions (and now included in POSIX.1-2001). The range of supported real-time signals is defined by the macros SIGRTMIN and SIGRTMAX. POSIX.1-2001 requires that an implementation support at least POSIX_RTSIG_MAX(8) real-time signals.

The Linux kernel supports a range of 32 different real-time signals, numbered 33 to 64. However, the glibc POSIX threads implementation internally uses two (for NPTL) or three (for LinuxThreads) real-time signals (see pthreads(7)), and adjusts the value of SIGRTMIN suitably (to 34 or 35).

SIGHUP (Hangup Ctrl+D) (1)
Bu konu ile ilgili olarak nohup başlıklı yazıya göz atabilirsiniz. Uygulamanın çalıştığı terminal kapatılırsa bu sinyal o terminalde çalışan uygulamalara gönderilir. 

Bazı daemonlara bu sinyal gönderilince konfigürasyon dosyalarını tekrar yüklerler.

SIGINT (Ctrl+C) (2)
SIGINT yazısına taşıdım.

SIGQUIT (Ctrl+\) (3)
SIGINT'e benziyor ancak farklı tuşlar kullanılıyor. Aradaki en önemli fark ise, bu sinyal uygulamanın core dump vererek çıkmasına sebep olur. Eğer uygulamada bir hata olduğunu düşünüyorsak, örneğin donduysa inceleme imkanı tanır.

SIGFPE (8)
Bir floating point exception olduğunda gönderilir. Örneğin sıfıra bölme gibi. Açıklaması şöyle
If integer math results in a signal being delivered, POSIX require it to be SIGFPE. But POSIX doesn't require trapping for any particular integer operation.

SIGKIL (9)
SIGKILL yazısına taşıdım.

SIGPIPE (13)
Kapatılmış olan pipe veya sockete veri yazmaya çalışınca gönderilen sinyal. Karşıdaki uygulamanın haber vermeden kapandığını anlamamızı sağlar. Açıklaması şöyle.
You get SIGPIPE only if you try to write to a pipe that has no readers anymore. The idea is that typical unix processes run to produce output. If the output is going to a pipe, but no one is reading from a pipe, the process got useless and may be killed.

You never get SIGPIPE reading from an input pipe. If you read from an input pipe that has no writers anymore, you just get EOF. The usual behaviour of a process that reads EOF is finishing input processing. So you get the behaviour you suggest for nice filters "for free" without adding extra logic like counting SIGPIPEs.

SIGWINCH (28)
Açıklaması şöyle.
SIGWINCH, which is for window system events like a window resize
Örnek
Şöyle yaparız. Terminal penceresinin boyutları değişince "tput" komutunu çalıştırır
trap 'tput csr 1 $((LINES/2))' WINCH ; kill -s WINCH $$
Komutun devamının açıklaması şöyle.
The second part of the command kill -s WINCH $$ sends an initial SIGWINCH so that the tput csr command gets run when the shell is first invoked as well.

Hiç yorum yok:

Yorum Gönder