2 Ekim 2013 Çarşamba

ARINC 653

Not 1 : Bu yazıyla ilgili VxWorks 653 başlıklı yazıya göz atabilirsiniz.
Not 2 : Windows'ta ARINC 653 Gerçekleştirimi başlıklı yazıya göz atabilirsiniz.


ARINC 653 Nedir ?

ARINC 653 , POSIX standardı gibi , işletim sisteminden bağımsız bir arayüz sağlar. Bu standart ilk olarak 1996 yılında yazılmış. Gerçek zamanlı işletim sistemlerinde kullanılır. Bu standardı kullanan bir uygulamanın bir başka işletim sistemine port edilebileceği söyleniyor. Aşağıdaki şekilde ARINC 653 katmanı görülebilir.

Bu standart yurt dışında yaygın olarak kullanılsa da, benim bildiğim kadarıyla ülkemizde kullanıldığı ilk milli proje TAI'nin gerçekleştirdiği Erciyes C-130 modernizasyonu.


Standart iki kısımdan oluşuyor.

ARINC 653 Part 1 “Required Services”
Bu kısımda mutlaka olması gereken hizmetler tanımlı. Bunlar 
Partition Management
Process Management
Time Management
Inter- Partition and Intra-Partition Communications
Health Monitor Services

ARINC 653 Part 2 “Extended Services”
Bu kısımda olması tavsiye edilen hizmetler tanımlı.
File System Access
Data Logging

Standardın sağladığı API'ye Application Executive (APEX) denilmektedir. Her standartta olduğu gibi (POSIX vs.) APEX te ilk önce type tanımları yaparak başlıyor.Type tanımlamaları örnek için Pthreads on Microsoft Windows başlıklı yazıya bakılabilir.

APEX standardı ADA veya C tabanlı arayüzler sağlıyor. POSIX'ten farklı olarak type tanımları mat (opaque) değil. Yani struct'ların içi standart ile tanımlanmış durumda. Bir diğer fark ise APEX ile yaratılan yapıları, yok etmenin imkanı yok. Gerçek zamanlı işletim sistemlerinde bu yöntem benimsenmiş. Uygulama açılırken gereken kaynağı bir kere alıyor ve bir daha bırakmıyor. Örneğin bir mutex yaratıldıktan sonra silinemiyor.

Bir diğer önemli nokta ise, Buffer, Blackboard, Event, Process, Queuing Port, Sampling Port, Semaphore gibi yapıların "isim" ile yaratılması. Yani hepsi "named" yapılar ve gerek XML gerekse kod içinde isim ile erişilebiliyorlar.

ARINC 653 Aygıt Sürücüler
Aygıt sürücüleri diğer gerçek zamanlı işletim sistemlerinden farklı olarak kesme (interrupt) tabanlı değil, polling tabanlı yazılıyor.

Bölümlenme (Partition) İşlemleri
Bölümlenme bir Unix uygulaması ile aynıymış gibi düşünülebilir. Sistem tasarımında yeni bir bölümlemenin oluşturulmasında diğer bölümleler ile ne kadar bağımlı olunduğu kuralına dikkat etmek gerekir.
As was stated in section II, the ARINC 653 standard encourages the distribution of behavior (user functions) among partitions. Communications between partitions are set through the use of APplication EXecutive (APEX) channels which link statically a source partition with a target one. Though partitioning is expected to enhance reusability, portability and scalability, lots of interconnections tend to reduce all these capabilities. The main reason is that it would be less likely that a partition can work without the support of others (that is, the partitions would be strongly coupled), so that the system would act as it were monolithic.
Bölümlenme için önemli parametreler şunlar:
emniyet seviyesi (criticality level), periyodu (period) ve süresi (duration)
A partition is analogous to a Unix process, in the sense that it runs in its own, separate memory space that is not shared with that of other partitions.
Bölümlenme işlemleri şu konuları kapsar: Bölümlenmenin durumunu sorgulama (partition status), bölümlenmenin durumunu atama (partition operating mode).

Major Frame
A major frame is a repeating fixed-length period during which each partition is executed at least once. Örnek:

Bir başka örnekte ise gerekirse zaman dilimleri arasında boşluklar (spare) olabileceği de gösterilmiş.

Burada yazdığına göre iyi tasarlanmış bir sistemde, Major Frame'in süresi bölümlenmelerin en küçük ortak katı olmalıymış.
For a well designed system, the duration of the MTF will correspond to the least common multiple of the partitions’ periods (so that it is a multiple of each individual partition’s period).
SET_PARTITION_MODE
Metodun imzası aşağıdaki gibi.

Bir bölümlenme aşağıdaki durumlardan birinde olabilir. NORMAL,IDLE,COLD_START ve WARM_START.

SET_PARTITION_MODE(NORMAL) çağrısı ile partition içi scheduler'ı çalışmaya başlıyor. Bu noktadan sonra dinamik olarak başka process yaratılamaz. Böylece sistem kararlı bir hale gelir.

