Kesintisiz süreç nedir?


156

Bazen Linux'ta bir program yazdığımda ve bir tür hata nedeniyle çöktüğünde, kesintisiz bir süreç haline gelir ve bilgisayarımı yeniden başlatana kadar sonsuza kadar çalışmaya devam eder (çıkış yapsam bile). Sorularım:

  • Bir sürecin kesintisiz hale gelmesine ne sebep olur?
  • Bunun olmasını nasıl önleyebilirim?
  • Bu muhtemelen aptalca bir soru, ancak bilgisayarımı yeniden başlatmadan kesmenin herhangi bir yolu var mı?

TASK_UNINTERUPTIBLESistem boşta olmadığında bir duruma giren bir süreci başlatmak için bir programın yazılabilmesi ve böylece süper kullanıcı çıktıktan sonra iletilmeyi bekleyen zorla veri toplanması mümkün mü? Bu, bilgisayar korsanlarının bilgi alması, zombi durumuna dönmesi ve ağ üzerinden boşta bilgi aktarması için bir altın madeni olacaktır. Bazıları bunun Blackdoor, güçler için bir yaratmanın , istediği gibi herhangi bir sisteme girip çıkmanın bir yolu olduğunu iddia edebilir . Bu boşlukun `` TASK_UNINTERUPTIB
Nuuwski

2
Lütfen kodu paylaşır mısınız?
yine

Yanıtlar:


198

Kesintisiz bir süreç, bir sistem çağrısında (çekirdek işlevi) gerçekleşen ve bir sinyalle kesilemeyen bir işlemdir.

Bunun ne anlama geldiğini anlamak için, kesilebilir bir sistem çağrısı kavramını anlamanız gerekir. Klasik örnek read(). Bu, sabit sürücüyü veya hareketli kafaları döndürmeyi içerebileceğinden uzun süre (saniye) sürebilen bir sistem çağrısıdır. Bu sürenin çoğunda, süreç uyuyacak, donanımı engelleyecektir.

İşlem sistem çağrısındayken, bir Unix asenkron sinyali alabilir (örneğin, SIGTERM), o zaman aşağıdakiler olur:

  • Sistem çağrıları zamanından önce çıkar ve -EINTR öğesini kullanıcı alanına döndürecek şekilde ayarlanır.
  • Sinyal işleyici yürütülür.
  • İşlem hala çalışıyorsa, dönüş değerini sistem çağrısından alır ve aynı çağrıyı tekrar yapabilir.

Sistem çağrısından erken dönülmesi, kullanıcı boşluk kodunun sinyale yanıt olarak davranışını hemen değiştirmesini sağlar. Örneğin, SIGINT veya SIGTERM'e tepki olarak temiz bir şekilde sonlandırma.

Öte yandan, bazı sistem çağrılarının bu şekilde kesilmesine izin verilmez. Sistem bir sebepten ötürü tezgahları çağırırsa, süreç süresiz olarak bu dayanıklı durumda kalabilir.

LWN Temmuz ayında bu konuya değinen güzel bir makale yayınladı .

Orijinal soruyu cevaplamak için:

  • Bunun olmasını nasıl önleyebilirim: Hangi sürücünün size sorun yarattığını bulun ve kullanmayı bırakın ya da çekirdek korsanı olun ve düzeltin.

  • Kesintisiz bir süreci yeniden başlatmadan nasıl öldürürüm: bir şekilde sistem çağrısını sonlandırın. Güç düğmesine basmadan bunu yapmanın en etkili yolu güç kablosunu çekmektir. Ayrıca LWN makalesinde açıklandığı gibi bir çekirdek korsanı olabilir ve sürücünün TASK_KILLABLE kullanmasını sağlayabilirsiniz.


31
Güç kablosunu dizüstü bilgisayarımdan çektim ve ne yazık ki çalışmıyor. ;-)
thecarpy

1
EAGAIN yerine EINTR değil mi? Ayrıca read () -1 döndürür ve errno hataya ayarlanır.
ölümcül

