Watchdog Kullanımı
Watchdog mekanizmaları, çalışan ana yazılımların beklenmedik bir şekilde sonlanması sonrasında sistemin yeniden başlatılabilmesine imkan tanır.
Bu mekanizma genellikle donanım tabanlı bir zamanlayıcı (Watchdog Timer - WDT) ile gerçekleştirilir.
Sistemin genel çalışma prensibi oldukça basittir:
- WDT zamanlayıcısını örnek olarak 60 saniye için başlat
- 60 saniyelik süre bitmeden hayatta olduğunu ispat et ve yeni bir 60 saniye kazan
Periyodik olarak zamanlayıcıya hayatta olduğunuzu söylediğiniz müddetçe sorun olmayacaktır. Ancak bu işlemi yapamaz hale gelirseniz (uygulamanız bir SEGFAULT ile sonlanmışsa vb.) zamanlayıcının süresi dolduğunda sistem otomatik olarak yeniden başlatılacaktır.
Buradaki yeniden başlatma işlemi kontrollü (reboot) değil, reset şeklindedir.
Kernel Panic Sistemi İle Fark
Watchdog haricinde görece benzer bir işlevi Linux çekirdeği içerisindeki panic handler ile de yapabildiğimizi hatırlayınız. Eğer çekirdek içerisindeki yer alan kodlarda herhangi bir kritik hata oluşması nedeniyle tüm çekirdek çalışamaz hale gelirse, sistemin panic
parametresi ile açılmış olması halinde otomatik yeniden başlatma (reset) işlemi çekirdek tarafından yapılmaktadır.
Ancak bu yöntem sadece çekirdek seviyesindeki hatalarda işe yaramaktadır. Watchdog ise kullanıcı kipi hatalarını da yakalamaya ve bir şeyler ters gittiğinde en azından sisteminizi yeniden başlatabilmenize imkan tanımaktadır.
Çekirdek Desteği
Sistemdeki watchdog donanımının kullanımı için çekirdek seviyesinde sürücü desteği sağlanmış olmalıdır.
Linux çekirdeğinde watchdog donanım sürücüleri için genel bir Watchdog Driver API mevcut olup, tüm donanımlar tarafından aynı arayüz, yetenekleri doğrultusunda sağlanır. Detaylar için https://www.kernel.org/doc/Documentation/watchdog/watchdog-api.txt belgesini inceleyebilirsiniz.
Temel Kullanım Modu
Tüm watchdog sürücülerinin en az bu modu desteklemesi beklenir, dolayısıyla watchdog donanımızın desteklenmesi halinde her durumda bu çalışma yöntemini kullanabilirsiniz.
Çalışma mantığı şu şekildedir:
Uygulama katmanında
/dev/watchdog
aygıt dosyası yazma modunda açılırÖntanımlı olarak 60 saniyelik bir zamanlayıcı başlar
60 saniye dolmadan, bu dosyaya herhangi bir veri yazılır (tek karakter de olabilir) ve zamanlayıcının yeniden başlatılması sağlanır
Uygulama, kendi içinde bir döngüde kalıp zamanında watchdog dosyasına yeni bir veri yazamaz ise, süre dolumunda sistem yeniden başlatılır
Açık durumdaki
/dev/watchdog
dosyası kapatılır ise, watchdog sistemi devre dışı bırakılır
Görüleceği üzere Unix sistemlerde hemen her şeyin dosya arayüzü ile kullanıcı katmanına sunumu yaklaşımı burada da benimsenmiştir. Uygulamanız içerisinde yukarıdaki iş akışını dosya işlemleriyle kolaylıkla gerçekleyebilirsiniz.
Yalnız burada dikkat edilmesi gereken husus, /dev/watchdog
dosyasının yazma modunda açılması ile başlayan zamanlayıcının dosyanın kapatılması halinde devre dışı kalıyor oluşudur. İlk başta önemli bir problem olarak görünmeyebilir, ancak Linux çekirdeği herhangi bir yöntemle sonlanan kullanıcı kipi uygulamaları için, açık halde bulunan tüm dosyaları da kapatır. Bu nedenle watchdog mekanizmasını işletmek için uygulamanızda /dev/watchdog
açık halde iken uygulamanız kontrolsüz biçimde sonlanacak olursa, dosya kapatıldığı için watchdog da devre dışı kalacak ve beklediğiniz zamanlayıcı süresi dolumundaki yeniden başlatma işlemi gerçekleşmeyecektir.
Peki o halde watchdog ne işe yarayacak diye sorabilirsiniz. Endişeye mahal yok.
Bu dizayn ile temelde 3 çözüm yönteminiz bulunuyor:
Ana uygulama(ları)nız içerisinde watchdog yönetmek yerine, watchdog'u yöneten ayrı bir uygulama yazmak (veya hazır bir watchdog daemon kullanmak)
Magic Close özelliği destekleniyorsa kullanmak
Çekirdek derleme sürecinde
CONFIG_WATCHDOG_NOWAYOUT
opsiyonu seçerek, sürücünüzün de desteklemesi halinde watchdog dosyasının kapanmasıyla zamanlayıcının durdurulmasını engellemek
Magic Close Özelliği
Bazı sürücüler Magic Close adı verilen bir özelliği desteklemektedir. Bu destek sayesinde, watchdog dosyası kapatılmadan önce V karakteri dosyaya yazılmaz ise, dosya kapatılsa dahi zamanlayıcı çalışmaya devam etmekte ve zamanı dolduğunda sistemi yeniden başlatmaktadır.
Eğer özellikle watchdog zamanlayıcısını durdurmak istiyorsanız, dosyayı kapamadan önce V karakterini yazabilir ve sonra kapama işlemini gerçekleştirebilirsiniz.
Magic Close desteği daha rahat bir kontrol sağlıyor olmasına karşın sisteminizde desteklenmiyor olması ihtimali kuvvetle muhtemeldir. Bu özelliğin desteklenip desteklenmediğini ioctl arayüzü üzerinden WDIOC_GETSUPPORT
opsiyonuyla sorgulayabilirsiniz. Aşağıdaki örnek uygulama ile watchdog sürücünüzün Magic Close, Set Timeout ve Keep Alive Ping özelliklerini destekleyip desteklemediğini öğrenebilirsiniz:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/watchdog.h>
#define WATCHDOG_DEVICE "/dev/watchdog"
int main(void)
{
struct watchdog_info info;
int fd;
if ( (fd = open(WATCHDOG_DEVICE, O_RDWR)) < 0) {
perror("open failure");
exit(EXIT_FAILURE);
}
if (ioctl(fd, WDIOC_GETSUPPORT, &info) < 0) {
perror("ioctl");
exit(EXIT_FAILURE);
}
printf("Magic Close Feature : %s\n", (info.options & WDIOF_MAGICCLOSE) ? "Yes" : "No");
printf("Set Timeout Feature : %s\n", (info.options & WDIOF_SETTIMEOUT) ? "Yes" : "No");
printf("KeepAlivePing Feature: %s\n", (info.options & WDIOF_KEEPALIVEPING) ? "Yes" : "No");
close(fd);
}
ioctl Arayüzü
Tüm watchdog sürücüleri, destekledikleri özellikler için ioctl arayüzü de sağlamaktadırlar.
Watchdog zamanlayıcıyı beslemek ve yeni bir tur daha süre kazanmak için WDIOC_KEEPALIVE
ile aşağıdaki gibi bir ioctl çağrısı yapabilirsiniz. 3. parametrenin ne olduğunun bir önemi yoktur:
ioctl(fd, WDIOC_KEEPALIVE, 0);
Sürücü tarafından desteklenmesi halinde 60 saniyelik öntanımlı watchdog zamanlayıcı değerini değiştirmek isterseniz, WDIOC_SETTIMEOUT
ile aşağıdaki gibi bir ioctl çağrısı yapabilirsiniz:
int timeout = 20; /* saniye */
ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
Benzer şekilde, zamanlayıcıda kalan zamanı WDIOC_GETTIMEOUT
ile aşağıdaki gibi sorgulayabilirsiniz:
int remaining;
ioctl(fd, WDIOC_GETTIMEOUT, &remaining);
Sistemin son defa yeniden başlatılması işleminin watchdog yüzünden olup olmadığını WDIOC_GETBOOTSTATUS
ile sorgulayabilirsiniz:
int bootfromwatchdog;
ioctl(fd, WDIOC_GETBOOTSTATUS, &bootfromwatchdog);
Daha detaylı özellikler için çekirdek içerisindeki dokümantasyonu inceleyebilirsiniz.