GNU/Linux >> Belajar Linux >  >> Linux

Kapan sinyal ditangani dan mengapa beberapa info membeku?

termA tidak membeku. Itu hanya menampilkan callback di kotak input. Cukup tekan Enter kunci untuk melanjutkan masukan.


Sebelum menjelaskan masalah Anda, sedikit konteks tentang bagaimana read perintah bekerja. Bunyinya dalam input data dari stdin hingga EOF dihadapi. Aman untuk mengatakan panggilan ke read perintah tidak memblokir ketika harus membaca dari file di disk. Tetapi ketika stdin terhubung ke terminal, perintah akan memblokir sampai pengguna mengetik sesuatu.

Bagaimana cara kerja penangan sinyal?

Penjelasan sederhana tentang cara kerja penanganan sinyal. Lihat cuplikan di bawah ini di C yang hanya bekerja pada SIGINT (alias CTRL+C )

#include <stdio.h>
#include <signal.h>

/* signal handler definition */
void signal_handler(int signum){
  printf("Hello World!\n");
}

int main(){
  //Handle SIGINT with a signal handler
  signal(SIGINT, signal_handler);
  //loop forever!
  while(1);
}

Ini akan mendaftarkan penangan sinyal dan kemudian akan memasuki loop tak terbatas. Saat kita menekan Ctrl-C , kita semua setuju bahwa penangan sinyal signal_handler() harus mengeksekusi dan "Hello World!" mencetak ke layar, tetapi program berada dalam putaran tak terbatas. Untuk mencetak "Hello World!" itu pasti kasus yang merusak loop untuk mengeksekusi penangan sinyal, bukan? Jadi itu harus keluar dari loop serta programnya. Mari kita lihat:

gcc -Wall -o sighdl.o signal.c
./sighdl.o 
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!

Seperti yang ditunjukkan oleh keluaran, setiap kali kami mengeluarkan Ctrl-C , "Hello World!" mencetak, tetapi program kembali ke loop tak terbatas. Hanya setelah mengeluarkan SIGQUIT sinyal dengan Ctrl-\ apakah program benar-benar keluar. Bergantung pada ulimit Anda pengaturan, itu akan membuang inti atau mencetak nomor sinyal yang diterima.

Sementara interpretasi bahwa loop akan keluar masuk akal, itu tidak mempertimbangkan alasan utama untuk penanganan sinyal, yaitu penanganan peristiwa asinkron. Itu berarti penangan sinyal bertindak di luar aliran standar kontrol program; pada kenyataannya, seluruh program disimpan dalam konteks, dan konteks baru dibuat hanya untuk penangan sinyal untuk dieksekusi. Setelah penangan sinyal menyelesaikan tindakannya, konteks dialihkan kembali dan aliran eksekusi normal dimulai (yaitu while(1) ).

Untuk menjawab pertanyaan Anda,

Kesimpulan memverifikasi bahwa Ketika bash menjalankan perintah eksternal di latar depan, bash tidak menangani sinyal apa pun yang diterima hingga proses latar depan berakhir

Hal utama yang perlu diperhatikan di sini adalah eksternal bagian perintah. Dalam kasus pertama, di mana sleep adalah proses eksternal tetapi dalam kasus kedua, read adalah built-in dari shell itu sendiri. Jadi propagasi sinyal ke keduanya berbeda dalam kedua kasus ini

type read
read is a shell builtin
type sleep
sleep is /usr/bin/sleep

1.Buka terminal, beri nama termA , dan jalankan file yang dibuat callback.sh dengan /bin/bash callback.sh untuk pertama kalinya, info akan muncul secara instan.

Ya, perilaku ini diharapkan. Karena saat ini hanya fungsi yang didefinisikan dan trap handler didaftarkan ke fungsi myCallback dan sinyal belum diterima di skrip. Saat urutan eksekusi berjalan, pesan dari read prompt dilemparkan untuk pertama kalinya.

2. Buka terminal baru, beri nama termB dan jalankan pkill -USR1 -f callback.sh pertama kali, info langsung muncul di termA

Ya, sedangkan read perintah sedang menunggu string diikuti oleh Enter key pre yang menandakan EOF , menerima sinyal SIGUSR1 dari terminal lain, konteks eksekusi saat ini disimpan dan kontrol dialihkan penangan sinyal yang mencetak string dengan tanggal saat ini.

Segera setelah handler selesai mengeksekusi, konteks dilanjutkan ke while loop di mana read perintah masih menunggu input string. Sampai read perintah berhasil, semua perangkap sinyal berikutnya hanya akan mencetak string di dalam penangan sinyal.