2
@Dexter: Aslında bu noktayı kaçırıyorsunuz. LWN makalesini okuyun: lwn.net/Articles/288056 . Bu sorunlara tembel aygıt sürücüsü programcıları neden olur ve aygıt sürücüsü kodunda düzeltilmeleri gerekir.
ddaa

4
@ddaa "Unix geleneği (ve dolayısıyla neredeyse tüm uygulamalar) dosya deposunun yazmanın sinyalsiz olarak kesildiğine inanıyor. Bu garantiyi değiştirmek güvenli veya pratik olmayacaktır." -> Bu, tüm bu IMO'nun en yanlış kısmı. Sadece sürücünün okuma / yazma isteğine ara verin ve gerçek aygıt (sabit disk / ağ kartı / vb.) Verileri ilettiğinde, yok sayın. İşletim sistemi çekirdeği, HİÇBİR geliştiricinin bunu bertaraf edebileceği şekilde yapılmalıdır.
Dexter

2
@ddaa Linux'un mikro çekirdek olmadığını biliyorum, ancak yorumumun hangi kısmının bununla ilgili olduğundan emin değilim ... Ve sonra, yorumunuz bir mikro çekirdek işletim sisteminin bu "kesintisiz" süreçlerle ilgili bir sorunu olmadığı anlamına mı geliyor? Çünkü eğer olmazsa, belki de benim için mikro çekirdekli bir fan olma zamanı ...: D
Dexter

49

Bir işlem kullanıcı modundayken, herhangi bir zamanda kesilebilir (çekirdek moduna geçme). (Örneğin, öldürme işlemi için kullanılan da dahil olmak üzere bekleyen herhangi bir sinyal olup olmadığını kullanım moduna çekirdek döner, bu denetler SIGTERMve SIGKILL). Bu, bir işlemin yalnızca kullanıcı moduna döndüğünde öldürülebileceği anlamına gelir.

Bir işlemin çekirdek modunda öldürülememesinin nedeni, aynı makinedeki tüm diğer işlemler tarafından kullanılan çekirdek yapılarını potansiyel olarak bozabilmesidir (aynı iş parçacığını öldürmek, aynı işlemdeki diğer iş parçacıkları tarafından kullanılan veri yapılarını potansiyel olarak bozabilir) .