SET_PARTITION_MODE(IDLE) çağrısı ile bölümlenme uygulamalarını çalıştırmayı durdurur. Bu çağrıyı bölümlenme içindeki herhangi bir uygulama yapabilir. Eğer bölümlenme IDLE durumuna geçerse, tekrar başlatmanın tek yolu bölümlenmeyi yeniden başlatmaktır.

COLD_START ve WARM_START ise tam olarak ne işe yarar bilmiyorum. Bir hata oluştuğunda bölümlenmeyi tekrar başlatmak için kullanılabilir diye düşünüyorum.

Process İşlemleri
Process ise thread ile aynıymış gibi düşünülebilir.
ARINC-653 processes are analogous to POSIX threads. (Arguably, the usage of the word ‘process’ in the standard is unconventional, and can be confusing.) A partition may include one or more processes that share time and space resources. Processes have strictly applied priorities – if a process of higher priority than the current process is blocked and becomes able to run, it will preempt the running process immediately. Processes that have equal priority are round-robin scheduled. Memory is shared between all processes within a partition.
Process işlemleri şu konuları kapsar : Process bilgisinin alınması (identifier ve status), yeni process yaratılması, process'in önceliğinin değiştirilmesi, process'in yönetilmesi (suspend/resume, stop/start)

Aşağıda tanımlı olan PROCESS_ATTRIBUTE_TYPE yapısına bakarsak, Posix uygulamalarında bulunan başlatılan thread'e ek veri geçebilmek için bir alan olmadığını görüyoruz. Başlatılan process'e başlama verisi geçebilmenin tek yolu NAME alanına birşeyler yazma ve bunu thread için parse etmek ki bu çok ilkel bir yönteme dönüşüyor.

CREATE_PROCESS 
Metodun imzası aşağıdaki gibi.
İlk parametre yaratılması istenen yeni process'in özelliklerini belirtir. İkinci parametre eğer yaratma işlemi başarılıysa yeni process'in numarasıdır. Üçüncü parametre ise metodun döndürdüğü sonuçtur. Çağrı başarılı ise NO_ERROR dönmesi gerekir. Hata değerleri aşağıda.



Buradan PROCESS_ATTRIBUTE_TYPE yapısı var.

ENTRY_POINT
Process'in başlama metodunu belirtir. Metodun imzası şöyle:
typedef void  (* SYSTEM_ADDRESS_TYPE);
Burada dikkat edilmesi gereken nokta, normalde function pointer şöyle tanımlanır.
[return type] (*[name])([argument list]). Örnek:
int (*x)(); // pointer to a function that returns an int

Yukarıdaki metod imzası ise function pointer gibi tanımlanmıyor çünkü boş bile olsa () parantezleri eksik ancak yine de bir şekilde çalışıyor.

Bir function parametre olarak geçilirse, aynı array'ler gibi pointer olarak algılanır.Sebebi ise function pointer decay. Dolayısıyla x.ENTRY_POINT = function çağrısı için = işaratinden sonra ampersand koyabiliriz veya koymayabiliriz. Her ikisi de aynı. Örnek:


Yani void dönen ve parametresi olmayan bir metod. Bu alıştığımız POSIX thread başlama metodlarından farklı. POSIX'te void* dönen ve void * parametresi alan bir metod kullanılıyor.


STACK_SIZE
Process için kaç byte büyüklüğünde stack ayrılacağını gösterir.

BASE_PRIORITY
Bu alanın alabileceği değer platformdan platforma değişmektedir. Küçük sayır en düşük, büyük sayı ise en yüksek önceliği gösteriyor. MIN_PRIORITY_VALUE ve MAX_PRIORITY_VALUE değerleri alt ve üst sınırları gösterir.

PERIOD
Process'in kaç saniyede bir tekrar uyandırılacağını belirtir. Eğer bu değer 0 ise bu uygulama periyodik değildir. Emin olmamakla beraber Eğer INIFITE_TIME_VALUE verilirse, process'in periodik olmaması sağlanır. Aperiodik task'ın zaman süresi olmadığı için, sürekli yaşayan böyle bir task'ı durdurmanın tek yolu, bir kaynak (resource) üzerinde bloke ettirmektir.


TIME_CAPACITY
En uzun olabilecek çalışma (Worst-case execution) süresini belirtir. Bu sürenin tanımlanması WCE analizinin yapılmasını kolaylaştırır. Aşağıdaki şekilde tahmin edilen ve gerçekleşen WCE sürelerinin farklı olabileceği görülebilir. İşlemcinin daha verimli kullanılabilmesi için, tahmini WCE değerinin aşağıa çekilmesi gerekir. 

Eğer process işini verilen  süre içinde bitiremezse, deadline action çağırılır. Çağırmanın sonucu aşağıda. Bu alan PERIOD alanının değerinden büyük olamaz. Eğer INIFITE_TIME_VALUE verilirse sanırım deadline tanımlanmamış anlamına geliyor. Bu da process'in periodik olmaması demek.
 

