Kernel: το kill δεν πιάνει, τί σημαίνει αυτο

Giorgos Keramidas keramida at ceid.upatras.gr
Tue Dec 3 01:28:01 EET 2002


On 2002-12-02 15:50, "P. Christeas" <p_christ at hol.gr> wrote:
> Flame-bait:
> λυπάμαι που το γράφω αυτό, αλλά με το προηγούμενο mail κατάλαβα
> ποιοί εδώ μέσα ξέρουν από kernel, και ποιοί απλά κάνουν τους
> έξυπνους..

Μπορούμε να μην γινόμαστε προσβλητικοί χωρίς λόγο στη λίστα; :PPP

Συγγνώμη που δεν απάντησα στο mail σου που ρώταγε για σημεία που
μπορεί να κολλήσει κάποια process.  Το μάρκαρα σαν `important' στο
mutt και μετά το ξέχασα.  Το μόνο σχετικό κομμάτι που μπόρεσα να
καταλάβω διαβάζοντας πριν λίγο καιρό το source του FreeBSD kernel
(όταν κάποιος ρώτησε κάτι αντίστοιχο σε μια από τις λίστες του
FreeBSD) ήταν το εξής:

= Στο αρχείο src/sys/kern/kern_sig.c υπάρχει η killproc() που στέλνει
  το SIGKILL σε διεργασίες.  Αυτή ξεκινά με το παρακάτω:

        PROC_LOCK_ASSERT(p, MA_OWNED);

  Δεν μπορεί δηλαδή το kernel να την καλέσει αν το process είναι
  κλειδωμένο από κάποιο άλλο κομμάτι του kernel.  Αν το process είναι
  κλειδωμένο και προσπαθήσει κάποιος να στείλει SIGKILL, το kernel
  πανικοβάλλεται.

= Στο ίδιο αρχείο, στην συνάρτηση psignal έχει ένα σχόλιο για το
  delivery των signals.  Το kernel ελέγχει αν η διεργασία είναι
  stopped για κάποιο λόγο.  Ακόμα κι αν το signal που προσπαθείς να
  στείλεις είναι το SIGKILL, σε περίπτωση που είναι σταματημένη για
  κάποιο λόγο η διεργασία (π.χ. είναι στην ουρά κάποιου driver και
  περιμένει να τελειώσει ένα I/O request, το οποίο έχει κολλήσει για
  κάποιο λόγο), το μόνο που κάνει η psignal() είναι να προσπαθεί να
  "ξυπνήσει" τα threads της διεργασίας για να πάρουν το signal και να
  τερματίσουν.

  # src/sys/kern/kern_sig.c::psignal()

	runfast:
		mtx_lock_spin(&sched_lock);
		FOREACH_THREAD_IN_PROC(p, td)
			tdsignal(td, sig, action);
		thread_unsuspend(p);
		mtx_unlock_spin(&sched_lock);

= Η tdsignal() που καλείται από την psignal() για να ξυπνήσει τα
  threads ένα ένα δεν κάνει απολύτως τίποτα αν η διεργασία είναι σε
  uniterruptible κατάσταση.

  # src/sys/kern/kern_sig.c::tdsignal()

        if (TD_IS_SLEEPING(td)) {
                /*
                 * If thread is sleeping uninterruptibly
                 * we can't interrupt the sleep... the signal will
                 * be noticed when the process returns through
                 * trap() or syscall().
                 */
                if ((td->td_flags & TDF_SINTR) == 0) {
                        return;
                }

  Σύμφωνα με τα σχόλια της tdsignal(), αν μια διεργασία κάνει π.χ. ένα
  write() system call, που θα γράψει δεδομένα σε κάποιο NFS
  filesystem, και εντελώς τυχαία εκείνη τη στιγμή έχει πέσει το δίκτυο[1[]
  (οπότε το NFS write() δεν μπορεί να τερματίσει παρά μόνο μετά από
  κάποιου είδους timeout), η διεργασία δεν θα επιστρέψει από το system
  call άμεσα.  Για όση ώρα είναι σε τέτοια κατάσταση δεν θα μπορείς
  όχι signal να της στείλεις, αλλά ούτε τον θεό τον ίδιο.

Αυτά...

===
[1]	Για παράδειγμα όποτε κάνω NFS mount από το sunsite.ac.uk τον
κατάλογο με τα RFC, την πρώτη φορά που κάνω ls(1) η διεργασία είναι σε
αυτή ακριβώς την κατάσταση.  Μέχρι να κάνει stat() όλο τον κατάλογο
(που θέλει περίπου 1 λεπτό πάνω από 56 Kbit/s modem, αν δεν υπάρχει
άλλος καταναλωτής bandwidth εκείνη τη στιγμή) η διεργασία είναι
σταματημένη σε κατάσταση sbread (socket buffer read είναι αυτό, αν
θυμάμαι καλά).  Ούτε kill, ούτε τίποτα δεν καταλαβαίνει.  Αν κάνω
force unmount το NFS partition, ξαφνικά ξυπνάει, και μόλις πάει από
blocked se I/O κατάσταση να γυρίσει σε userspace τρώει όλα τα signals
μαζί στη μάπα.




More information about the Linux-greek-users mailing list