Kabuk kendi denetim uçbiriminde iş denetimi uygulamak için sorumluluğu aldıktan sonra, kullanıcı tarafından yazılan komutlara yanıt olarak işleri başlatabilir.
Bir süreç grubunda süreçleri oluşturmak için
Süreç Oluşturma Kavramları bölümünde açıklandığı gibi
fork ve
exec işlevleri kullanılabilir. Çok sayıda alt süreç karışık olduğundan, ister istemez, bazı şeyler biraz karmaşıklaşır, bu bakımdan bunları doğru sırada yapmak önem kazanır. Aksi takdirde istenmeyen yarış koşulları ortaya çıkabilir.
Süreçlerle ilgili ata-çocuk birliktelik ağacının yapılanmasında yerine göre iki seçimden birini kullanabilirsiniz. Ya, süreç grubundaki tüm süreçleri kabuk sürecinin çocukları yaparsınız ya da, süreç grubundaki bir süreci gruptaki diğer süreçlerin atası yaparsınız. Tıpkı, bu oylumun tamamındaki örnekleri basit bir kabuk yazılımının parçaları olarak vermemiz gibi, çünkü bu, bazı şeylerin muhasebesini yapmayı koloylaştırıyor.
Her süreç çatallandığında,
setpgid çağrısı ile kendini yeni süreç grubuna koymalıdır; bkz.
Süreç Grubu İşlevleri. Süreç grubundaki ilk süreç
süreç grubunun lideri haline gelir ve onun süreç kimliği de
süreç grup kimliği haline gelir.
Kabuk buna ek olarak kendi alt süreçlerinini yeni süreç grubuna koymak için her süreç için ayrı ayrı
setpgid çağrıları yapmalıdır. Olası bir zamanlama sorunu nedeniyle bunun böyle olması gerekir: her alt süreç kendi alt sürecini çalıştırmaya başlamadan önce süreç grubuna konulmak ve dolayısıyla kabuk çalışamaya devam etmeden önce grubundaki alt süreçlerini bağlamak zorundadır. Eğer hem kabuk hem de alt süreci
setpgid çağrısı yaparsa, hangi sürecin bunu önce yaptığına bakılmaksızın işler olması gerektiği gibi yürür.
Eğer iş bir önalan işi olarak başlatılmışsa, yeni süreç grubunun ayrıca tcsetpgrp kullanılarak denetim uçbiriminde önalana konulması gerekir. Tekrar, yarış koşullarından kaçınmak için bu işlem, hem kabuk tarafından hem de kabuğun alt süreçlerinin her biri tarafından yapılmalıdır.
Bundan sonra, her alt süreç kendi sinyal eylemlerini sıfırlamalıdır.
İlklendirme sırasında, kabuk süreci kendini iş denetim sinyallarini yoksaymaya ayarlamalıdır; bkz.
Kabuğun İlklendirilmesi. Sonuç olarak, bir miras olarak her alt süreç oluşturulduğunda bu sinyalleri yoksayacaktır. Bu kesinlikle istenmeyen bir durumdur, bu bakımdan kabuğun her alt süreci çatallandığında bu sinyaller
SIG_DFL'a yani öntanımlı haline getirmelidir.
Kabuklar bu uzlaşımlara uyduğundan, uygulamalar kendini çalıştıran süreçten bu sinyalleri doğru eylemlerle aldıklarını kabul edebilirler. Fakat her uygulamanın durdurma sinyallerinin işlenmesini bozmama sorumluluğu vardır. SUSP karakterinin normal yorumunu iptal eden uygulamalar, kullanıcıya işi durdurmak için başka mekanizmalar sunmalıdır. Kullanıcı bu mekanizmayı çalıştırdığında yazılım sadece kendi sürecinde değil, kendi süreç grubuna da bir
SIGTSTP sinyali göndermelidir. Bkz.
Başka Bir Sürece Sinyal Gönderme.
Son olarak, her süreç normal yolla
exec çağrısı yapmalıdır. Bu ayrıca standart girdi ve çıktı kanallarının yönlendirilmesinde önemlidir. Bunun nasıl yapılacağı
Tanıtıcıların Çoğullanması bölümünde açıklanmıştır.
Örnek kabuk yazılımından, bir uygulamayı çalıştırmakla yükümlü bir işlev aşağıda gösterilmiştir. Kabuk tarafından çatatallandıktan hemen sonra her alt süreç tarafından bu işlev çalıştırılır ve işlev asla dönmez.
void
launch_process (process *p, pid_t pgid,
int infile, int outfile, int errfile,
int foreground)
{
pid_t pid;
if (shell_is_interactive)
{
/* Süreci süreç grubuna koy ve uygunsa uçbirimi
süreç grubuna ver. Olası yarış koşullarının oluşmasını
engellemek için hem kabuk hem de her alt süreç
tarafından bu yapılmalıdır. */
pid = getpid ();
if (pgid == 0) pgid = pid;
setpgid (pid, pgid);
if (foreground)
tcsetpgrp (shell_terminal, pgid);
/* İş denetim sinyallerini öntanımlı eylemlerine ayarlayalım.. */
signal (SIGINT, SIG_DFL);
signal (SIGQUIT, SIG_DFL);
signal (SIGTSTP, SIG_DFL);
signal (SIGTTIN, SIG_DFL);
signal (SIGTTOU, SIG_DFL);
signal (SIGCHLD, SIG_DFL);
}
/* Standart girdi/çıktı kanallarını yeni sürece ayarlayalım. */
if (infile != STDIN_FILENO)
{
dup2 (infile, STDIN_FILENO);
close (infile);
}
if (outfile != STDOUT_FILENO)
{
dup2 (outfile, STDOUT_FILENO);
close (outfile);
}
if (errfile != STDERR_FILENO)
{
dup2 (errfile, STDERR_FILENO);
close (errfile);
}
/* Yeni süreci çalıştıralım ve çıkalım. */
execvp (p->argv[0], p->argv);
perror ("execvp");
exit (1);
}
Kabuk etkileşimli olarak çalışmıyorsa, bu işlev süreç grubu ve sinyallerle ilgili olarak hiçbir şey yapmaz. İş denetimi yapmayan bir kabuğun kendi alt süreçlerini kendi süreç grubunda tuttuğunu hatırlayın.
Aşağıda, bir işi tam anlamıyla çalıştıran bir işleve yer verilmiştir. Alt süreç oluşturulduktan sonra, bu işlev yeni oluşturulan işi önalana ya da artalana koyacak bazı işlevleri çağırır; bunlar
Önalan ve Artalan bölümünde açıklanmıştır.
void
launch_job (job *j, int foreground)
{
process *p;
pid_t pid;
int mypipe[2], infile, outfile;
infile = j->stdin;
for (p = j->first_process; p; p = p->next)
{
/* Set up pipes, if necessary. */
if (p->next)
{
if (pipe (mypipe) < 0)
{
perror ("pipe");
exit (1);
}
outfile = mypipe[1];
}
else
outfile = j->stdout;
/* Alt süreci çatallayalım. */
pid = fork ();
if (pid == 0)
/* This is the child process. */
launch_process (p, j->pgid, infile,
outfile, j->stderr, foreground);
else if (pid < 0)
{
/* Çatallama başarısız. */
perror ("fork");
exit (1);
}
else
{
/* Bu, ata süreç. */
p->pid = pid;
if (shell_is_interactive)
{
if (!j->pgid)
j->pgid = pid;
setpgid (pid, j->pgid);
}
}
/* Boruları temizleyelim. */
if (infile != j->stdin)
close (infile);
if (outfile != j->stdout)
close (outfile);
infile = mypipe[0];
}
format_job_info (j, "işe başladı");
if (!shell_is_interactive)
wait_for_job (j);
else if (foreground)
put_job_in_foreground (j, 0);
else
put_job_in_background (j, 0);
}