DEADLINE

SOFT veye HARD olarak verilebiliyor.
typedef enum { SOFT = 0, HARD = 1 } DEADLINE_TYPE;
SOFT deadline, sadece hatayı kayıt eder. HARD deadline ise WARM_START'a sebep olur.


Bu çağrı ile bir thread başlatılıyor. Örnek:

Aşağıdaki şekilde daha görsel bir gösterim var.

CREATE_ERROR_HANDLER
Metodun imzası aşağıdaki gibi.

Bu task'ın deadline'ı yoktur. Örnek için VxWorks 653 başlıklı yazıya göz atabilirsiniz.
Bu task'a işletim sistemi tarafından en yüksek öncelik verilir. 
 
START
Process yaratıldıktan sonra hemen başlamıyor.  START veya DELAYED_START metodlarından birini çağırmak lazım. Metodları çağırırken ilk parametre olarak CREATE_PROCESS ile elde ettiğimiz numarayı kullanıyoruz. DELAYED_START belli bir süre bekledikten sonra process'i başlatmak için kullanılıyor.


 
Zaman İşlemleri (Time management)

Zaman işlemleri şu konuları kapsar: timed wait, periodic wait, replenishment (bitiş süresinin ertelenmesi) ve sistem saatinin sorgulanması.

GET_TIME
Konuyla ilgili Hassas Süre Ölçümü ve API başlıklı yazıya göz atabilirsiniz.

TIMED_WAIT
Sleep ile aynı işlevi görür. Dikkat edilmesi gereken nokta, her sleep işleminde olduğu gibi verilen süre kadar değil sysClkRateGet (sistem clock) metodunun yukarı yuvarlanmış hali süre bekler. Uyuma işlemi bittikten sonra, task işletim sistemi tarafından "Ready" haline getirilir ancak çalıştırılması garanti değildir.

Bölümlenmeler Arası (Interpartition) Yapılar
Buraya taşıdım.

Bölümlenme İçi (Intrapartition) Yapılar

Buffer
Bir çeşit FIFO kuyruk.

CREATE_BUFFER : Yeni bir kuyruk yaratır.
SEND_BUFFER : Kuyruğa yeni bir eleman ekler.

Aşağıdaki şekilde aynı bölümlenme içindeki uygulamaların Buffer aracılığıyla haberleşebildikleri görülebilir.


Blackboard 
Tek bir element alıyor. Her güncelleme işlemi bir önceki bilginin üzerine yazar.

CREATE_BLACKBOARD : Yeni bir blackboard yaratır
DISPLAY_BLACKBOARD : Tahtadaki tek elemanı günceller.

Semaphore
Semaphore kullanırken "Priority Inversion" problemine dikkat etmek lazım. Problem düşük önceliğe sahip uygulamanın, daha yüksek önceliğe sahip uygulamayı semaphore'a sahip olmak için bekletmesinden kaynaklanıyor. Semaphore'un mümkün olduğunca eşit öncelikteki uygulamalar arasında kullanılması tavsiye edilmiş.

Health Monitoring
Health monitoring için kullanılan process'ler en yüksek ve değiştirilemez önceliğe sahiptirler. Preemptible olmadıkları için hataları işlerken başka bir uygulama tarafından engellenemezler.

ARINC 653 ve XML
ARINC 653 bir çok ayarın XML ile yapılmasını istiyor. XML yapısı aşağıdaki farklı renklerde gösterilen başlıklardan oluşuyor. Bunlar <Partition>, <Schedules> ve <HealthMonitoring> başlıkları. Maalesef XML'de tanımlanan özellikleri kod içinde sorgulamak için API mevcut değil.


XML derlenince Module OS içinde kaynaklar ayrılıyor. Daha sonra APEX API çağrıları ile
CREATE_XXX şeklinde bir çağrı yapılarak, istenilen kaynağın ismi verilir veModule OS'taki yapıya direkt erişmek için kullanılan bir ID alınır. Yani eşleşme için XML'deki kaynak ismi ile CREATE_XXX çağrısına verilen kaynak ismi aynı olmak zorunda.

APEX ve Real-Time olmayan İşletim Sistemleri Arasındaki Farklar
APEX ile bir eş zamanlılık veri yapısı üzerinden bekleme yaparken, bekleyen threadlerden hangisinin uyandırılacağını belirtme imkanı var. Seçenekler, Priority veya FIFO.

Ancak Windows ve Unix ailesinde bu tür seçenekler net olarak mevcut değil. Posix Eşzamanlılık Yapıları başlıklı yazıda, Linux'ta bekleme yapan threadlerin önceliğine göre uyandırıldığı yazılı. Ancak Posix'te standartta bu şekilde olmasını gerektiren bir zorunluluk yok.

Yazılımı geliştirirken geliştirme ortamı Windows ise, hedef ortamda olmayan Windows'a mahsus bazı kodları kullanmak için aşağıdaki macro bloku kullanılabilir.