Lanjutkan di termB, jalankan pkill -USR1 -f callback.sh kedua kalinya.

Sama seperti yang sudah dijelaskan sebelumnya, yaitu read perintah tidak selesai sekali dalam while loop Anda, hanya jika berhasil membaca string, iterasi berikutnya dari loop akan dimulai dan pesan prompt baru akan dilontarkan.

Sumber gambar:Antarmuka Pemrograman Linux oleh Michael KerrisK


Kesimpulan memverifikasi bahwa Ketika bash menjalankan perintah eksternal di latar depan, bash tidak menangani sinyal apa pun yang diterima hingga proses latar depan berakhir.

bash benar menangani sinyal di C / level implementasi, tetapi tidak akan menjalankan set penangan dengan trap sampai proses latar depan telah dihentikan. Itu diwajibkan oleh standar:

When a signal for which a trap has been set is received while the shell is waiting for the completion of a utility executing a foreground command, the trap associated with that signal shall not be executed until after the foreground command has completed.

Perhatikan bahwa standar tidak membuat perbedaan antara perintah bawaan dan perintah eksternal; dalam kasus "utilitas" seperti read , yang tidak dieksekusi dalam proses terpisah, tidak jelas apakah sinyal muncul dalam "konteks" atau di shell utama, dan apakah handler disetel dengan trap harus dijalankan sebelum atau sesudah read kembali.

masalah 1:callback.sh berisi while loop tak terbatas, bagaimana menjelaskannya tidak menangani sinyal apa pun yang diterima hingga proses latar depan berakhir., dalam hal ini proses latar depan tidak pernah berhenti.

Itu salah. bash tidak menjalankan while loop dalam proses terpisah. Karena tidak ada proses latar depan bash sedang menunggu, ia dapat menjalankan kumpulan penangan apa saja dengan trap langsung. Jika read adalah perintah eksternal, itu dan bukan while akan menjadi proses latar depan.

issue2:Tidak ada please input something for foo: shown dalam termA;

buka termB, jalankan pkill -USR1 -f callback.sh ketiga kalinya.

Info berikut ditampilkan di termA lagi:callback function called at Mon Nov 19 09:07:24 HKT 2018

Masih belum ada please input something for foo: ditampilkan di termA.Mengapa info please input something for foo: membeku?

Itu tidak membeku. Cukup tekan Enter dan itu akan muncul lagi.

Hanya saja

a) bash akan memulai ulang read bawaan di tempat ketika diinterupsi oleh sinyal -- ia tidak akan kembali dan melewati while lagi lingkaran

b) itu tidak akan menampilkan ulang set prompt dengan -p dalam hal itu.

Perhatikan bahwa bash bahkan tidak akan menampilkan prompt lagi jika ada SIGINT dari keyboard ditangani, bahkan jika itu membuang string yang dibaca sejauh ini dari pengguna:

$ cat goo
trap 'echo INT' INT
echo $$
read -p 'enter something: ' var
echo "you entered '$var'"

$ bash goo
24035
enter something: foo<Ctrl-C>^CINT
<Ctrl-C>^CINT
<Ctrl-C>^CINT
bar<Enter>
you entered 'bar'

Itu akan mencetak you entered 'foobar' jika sinyal dikirim dari jendela lain dengan kill -INT <pid> alih-alih dengan Ctrl-C dari terminal.

Semua hal di bagian terakhir ini (bagaimana read terputus, dll) sangat bash spesifik. Di shell lain seperti ksh atau dash , dan bahkan di bash saat dijalankan dalam mode POSIX (bash --posix ), setiap sinyal yang ditangani sebenarnya akan mengganggu read builtin. Pada contoh di atas, shell akan mencetak you entered '' dan keluar setelah ^C pertama, dan jika read dipanggil dari sebuah loop, loop akan dimulai ulang.


Linux
  1. Siapa yang menggunakan sinyal realtime POSIX dan mengapa?

  2. Mengapa malloc() memanggil mmap() dan brk() secara bergantian?

  3. Mengapa dentang menghasilkan teks yang tidak dapat dipahami saat dialihkan?

  1. Mengapa OpenStack melaporkan tipe Hypervisor sebagai QEMU ketika libvirt_type adalah KVM?

  2. Apa Env X=() { :;}; Command' Bash Do Dan Mengapa Tidak Aman?

  3. Mengapa debian dan ubuntu secara default menjalankan level 2?

  1. Kapan Dan Mengapa Saya Harus Menggunakan Pembaruan Apt-get?

  2. Apa yang Dilakukan Program Saat Mengirim Sinyal Sigkill?

  3. Mengapa Disarankan Membuat Grup Dan Pengguna Untuk Beberapa Aplikasi?