Çekirdeğin uzun zaman alabileceği bir şey yapması gerektiğinde (örneğin başka bir işlem tarafından yazılmış bir boruda beklemek veya donanımın bir şey yapmasını beklemek), kendini uyku olarak işaretleyerek ve zamanlayıcıyı diğerine geçmeye çağırarak uyur işlemi (eğer uykusuz bir işlem yoksa, cpu'ya biraz yavaşlamasını ve bir döngüde - boşta döngüde oturmasını söyleyen "kukla" bir işleme geçer).

Bir uyku işlemine bir sinyal gönderilirse, kullanıcı boşluğuna dönmeden ve dolayısıyla bekleyen sinyali işlemeden önce uyandırılması gerekir. Burada iki ana uyku tipi arasındaki fark var:

  • TASK_INTERRUPTIBLE, kesilebilir uyku. Bir görev bu işaretle işaretlenmişse uyuyor, ancak sinyallerle uyandırılabilir. Bu, görevi uyku olarak işaretleyen kodun olası bir sinyal beklediğini ve uyandıktan sonra onu kontrol edip sistem çağrısından geri döneceği anlamına gelir. Sinyal işlendikten sonra sistem çağrısı potansiyel olarak otomatik olarak yeniden başlatılabilir (ve bunun nasıl çalıştığına dair ayrıntılara girmeyeceğim).
  • TASK_UNINTERRUPTIBLE, kesintisiz uyku. Bir görev bu işaretle işaretlenmişse, kolayca yeniden başlatılamadığı veya programların sistem çağrısının atomik olmasını beklediği için beklediği dışında herhangi bir şey tarafından uyandırılması beklenmez. Bu aynı zamanda çok kısa olduğu bilinen uykular için de kullanılabilir.

TASK_KILLABLE (ddaa'nın cevabı ile bağlantılı LWN makalesinde belirtilmiştir) yeni bir varyanttır.

Bu ilk sorunuza cevap verir. İkinci sorunuza gelince: kesintisiz uykulardan kaçınamazsınız, bunlar normal bir şeydir (örneğin, bir işlem diske her okuma / yazma) gerçekleşir; ancak bir saniyenin sadece bir kısmı kadar sürmelidir. Daha uzun süre dayanırlarsa, genellikle aygıt sürücüsünün donanımın asla gerçekleşmeyecek bir şey yapmasını beklediği bir donanım sorunu (veya çekirdeğe benzeyen bir aygıt sürücüsü sorunu) anlamına gelir. Ayrıca, NFS kullandığınız ve NFS sunucusunun kapalı olduğu anlamına da gelebilir (sunucunun kurtarılmasını beklemektedir; sorunu önlemek için "intr" seçeneğini de kullanabilirsiniz).

Son olarak, iyileşememenizin nedeni, çekirdeğin bir sinyal vermek veya işlemi öldürmek için kullanıcı moduna dönene kadar beklemesinin aynı nedenidir: potansiyel olarak çekirdeğin veri yapılarını bozar (kesilebilir bir uykuda bekleyen kod, bunu bildiren bir hata alabilir) işlemin öldürülebileceği kullanıcı alanına geri dönmek için; kesintisiz bir uykuda bekleyen kod herhangi bir hata beklemiyor).


1
Dosya sistemi kilitleme hatası da IME'nin olası bir nedenidir.
Tobu

3
Bütün bunları anlamıyorum. "Kesintisiz uykulardan kaçınamazsınız" - İşletim sistemi, kesintisiz uykunun bir devlet olarak var olmayacağı şekilde yapılamaz mı? O zaman yolsuzlukla ilgili kısım - sürecin kendisinin çekirdek modu kısmı (ya da yolsuzluğa neden olan her ne olursa olsun) sonlandırılamaz mı, yoksa sadece bellekte değiştirilmiş olan kodu geri dönemez mi? Lütfen bunu Linux'un bile yapmadığı için neden bu kadar zor / imkansız olduğunu açıklayın. (Bu sorunun yalnızca Windows'ta bulunduğunu düşündüm)
Dexter

Bu süreçleri gerçekten imkansız (ve sadece son derece zor değil ) öldürmenin (güvenli bir şekilde) yapmasını düşünebileceğim tek durum , donanımın kendisinin bozulmaya neden olabileceğidir. Donanım kontrol edilemez; çekirdek olabilir . Ancak donanımdan veri alan ve belleği değiştiren çekirdek (bu yüzden işlem kullanıcı moduna dönmeden önce serbest bırakılmamalı ve neden bozulma meydana gelebilir) ... bellekteki çekirdek kodunu değiştirin ve daha fazla sorun yok.
Dexter

@Dexter, çekirdeği sanki her işlemin çekirdek modu kısmının çekirdek içindeki bir iş parçacığı olduğu çok iş parçacıklı tek bir işlemmiş gibi düşünün. Öneriniz çok iş parçacıklı bir programda tek bir iş parçacığını öldürmek kadar kötü olurdu: sarkan kilitler, veri yapıları geçici olarak değiştirilmiş veya değiştirilmenin ortasında bırakılabilir vb.
CesarB