#if defined _WIN32
//Windows'a mahsus kod
#endif

ARINC 653 ve Dinamik Hafıza Kullanımı
Dinamik hafıza kullanımını engellemek için Array tabanlı bazı veri yapıları aşağıda.

Array Tabanlı Fabrika Örüntüsü
Aşağıdaki örnekte Fabrika (Factory) örüntüsü gösteriliyor. Nesneler bir dizi içinden çekiliyorlar. Örnekte fabrika son nesneyi de üretince, artık NULL döndürüyor. Ancak bir çok sistemde, nesnenin işinin bittiği farz edilip, sayacın tekrar başa dönecek şekilde kullanıldığını da gördüm.


Array tabanlı Dequeue
Başa ve sonra ekleme/çıkarma işlemlerini O(1)'de yapabilen, sınırlı kapasitesi olan array tabanlı dequeue örneği. Diğer ismiyle Circular Buffer. Bu veri yapısında head ve tail sadece kuyruk boş iken aynı indeksi gösterirler. Kuyruk tam dolu iken tail head'in bir mantıksal olarak bir arkasındadır.

Enqueue işleminde m_Size değişkenini tutmak istemiyorsak, tail bir artırılınca, head'den farklı ise halen yer vardır.

Dequeue işleminde head != tail ise halen okunacak elaman vardır diye de kodlanabilirdi.

class Queue{
 Object** m_pBuffer;
 uint16_t m_Capacity,m_Head,m_Tail,m_Size;

};
Queue::Queue(){
  m_ pBuffer = NULL;
  m_Head     = NULL;
  m_Tail        = NULL;
  m_Size       = 0;
  m_Capacity= 0;
}

void Queue::SetCapacity(uint16_t capacity){
 m_pBuffer = new Object*[capacity];
 memset (m_pBuffer,0,sizeof(Object*) * capacity);//Reset array
 m_Head = m_Tail = m_Size = 0;
 m_Capacity = capacity;
}

Object* Queue::Dequeue (){
  Object* pResult = NULL;
  if (m_Size > 0) { //If not empty
    pResult = m_pBuffer [ m_Head ];
    m_Head ++;
    m_Size --;
    if ( m _Head == m_Capacity ) {//Rollover
      m_Head = 0;
    }
  }
  return pResult;
}

Object* Queue:Enqueue (void* ptr){
 bool result = false;
 if (m_Size < m_Capacity){//If has space
  m_pBuffer [ m_Tail ] = ptr;
  m_Tail ++;
  m_Size ++;
  if (m_Tail == m_Capacity) { //Rollover
    m_Tail = 0;
 }
  result = true;
}
return result;
}
Array Tabanlı Kuyruk
Bu veri yapısında, ortadan eleman çıkartmak mümkün. Bu durumda ortada boşluk oluşuyor. Boşluğu gidermek için ya silinenen indeksten sonraki herşeyi memmove ile bir öne taşımak lazım (defragmentation, bu durum std::vector kullanımına benziyor) ya da boşlukları saklayan bir ikinci veri yapısı (örneğin yukarıdaki dequeue gibi) kullanarak O(1) zamanda boşluğa erişim sağlayabilmek gerekiyor.

İkinci kullanım şeklinde veri herhangi bir özelliğe göre dizilmez, tüm verilerin bir küme şeklinde sıralamaya bakılmaksızın işlendiği farz edilir.
 



ARINC 653 ve Mimari
Gömülü mimarilerde genellikle aşağıdakine benzer mimarisel katmanlar bulunur.
Hardware Abstraction Layer
Device Driver Layer
RTOS layer
Application Layer

ARINC 653 ve Dosya Sistemi
ARINC 653 Required Services dosya sistemi ile ilgili hiç bir API tanımlamıyor. Dolayısıyla bir çok işletim sistemi sadece temel hizmetleri saladığı için dosya sistemine erişim kodları genellikle, native API kulllanılarak yapılıyor. Loglama gibi hizmetleri ayrı bir bölümlenme üzerinden yönetmek çok kullanılan bir yaklaşım. 

ARINC 653 ve Scheduling
Konuyu ARINC 653 Scheduler başlıklı yazıya taşıdım.

Tübitak ve Gerçek Zamanlı İşletim Sistemi (GIS)
Tübitak BİLGEM de GIS adını verdiği ve ARINC 653'ü destekleyen bir işletim sistemi geliştirdi. Gazetelerde yazanın aksine, anladığım kadarıyla bu işletim sistemi henüz bir projede kullanılmış değil.

Bu işletim sistemi, ek olarak POSIX (PSE51, PSE52, PSE53) standartlarını da destekliyor. Aşağıdaki şekilde bu standartların birbirleri ile ilgisini görebilirsiniz.

Burada yazdığına göre PSE51 287 API'den oluşuyor. PSE52 626 ve PSE53 ise 754 API'ye sahip. GIS'in tüm bu API'leri desteklediği yazılmış. Ancak her ne olursa olsun ARINC 653'e kıyasla çok fazla API var.

VxWorks 6.4 PSE52 uyumluluk sertifikasını 2006 senesinde aldı. GIS'in sertifikası varmı bilmiyorum.

PSE51'in kapsamı aşağıdaki şekide görülebilir.
threads, fixed-priority schedul-ing, mutexes with priority inheritance, condition variables, semaphores, timing services including CPU-time clocks, simple device I/O, signals, and memory management.


Aralarındaki temel farkları gösteren bir şekli ise buradan aldım.

GIS ile ilgili gazete haberi de burada.
Not : Yazının ilk halinde şöyle yazmıştım.  Ancak gelen uyarı üzerine aşağıdaki gibi düzelttim.
GIS'in teknik  şu anda sadece 2 işlemciyi destekliyor
GIS şu anda sadece Freescale MPC74xx işlemcilerde çalışıyor. Freescale 2004 yılında Motorola'dan ayrılan bir firma. Dünyanın en büyük ticari PowerPC işlemci üreticisi. Board olarak da sadece Curtiss-Wright'ın DY4-181 board'unda çalisabiliyor. VxWorks 653 ise çok daha fazla işlemciyi destekliyor.
Aşağıdaki mpc7448'in karşılaştırmasını görebilirsiniz. Tablodaki MIPS (Million Instructions per second) anlamına geliyor.


Bu İşletim Sistemi Uzayda Kullanılabilir mi ?
Uzayda kullanılan işlemciler radyasyona dayanıklı olmak zorunda. COTS işlemciler bu isteri karşılamıyor. Dolayısıyla ya mevcut bir işlemciyi radyasyona dayanıklı hale getirmek, ya da yeni bir işlemci tasarlamak gerekiyor. Örneğin RAD 750 PowerPC 750 tabanlı bir işlemci. İşletim sistemi de haliyle bu işlemci ile çalışabilmeli. Avrupada uzay alanında genellikle PikeOS veya RTEMS kullanılıyor. GIS böyle bir işlemciyi desteklemediği müddetçe uzayda kullanılamaz.

24 Eylül 2013 Salı

Hibernate Extra Lazy Collection

OneToMany ilişkilerde Hibernate List arayüzünü gerçekleştiren PersistentBag sınıfını kullanır. 
Bu sınıfın size() metodu aşağıdaki gibidir.

Eğer OneToMany  ilişki lazy tanımlanmış ise yukarıdaki kodda görülen readSize metodu aşağıdaki
if (persister.isExtraLazy()){...} dalına girmez . Grimediği için de en alttaki read() metodunu çağırır ve false döner. Dolayısıyla aşağıdaki gibi bir  Sql cümlesinin çalışmasına sebep olur.

select * from child where child.parentID = ?

Eğer ilişki @LazyCollection(LazyCollectionOption.EXTRA) anotasyonu ile extra lazy olarak tanımlı ise bu sefer if (persister.isExtraLazy()){...}dalına girer ve aşağıdaki gibi bir  Sql cümlesinin çalışmasına sebep olur.
select count(ID) from child where child.parentID =?

.Net
.Net ile Lazy sınıfı geliyor. Bu sınıf aslında PersistentBag ile benzeşiyor. Örneğin veritabanından lazy yükleme yapmak için aşağıdaki gibi yapabiliriz.

Lazy<List<Order>> orders = new Lazy<List<Order>>(() => LoadOrders()); 

List<Order> LoadOrders()
{...}


23 Eylül 2013 Pazartesi

.Net ThreadPool vs. QThreadPool vs. Java ThreadPoolExecutor

Not 1: Linux Scheduler'ları başlıklı yazıda ThreadPool içinde koşan thread'lerin öncelik seviyesinin ayarlanması ile ilgili bilgi bulmak mümkün.
Not 2 : ACE_Thread_Manager ile yeni thread yaratmak başlıklı yazıda ise Process Scheduler ve kernel tarafından kullanılabilen thread modelleri ile ilgili bilgi bulmak mümkün.

.Net 4.0 ThreadPool

.Net 4.0 ile gelen ThreadPool sınıfı yaratılabilecek azami thread sayısını dinamik olarak hesaplıyor.

MSDN'nin dediğine göre :

There is one thread pool per process. Beginning with the .NET Framework version 4, the default size of the thread pool for a process depends on several factors, such as the size of the virtual address space. A process can call the GetMaxThreads method to determine the number of threads. The number of threads in the thread pool can be changed by using the SetMaxThreads method. Each thread uses the default stack size and runs at the default priority. 
4 tane Core i5 CPU'ya sahip 3 GB hafıza taşıyan sistemim için bu rakamlar :

1023  tane worker thread ve 1000 tane de I/O completion thread çıkınca bayağı şaşırdım. Bu kadar çok thread açılabileceğini hiç sanmazdım.