@CesarB iyi bir iplik öldürme konusunda haklısınız ... Ama "ana" iş parçacığı (OS çekirdeği ve diğer iş parçacıkları örneğin sürücüleri olurdu) bir şekilde işlemez mi? "Modifiye edilmenin ortasında" olan bu yapılar gerçekten zor bir konu gibi görünse de ... Kesinlikle asla kesintisiz süreçlerin imkansız olacağı bir işletim sistemi göremeyiz :(
Dexter

23

Kesintisiz işlemler genellikle bir sayfa hatasından sonra G / Ç'yi bekliyor.

Bunu düşün:

  • İş parçacığı, çekirdek olmayan bir sayfaya (isteğe bağlı yüklü bir yürütülebilir dosya, değiştirilen anonim bellek sayfası veya isteğe bağlı olarak yüklenen bir mmap () 'dosyasına erişmeye çalışır. aynı şey)
  • Çekirdek şimdi (yüklemeye çalışıyor)
  • Sayfa hazır olana kadar işlem devam edemez.

İşlem / görev bu durumda kesintiye uğratılamaz, çünkü herhangi bir sinyali işleyemez; eğer öyleyse, başka bir sayfa hatası olur ve geri olduğu yerde olur.

"İşlem" dediğimde, gerçekten Linux (2.6) altında kabaca / proc içinde tek bir "iş parçacığı grubu" girdisi olsun ya da olmasın "iş parçacığı" anlamına gelen "görev" demek istiyorum.

Bazı durumlarda, uzun süre beklemiş olabilir. Bunun tipik bir örneği, çalıştırılabilir veya mmap'd dosyasının sunucunun başarısız olduğu bir ağ dosya sisteminde olduğu durumdur. G / Ç sonunda başarılı olursa, görev devam eder. Sonunda başarısız olursa, görev genellikle bir SIGBUS veya başka bir şey alır.


1
Sonunda başarısız olursa, görev genellikle bir SIGBUS veya başka bir şey alır. Bekleyin, çekirdek "bu kesintisiz" süreçleri öldürürken, onlara sadece G / Ç işleminin başarısız olduğunu söyler mi? O zaman süreç kullanıcı moduna geri dönüp gidecek mi? Bu 'D' devlet süreçlerini güvenli bir şekilde öldürmenin bir yolu olmalı. Sanırım bu kolay değil ve bu yüzden ne Windows ne de Linux'un henüz bu olasılığı yok. Öte yandan, bu süreçleri en azından güvensiz bir şekilde öldürmek istiyorum. Muhtemel sistem çökmesi ya da her neyse ...
Dexter

@Dexter hmm, Windows ile bu sorunu hiç yaşamadım. Orada çoğaltmanın yolu nedir? En azından bu gönderiye göre , tüm G / Ç istekleri Windows'da kesilebilir.
Ruslan

1

3. sorunuza: Kesintisiz süreçleri koşarak öldürebileceğinizi düşünüyorum sudo kill -HUP 1. Çalışan işlemleri sonlandırmadan init'i yeniden başlatacak ve çalıştırdıktan sonra kesintisiz süreçlerim gitmişti.


-3

Bir "zombi" işleminden (ps çıktısında "zombi" olarak adlandırılır) bahsediyorsanız, bu işlem listesindeki birinin dönüş kodunu toplamasını bekleyen zararsız bir kayıttır ve güvenli bir şekilde göz ardı edilebilir.

Sizin için "kesintisiz süreç" in ne olduğunu açıklar mısınız? "Öldürmek -9" hayatta ve mutlu birlikte chugs? Bu durumda, bazı sürücüde sıkışmış bazı sistem çağrılarına yapışır ve yeniden başlatılana kadar (ve bazen yakında yeniden başlatmak daha iyidir) veya ilgili sürücünün boşaltılması (gerçekleşmesi olası değildir) . Sürecinizin nerede sıkıştığını öğrenmek ve ileride bundan kaçınmak için "strace" kullanmaya çalışabilirsiniz.


Sürücüler , bir sürecin öldürülmesi gibi zorla boşaltılamaz mı? Çekirdek modunun kullanıcı modundan daha ayrıcalıklı erişimi olduğunu biliyorum, ancak işletim sisteminin kendisinden daha fazla ayrıcalıklı olamaz. Çekirdek modunda yürütülen herhangi bir şey, çekirdek modunda yürütülen başka bir şeyle her zaman kurcalanabilir - kontrol yoktur.
Dexter
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.