Aslında açılan thread sayısını da sınırlamak için bir tedbir de düşünülmüş.
ThreadPool Max Threads sorusuna verilen bir cevapta :

However, there's something else at play: the thread pool doesn't immediately create new threads in all situations. In order to cope with bursts of small tasks, it limits how quickly it creates new threads. IIRC, it will create one thread every 0.5 seconds if there are outstanding tasks, up to the maximum number of threads. I can't immediately see that figure documented though, so it may well change. I strongly suspect that's what you're seeing though. Try queuing a lot of items and then monitor the number of threads over time.

Yani ThreadPool'da akıllı davranıyor ve biraz bekliyor çünkü çoğu işin kısa sürede biteceğini düşünerek iyimser davranıyor.

ThreadPool Available Threads shows very high figures sorusunda ise kaç tane daha thread'in açılabileceğini öğrenmek için ThreadPool.GetAvailableThreads metodunun kullanımına örnek verilmiş.



QT QThreadPool

Öte yandan QT ile gelen QThreadPool sınıfı en fazla sistemdeki core sayısı kadar thread yaratıyor.

Returns the ideal number of threads that can be run on the system. This is done querying the number of processor cores, both real and logical, in the system. 

Yani benim sistemimde bu sayı 4 olacaktı ki .Net ThreadPool sıfınıfa göre sayı yetersiz görünüyor.

Bu arada QT ile yaratılan threadler posix threadleri. Thread'ler pool tarafından join edilecek şekilde yaratılıyorlar. Yani threadler yaratılırken PTHREAD_CREATE_DETACHED flag'i kullanılmıyor. Bu flag'in kullanım amacını buradan okuyabilirsiniz. Böylece thread pool tüm worker thread'lerin bitmesini waitForDone() metodunu çağırarak bekleyebiliyor. waitForDone() metodu ise aslında pthread_join metodunu çağırıyor. Aşağıda pthread_join() metodunun nasıl çalıştığını gösteren bir şekil var.


Yeri gelmişken Avoiding memory leaks in Posix Thread Programming başlıklı yazıda
ls /proc/PID/task | wc -l ve (Bu komut ile aktif threadler sayılıyor)
pmap PID | grep 10240 | wc -l (Bu komut ile yaratılan thread stackleri sayılıyor)
komutları kullanılarak pthread_join() metodu ile bitmesi beklenilmemiş thread'lerin nasıl bulunabileceği anlatılıyor.

Nitekim yaptığımız bir projede karşı cihazı SNMP ile sorgulama işinin biraz uzun sürmesi halinde QThreadPool sınıfının tıkanma noktası oluşturduğunu görüp  açılabilecek max. thread sayısını artırmak zorunda kalmıştık.

Kendi Thread Poolumuz
Aşağıda kendi thread pool nesnemizi kabaca gösteren bir kod parçası var.
class Executor {
  FIFOQueue<Task> m_List;
  FIFOQueue<Task> m_CompletedList;

  void Initialize (int threadCount){
    for (int index = 0; index < threadCount; index++) {
      Worker thread = new Worker (this);
       t.start ();
    }
  }

  bool ExecuteTask () {
    Task* pTask = m_List.Dequeue ();
    pTask->Perform ();
    m_CompletedList.Enqueue (pTask);
  }

  Task* GetCompletedTask () {
    return m_CompletedList.Dequeue ();
  }
};

class Worker : public Thread {
Executor* m_pExecutor;
  void Execute () {
    while (runFlag){
        m_pExecutoer->ExecuteTask ();
    }
  }  
};

Java ThreadPoolExecutor

ThreadPoolExecutor aslında karmaşık bir hiyerarşinin parçası. Bu hiyerarşiye kısaca bakarsak herşey Executor ve ExecutorService arayüzleri ile başlıyor.

Arayüzleri gösteren bir diğer şekli ise buradan aldım.

 Bir ExecutorService yaratmayı kolaylaştırmak için Executors sınıfı mevcut. Örneğin aşağıdaki kod parçasıyla
ExecutorService sendingService = Executors.newSingleThreadExecutor();

buradan aldığım şekildeki gibi herşeyi sırayla işleyen tek threadli bir servis yaratılabilir.



Java ile gelen ThreadPoolExecutor ise kendisi kaç tane thread açması gerektiğini hesaplamıyor bile. Her şeyi programlayacının inisiyatifine bırakmış ne kadar istersen o kadar aç ben karışmam diyor.Aşağıdaki şekli buradan aldım.



Yalnız ThredPoolExecutor sınıfının bir güzel özelliği işlemediği görevleri için bir rejection handler kullanması. Aşağıda buradan aldığım hazır kullanılabilen rejection handler sınıflarının şekli var.


Özel bir çeşit thread pool olan ScheduledThreadPoolExecutor sınıfının hiyerarşi şeklini ise buradan aldım.

Özet
Özet olarak .Net ThreadPool sınıfı ise işin bloke olabileceğini farz edip core sayısından kat kat fazla thread açılabilmesine imkan tanıyor.Çıtayı çok yüksek tutmuş.


 QThreadPool sınıfı kendine verilen işlerin çok çabuk biteceğini farz ediyor ve işin bloke olmasını kabul etmiyor. Dolayısıyla çıtayı alçak tutup azami thread sayısını düşük tutmuş.

Esasen QThreadPool sınıfını da 1023 thread açabilecek hale getirdikten sonra problem kalmıyor ancak iki thread pool sınıfı arasındaki felsefe farkına dikkat çekmek istedim.

Jaba ThreadPoolExecutor ise ben bilmem  beyim bilir yöntemini seçmiş ve her şeyi programlayıcıya bırakmış.

20 Eylül 2013 Cuma

Spring Bean XML Tanımları

Spring IoC XML tanımları ile ilgili aldığım notlar aşağıda.

Yaratılmış Olan Bean'e Değer Atamak
Tek Parametreli Setter İle Bir Başka Bean Atamak
Örnek buradan geldi.
<property name="beanTwo" ref="yetAnotherBean"/>
Tek Parametreli Setter İle Değer Atamak
Örnek buradan geldi.
<property name="name" value="myvalue" />
Tek Parametreli Setter İle List Atamak
Örnek buradan geldi.
<property name="list">
    <list>
        <value>1</value>
    </list>
</property>
Bean Yaratmak
Constructor metoduna parametre geçmek
Örnekte constructor parametreleri string ise aynen geçilir. int long tipleri ise XML'de hangi tip oldukları belirtilir.

<bean id="Pool" class="org.apache.commons.pool.impl.GenericKeyedObjectPool">
  <constructor-arg type = "int" name = "maxActive" value="3" />
  <constructor-arg type = "long" name = "maxWait" value="3000" />
  <constructor-arg name = "testOnBorrow"  value="true" />
</bean>

Factory Sınıf ile Bean Yaratmak
Elimizdeki sınıfın bean yaratmak için static bir metodu varsa aşağıdaki gibi kullanabiliriz. Örnekte Pattern sınıfının static olan compile metodu yeni bir bean yaratmak için kullanılıyor.
<bean id="pattern" class="java.util.regex.Pattern" factory-method="compile">
    <constructor-arg value="abc"/>
</bean>

6 Eylül 2013 Cuma

SSH

SSH ile key üretmek için ssh-keygen yazılımı kullanılıyor. Bu yazılım bir private bir de public key üretir.
 Public key her zaman karşıdakine verilen dosyadır. Aşağıda bu durumu gösteren ve buradan aldığım bir örnek resim var.
Bir başka örnekte ise public/private key oluşturmak için aşağıdaki komut kullanılıyor. -f seçeneği ile private key'in hangi dosyaya konulacağı belirtiliyor.
ssh-keygen -t rsa -f ~/.ssh/id_rsa
Public karşıdaki sistemin ~/.ssh/authorized_keys dosyasına eklenir. Örneğin ismi id_rsa.pub olan public key dosyasını eklemek için aşağıdaki komut kullanılabilir.
 cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
Karşı Sistemde Komut Çalıştırmak
Örnek:
ssh root@mypc "opt/mycode/check.sh"

Eğer istersek bir betik yazıp ssh'a parametre geçip geçilmediğini de kontrol edebiliriz. Örnek:
if [ $# - eq 2 ]; then
  ssh root@mypc $1
fi


18 Ağustos 2013 Pazar

JSR 181

Giriş

JAX-WS ile JSR 181 ile kullanılması kararlaştırılan anotasyonlar kullanılıyor. Bu anotasyonlardan bazıları
@WebService, @WebMethod, @WebParam vs. Anotasyonlar javax.jws paketinde mevcut.

JSR 181 Anotasyonları

javax.jws.WebService ve serviceName

Eğer bir web servisine aşağıdaki gibi isim verilirse 
@WebService(name = "myService")
üretilen wsdl dosyasında aşağıdaki gibi bir XML üretiliyor

<service name="myService">
    <port name="myServicePort" binding="tns:myServicePortBinding">
    <soap:address location="http://localhost:8080/myApp/webservice"/>
    </port>
</service>
Burada kullanılan servis ismine ?wsdl eklenip sorgulama yapılırsa XML çıktısı görülebilir.

Bazen wsdl dosyasında wsdl: şeklinde kullanım da görülebilir. O zaman XML aşağıdaki gibi olacaktı.

<wsdl:service name="myService">
    <wsdl:port name="myServicePort" binding="tns:myServicePortBinding">
    <soap:address location="http://localhost:8080/myApp/webservice"/>
    </wsdl:port>
</wsdl:service>
Eğer serviceName atanmazsa, JAX-WS sınıfın ismine "Service" kelimesini ekliyor. Örnek:
Bu sınıf için wsdl dosyasını adresi aşağıdaki gibidir.Sınıfın ismine yapılan ektentiye dikkat.
http://localhost:9080/service/ServiceImplService?wsdl
javax.jws.WebService ve portName
Eğer WebService'e portName vererek aynı arayüzden türeyen ancak farklı çalışan sınıflar yazabiliriz. Örnek:
Üretilen wsdl aşağıdaki gibi olacaktır.

javax.jws.WebMethod

Eğer bir metodun dışarıya açılmasını istemiyorsak aşağıdaki gibi yapıyoruz.
@WebMethod(exclude = true)
javax.jws.OneWay

Eğer bir metodun geriye döneceği bir cevap yoksa onu OneWay olarak işaretlersek WSDL dosyasında port'a bağlı olan output tagleri üretilmez. Örnek:
@WebMethod
@OneWay
public void myCall ()...

Linux Dosya Distemi

Bu yazıyla ilgili olarak TTY ve Devpts , Per Process File Table ve INode ve ls komutu başlıklı yazıları okuyabilirsiniz.

HAL
Hardware Abstraction Layer (HAL) ile fstab arasındaki bağlantıyı gösteren bir şekili buradan aldım.

Mount
Mount komutu yazısına taşıdım.

Virtual File System (VFS)

fstab veya mount ile bağlanan diskler farklı dosya sistemelerini kullanıyor olabilirler. Aradaki farkları ortadan kaldırmak için VFS sistemi kullanılır. VFS sistemini gösteren bir şekli buradan aldım.


Path'i bilinen bir dosyayı açmak için VFS path'ten yukarı doğru çıkıyor ve mount edilmiş dosya sistemini buluyor.


Örneğin /proc altındaki bir dosya okunmak istenirse istek önce VFS sistemine geliyor. Sistem isteği procfs dosya sistemine geçiyor ve gelen cevabı da uygulamaya gönderiyor. Akışı gösteren bir şekili aşağıda bulabilirsiniz.



Böylece procfs aslında diskte bulunmadığı halde VFS sayesinde diskin bir parçasıymış gibi kullanılabiliyor.

The "Virtual File System" in Linux başlıklı yazıda VFS ana kısımlara bölünmüş. Bunlar :
  1. super-block : Her mount edilmiş dosya sistemi hakkında bilgiyi tutar
  2. inode  : Bir dosyanın ismi ve gerçek verisi hariç geri kalan herşeyi tutar
  3. directory : Dosya isimleri ile inode yapısını eşleştirir
  4. file  : Dosya ile inode yapısını eşleştirir. Eşleşmeyi daha iyi anlamak için Per Process File Table ve INode başlıklı yazıyı okuyabilirsiniz.
şeklinde açıklanmış.

Index Node (inode)


Linux dosya sisteminin temelinde inode (index node) yapısı bulunmakta. Bu yapıyı gösteren bir kaç şekli aşağıya ekledim.
İlk şekli buradan aldım.


Ext2 dosya sistemini gösteren bir diğer şekli ise buradan aldım.
inode ve programlama
inode verisi C dilinde ino_t ile temsil edilir. inot_t aslında çoğunlukla long gibi bir şeye typedef'dir.

inode ve  reference count
Her inode yapısının içinde bir sayaç bulunuyor. Bu sayaç inode'a hard link ile bağlı olan dosyaların sayısını tutuyor. Eğer sayaç sıfır olursa inode silinebiliyor.

inode ve block yapısı
Tüm şekiller hemen hemen aynı çalışma yöntemini işaret ediyor. Bir inode yapısı içinde diskteki blokların adresleri tutuluyor. Aslında Unix ve diğer işletim sistemleri dosya erişimini byte-stream mantığı üzerine oturtmuş durumdalar ancak sabit diskler bloklar ve sektörler şeklinde çalışıyor. Dolayısıyla inode yapısı içinde blok büyüklüğü ve stream içindeki örneğin 100. byte'ın aslında hangi sektörde olduğu bilgisi bulunuyor.
inode veri yapısı ile dosyanın sahibi, grubu, erişim hakları ve erişim zamanı gibi bilgileri sakladığını söylemiştik.
Yani inode yapısında dosya sistemine ait metadata bilgisi de mevcut.

Bu bilgileri gösteren bir şekle bakmak için ls komutu başlıklı yazıya göz atabilirsiniz.


inode veriyapısı tarafından desteklemesi gereken işlemleri örnekleyen bir şekil ise aşağıda.
Bu işlemler birer virtual function gibi düşünülürse, her dosya sisteminin nasıl olup ta aynı arayüz üzerinden farklı medyalara farklı formatlarda yazabildikleri daha rahat anlaşılır.

Does folders in windows have IDs? or GUIDs? sorusunda Windows üzerinde inode numarası gibi bir numara üretilmesini sağlayan ilginç bir yöntem gördüm. Kod aşağıdaki gibi



Linux üzerinde bir dosyanın inode numarasını görmek için ls komutu başlıklı yazıdaki inode numarası bölümüne bakabilirsiniz.

inotify
inotify dizin izleme yazısına taşıdım.