Wednesday, October 24, 2012

പ്രോഗ്രാം, പ്രോസസ്സ് - 7

പ്രോസസ്സുകളെക്കുറിച്ചുള്ള വിവരങ്ങള്‍ രണ്ട് വിഭാഗങ്ങളിലായി ആണ് സൂക്ഷിക്കപ്പെട്ടിരിക്കുന്നത്. പ്രോസസ്സ് ടേബിളും യു-ഏരിയയും. പ്രോസസ്സിനെക്കുറിച്ച് കെര്‍ണലിന് ആവശ്യമുള്ള വിവരങ്ങള്‍ പ്രോസസ്സ് ടേബിളില്‍ സൂക്ഷിച്ചിരിക്കും. പ്രോസസ്സിന് തന്നെ ആവശ്യമുള്ള വിവരങ്ങള്‍ യു-ഏരിയയിലും സൂക്ഷിച്ചിരിക്കും.

പ്രോസസ്സ് ടേബിള്‍ എന്‍ട്രി
കെര്‍ണല്‍ സൂക്ഷിക്കുന്ന പ്രോസസ്സുകളുടെ പട്ടികയാണ് പ്രോസസ്സ് ടേബിള്‍. കെര്‍ണല്‍ എങ്ങനെയാണ് പ്രോസസ്സുകളെ കൈകാര്യം ചെയ്യുന്നത് എന്ന് മനസ്സിലാക്കാന്‍ പ്രോസസ്സ് ടേബിളിനെക്കുറിച്ചൂള്ള വിവരങ്ങള്‍ സഹായകമായിരിക്കും.

പ്രോസസ്സ് ടേബിള്‍ ഒരു സര്‍ക്കുലാര്‍ ഡബ്ലി ലിങ്ക്ഡ് ലിസ്റ്റ് ആണ്. (Circular Doubly Linked List). ഇതില്‍ ഏത് പ്രോസസ്സിന്റെ എന്‍ട്രിയില്‍ നിന്ന് ആരംഭിച്ചാലും മുന്നിലേക്കോ പിന്നിലേക്കോ പോയി എല്ലാ പ്രോസസ്സുകളുടെയും  എന്‍ട്രികളിലൂടെ പോയി വരാന്‍ സാധിക്കും. ഒരു പ്രോസസ്സിന്റെ പ്രോസസ്സ് ടേബിള്‍ എന്‍ട്രിയില്‍ ഉള്ള വിവരങ്ങളില്‍ ചിലത് താഴെക്കൊടുക്കുന്നു.
1.പ്രോസസ്സിന്റെ അവസ്ഥ. യൂണിക്സിലെ വിവിധ പ്രോസസ്സ് അവസ്ഥകള്‍ വിശദമാക്കുന്ന ചിത്രം താഴെക്കൊടുത്തിരിക്കുന്നു.
2. പ്രോസസ്സ് ഐഡി
3. വിവിധ യൂസര്‍ ഐഡികള്‍ - ഇവ ഉപയോഗിച്ചാണ് ഒരു പ്രോസസ്സിനുള്ള അനുമതികള്‍ തീരുമാനിക്കപ്പെടുന്നത്.
4. പ്രോസസ്സിലും ഷെയേര്‍ഡ് ലൈബ്രറികളിലുമായി ഉള്ള ടെക്സ്റ്റ് സെഗ്‌‌മെന്റുകളിലേക്കുള്ള പോയിന്ററുകള്‍.
5. മെമ്മറി മാനേജ്‌‌മെന്റ് ആവശ്യങ്ങള്‍ക്കായി പേജ് ടേബിളിലേക്കുള്ള പോയിന്ററുകള്‍.
6. ഷെഡ്യൂളിങ്ങിന് ആവശ്യമായ വിവരങ്ങള്‍. ലിനക്സ് സിസ്റ്റങ്ങളില്‍ പ്രോസസ്സുകള്‍ക്ക് 'നൈസ് വാല്യു' എന്നറിയപ്പെടുന്ന മൂല്യങ്ങള്‍ നല്‍കിയിരിക്കും. പ്രോസസ്സ് ഷെഡ്യൂളിങ്ങിന്റെ സമയത്ത് ഏതൊക്കെ പ്രോസസ്സുകള്‍ക്ക് പ്രാധാന്യം നല്‍കണം എന്ന് തീരുമാനിക്കപ്പെടുന്നത് ഈ മൂല്യത്തിന്റെ അടിസ്ഥാനത്തിലാണ്.
7. വിവിധ ടൈമറുകള്‍. ഓരോ പ്രോസസ്സിനും പ്രവര്‍ത്തിക്കാന്‍ സി പി യു വില്‍ സമയ പരിധികള്‍ തീരുമാനിക്കപ്പെട്ടിരിക്കും. ഈ പരിധികള്‍ പാലിക്കാനും പ്രോസസ്സ് എത്ര സമയം ഏതൊക്കെ മോഡില്‍ പ്രവര്‍ത്തിച്ചു എന്നൊക്കെ കണക്കാക്കാനും ഈ ടൈമറുകള്‍ ഉപയോഗിക്കപ്പെടുന്നു.
8. പ്രോസസ്സിന്റെ യു-ഏരിയയിലേക്കുള്ള പോയിന്റര്‍.

യു-ഏരിയ
പ്രോസസ്സിന്റെ യു-ഏരിയയില്‍ ഉള്‍പ്പെടുത്തിയിരിക്കുന്ന കാര്യങ്ങള്‍ ചുവടെ ചേര്‍ക്കുന്നു.
1. റിയല്‍ യൂസര്‍ ഐഡി, എഫക്റ്റീവ് യൂസര്‍ ഐഡി.
2. പ്രോഗ്രാമിന്റെ വര്‍ക്കിങ്ങ് ഡയറക്ടറി (ഒരു പ്രോഗ്രാം പ്രവര്‍ത്തിക്കുന്നത് ഒരു സമയത്ത് ഫയല്‍ സിസ്റ്റത്തിലെ ഏതെങ്കിലും  ഒരു ഡയറക്ടറിയില്‍ ആയിരിക്കും. ഇതിന് പ്രോഗ്രാമുമായി നേരിട്ട് ബന്ധമൊന്നുമില്ലെങ്കിലും ആ ഡയറക്ടറിയില്‍ ഉള്ള ഫയലുകള്‍ ഉപയോഗിക്കാന്‍ മുഴുവന്‍ പാത്ത് നല്‍കാതെ ഫയലിന്റെ പേര് മാത്രം ഉപയോഗിച്ചാല്‍ മതിയാകും)
3. യൂസര്‍ മോഡിലും  കെര്‍ണല്‍ മോഡിലുമായി പ്രോഗ്രാം  ചെലവിട്ട സമയം കണക്കാക്കുന്നതിനായുള്ള ടൈമറുകള്‍.
4. പ്രോഗ്രാം സിഗ്നലുകളോട് എങ്ങനെ പ്രതികരിക്കണം എന്നതിനെ സംബന്ധിച്ച വിവരങ്ങള്‍.
5. പ്രോഗ്രാമുമായി ബന്ധപ്പെട്ടിരിക്കുന്ന കണ്ട്രോളിങ്ങ് ടെര്‍മിനലിനെ സംബന്ധിച്ച വിവരങ്ങള്‍.
6. പ്രോഗ്രാം നടത്തിയ സിസ്റ്റം കോളൂകളെ സംബന്ധിച്ച വിവരങ്ങള്‍.
7. യൂസര്‍ ഫയല്‍ ഡിസ്ക്രിപ്റ്റര്‍ ടേബിള്‍ - ഒരു പ്രോഗ്രാം തുറക്കുന്ന ഫയലുകളുടെ ഡിസ്ക്രിപ്റ്ററുകളുടെ പട്ടിക.
8. ഫയല്‍ സിസ്റ്റത്തെയും പ്രോസസ്സ് എന്‍വയോണ്‍മെന്റിനെയും സംബന്ധിച്ച വിവരങ്ങള്‍യ്

യൂസര്‍ ഐഡികള്‍
ഫയലുകള്‍ക്ക് ഉള്ളത് പോലെ തന്നെ പ്രോസസ്സുകള്‍ക്കും യൂസറും ഗ്രൂപ്പും ഒക്കെ ഉണ്ട്. ഇത് കൂടാതെ സെഷനും. പ്രോസസ്സുകള്‍ക്കുള്ള വിവിധ യൂസര്‍/ഗ്രൂപ്പ് ഐഡികള്‍ എന്നിവ ചുവടെ. സിസ്റ്റത്തില്‍ ഉള്ള ഓരോ ഉപയോക്താവിന്റെയും ഗ്രൂപ്പിന്റെയും പേരുകള്‍ ഒരു യൂസര്‍ ഐഡിയും ഗ്രൂപ്പ് ഐഡിയും ആയി ബന്ധപ്പെട്ടിരിക്കുന്നു. എല്ലാ സമയത്തും മുഴുവന്‍ പേരും ഉപയോഗിക്കാനുള്ള വിഷമം പരിഗണിച്ചാണ് ഓരോ പേരുകളുമായി ബന്ധപ്പെട്ട് സംഘ്യകള്‍ നല്‍കിയിരിക്കുന്നത്. ഇതിനെപ്പറ്റിയുള്ള വിവരങ്ങള്‍ അടങ്ങിയിരിക്കുന്നത് /etc/passwd, /etc/group എന്നീ ഫയലുകളില്‍ ആണ് ഉണ്ടായിരിക്കുക.

റിയല്‍ യൂസര്‍ ഐഡി
ഇത് ഒരു പ്രോസസ്സ് തുടങ്ങിവച്ച ഉപയോക്താവിന്റെ ഐഡി ആയിരിക്കും. ഒരു പ്രോസസ്സ് ആരംഭിച്ച ശേഷം സെറ്റ്‌‌യുഐഡി വഴി അതിന്റെ യൂസര്‍ ഐഡി മാറ്റിയേക്കാം. എന്നാലും റിയല്‍ യൂസര്‍ ഐഡി പഴയത് തന്നെ ആയിരിക്കും. ഈ പ്രോസസ്സ് ഉണ്ടാക്കുന്ന ഫയലുകള്‍ക്കോ പ്രോസസ്സിന്റെ അനുമതികള്‍ക്കോ റിയല്‍ യൂസര്‍ ഐഡി ഉപയോഗിക്കാറില്ല. എന്നാല്‍ മറ്റ് പ്രോസസ്സുകള്‍ക്ക് സിഗ്നലുകള്‍ അയക്കുമ്പോള്‍ പരിഗണിക്കുന്നത് റിയല്‍ യൂസര്‍ ഐഡി ആണ്‍. സൂപ്പര്‍യൂസര്‍ അനുമതികളില്ലാത്ത ഒരു പ്രോസസ്സിന് അതിന്റെ റിയല്‍ യൂസര്‍ ഐഡി തന്നെയുള്ള പ്രോസസ്സുകള്‍ക്കേ സിഗ്നലുകള്‍ അയക്കാന്‍ സാധിക്കുകയുള്ളു.

എഫക്റ്റീവ് യൂസര്‍ ഐഡി
ഒരു പ്രോസസ്സ് സൃഷ്ടിക്കപ്പെട്ട ശേഷം സെറ്റ്‌‌യുഐഡി ഉപയോഗിച്ച് ആ പ്രോസസ്സിന്റെ എഫക്റ്റീവ് യൂസര്‍ ഐഡി റിയല്‍ യൂസര്‍ ഐഡിയില്‍ നിന്ന് മാറ്റാന്‍ സാധിക്കും. ഒരു പ്രോസസ്സ് ഫയലുകള്‍ നിര്‍മ്മിക്കുകയോ ഏതെങ്കിലും  ഒരു റിസോഴ്സ് ഉപയോഗിക്കാന്‍ ശ്രമിക്കുകയോ ചെയ്യുമ്പോള്‍ ആ പ്രോസസ്സിന്റെ എഫക്റ്റീവ് യൂസര്‍ ഐഡി ആണ് പരിഗണിക്കപ്പെടുക.

ഗ്രൂപ്പ് ഐഡികളും മേല്‍പ്പറഞ്ഞത് പോലെ തന്നെ. യൂസറിന് പകരം യൂസര്‍ ഉള്‍പ്പെടുന്ന ഗ്രൂപ്പിന്റെ ഐഡി ആയിരിക്കും പരിഗണിക്കപ്പെടുക. താഴെക്കൊടുത്തിരിക്കുന്ന പ്രോഗ്രാം പ്രോസസ്സിന്റെ യൂസര്‍ ഐഡി, ഗ്രൂപ്പ് ഐഡി തുടങ്ങിയവ കാണിച്ചു തരും. sudo ഉപയോഗിക്കാതെ റണ്‍ ചെയ്താല്‍ setuid പ്രവര്‍ത്തിക്കില്ല. 65534 nobody എന്ന യൂസറിന്റെ ഐഡി ആണ്. ലഭ്യമായ യൂസര്‍ ഐഡികള്‍ക്കായി /etc/passwd ഫയല്‍ തുറന്ന് നോക്കുക. സെറ്റ്‌‌യുഐഡി റിയല്‍ യൂസര്‍ ഐഡി മാറ്റുന്നില്ല എന്ന് ഈ പ്രോഗ്രാം  പ്രവര്‍ത്തിക്കുമ്പോള്‍ മനസ്സിലാക്കാം.

 #include <stdio.h>  
 #include <unistd.h>  
   
 int main(void)   
 {  
     printf("The real user of this process has ID %d\n",getuid());  
     printf("The effective user of this process has ID %d\n",geteuid());  
     printf("The real user group ID for this process is %d\n",getgid());  
     printf("The effective user group for this process is %d\n",getegid());  
   
     setuid(65534);  
   
     printf("The real user of this process has ID %d\n",getuid());  
     printf("The effective user of this process has ID %d\n",geteuid());  
     printf("The real user group ID for this process is %d\n",getgid());  
     printf("The effective user group for this process is %d\n",getegid());  
   
     return 0;  
 }  

പ്രോസസ്സ് സെഷന്‍
എല്ലാ പ്രോസസ്സുകളും  ഒരു പ്രോസസ്സ് സെഷന്റെ ഭാഗമായിരിക്കും. മിക്കവാറും സിസ്റ്റം പ്രവര്‍ത്തിച്ച് തുടങ്ങുമ്പോള്‍ ഉള്ള ലോഗിന്‍ പ്രോസസ്സ് ആയിരിക്കും ഒരു സെഷന്‍ ആരംഭിക്കുക. അതിന്റെ ചൈല്‍ഡ് പ്രോസസ്സുകള്‍ ഒക്കെ ആ സെഷനില്‍ ആയിരിക്കും. ഒരു സെഷനിലെ ആദ്യത്തെ പ്രോസസ്സ് ആണ് സെഷന്‍ ലീഡര്‍ എന്നറിയപ്പെടുന്നത്. സെഷന്‍ ഐഡി സെഷന്‍ ലീഡറിന്റെ പിഐഡി ആയിരിക്കും. എല്ലാ പ്രോസസ്സ് സെഷനുകള്‍ക്കും ഒരു കണ്ട്രോളിങ്ങ് റ്റിറ്റിവൈ ഉണ്ടായിരിക്കും. ഇതിനെ ടെര്‍മിനല്‍ എന്ന് വിളിക്കാം. ആദ്യകാലത്ത് ഒരു പ്രധാന കമ്പ്യൂട്ടറുമായി ഘടിപ്പിക്കപ്പെട്ടിരുന്ന ഉപകരണങ്ങളായിരുന്നു ടെര്‍മിനലുകള്‍. ഒന്നിലധികം ടെര്‍മിനലുകള്‍ ഉപയോഗിച്ച് ഒന്നിലധികം ഉപയോക്താക്കള്‍ ഒരേ കമ്പ്യൂട്ടര്‍ തന്നെ പ്രവര്‍ത്തിപ്പിച്ചിരുന്നു. ps -e കമാന്റ് ഉപയോഗിച്ച് സിസ്റ്റത്തിലെ പ്രോസസ്സുകളും അവയുടെ TTY ഉം  കാണാന്‍ സാധിക്കും. ചില പ്രോസസ്സുകള്‍ക്ക് കണ്ട്രോളിങ്ങ് ടെര്‍മിനല്‍ കാണില്ല. അവയെക്കുറിച്ച് പിന്നീട് പറയാം. താഴെക്കൊടുത്തിരിക്കുന്ന പ്രോഗ്രാം അതിന്റെ സെഷന്‍ ഐഡി കാട്ടിത്തരും. അതിന് ശേഷം ps കമാന്റ് ഉപയോഗിച്ചാല്‍ ആ പ്രോഗ്രാമിനെ പ്രവര്‍ത്തിപ്പിച്ച ഷെല്ലിന്റെ പിഐഡി തന്നെയാണ് സെഷന്‍ ഐഡി എന്ന് കാണാം. അതിന്റെ കാരണം ഊഹിക്കാമല്ലോ..

 #include <stdio.h>  
 #include <stdlib.h>  
 #include <unistd.h>  
   
 int main(void)  
 {  
     printf("My session id is: %d\n", getsid(getpid()));  
   
     return 0;  
 }  

ഇന്റര്‍ പ്രോസസ്സ് കമ്യൂണിക്കേഷന്‍, സിഗ്നലുകള്‍ എന്നിവയെപ്പറ്റി അടുത്ത പോസ്റ്റ്..

Sunday, October 14, 2012

പ്രോഗ്രാം, പ്രോസസ്സ് - 6

യൂണിക്സ്/ലിനക്സ് സിസ്റ്റങ്ങളില്‍ ബൂട്ടിങ്ങിന് ശേഷം കെര്‍ണല്‍ തന്നെ നിര്‍മിക്കുന്ന പ്രോസസ്സാണ് ഇനിറ്റ്. ഇനിറ്റ് വരെ സിസ്റ്റം കെര്‍ണല്‍ മോഡിലായിരിക്കും. ഇനിറ്റ് പ്രവര്‍ത്തനമാരംഭിക്കുന്നതോടെ സിസ്റ്റം യൂസര്‍മോഡിലേക്ക് മാറുന്നു. ഇനിറ്റിന്റെ വകഭേദങ്ങളും  പ്രവര്‍ത്തനവും ഒരു പോസ്റ്റി വിശദീകരിക്കാം. ഇനിറ്റിനു ശേഷമുള്ള  എല്ലാ പ്രോസസ്സുകളും ഫോര്‍ക്ക് സിസ്റ്റം കോള്‍ ഉപയോഗിച്ച് സൃഷ്ടിക്കപ്പെടുന്നവയാണ്. ഇനിറ്റ് പ്രോസസ്സ് ഷെല്ലുകളോ ഗ്രാഫിക്കല്‍ യൂസര്‍ ഇന്റര്‍ഫേസുകളോ എക്സിക്യൂട്ട് ചെയ്യുന്നു. അപ്പോള്‍ ഉപഭോക്താവിന് കമ്പ്യൂട്ടര്‍ പ്രവര്‍ത്തിപ്പിക്കാനുള്ള ഉപാധികള്‍ ലഭ്യമാകും. ഉപഭോക്താവ് കമാന്റുകളോ മൗസോ ഉപയോഗിച്ച് ഒരു പുതിയ പ്രോഗ്രാം തുറക്കുമ്പോള്‍ സംഭവിക്കുന്ന കാര്യങ്ങള്‍ എന്തൊക്കഎയാണെന്ന് നോക്കാം. ഷെല്ലോ ഗ്രാഫിക്കല്‍ ഇന്റര്‍ഫേസോ ആദ്യം ഫോര്‍ക്ക് സിസ്റ്റം കോള്‍ ഉപയോഗിച്ച് അതിന്റെ തന്നെ ഒരു കോപ്പി നിര്‍മ്മിക്കുന്നു. ഈ കോപ്പി നിര്‍മ്മിക്കപ്പെടുന്ന വഴി ഇങ്ങനെയാണ്.
1. ഫോര്‍ക്ക് സിസ്റ്റം കോള്‍ ഉപയോഗിക്കപ്പെടുമ്പോള്‍ സിസ്റ്റം യൂസര്‍ മോഡില്‍ നിന്ന് കെര്‍ണല്‍ മോഡിലേക്ക് മാറുന്നു.
2. കെര്‍ണലിന്റെ സിസ്റ്റം കോള്‍ ഇന്റര്‍ഫേസ് ഫോര്‍ക്ക് സിസ്റ്റം കോളിലെ നിര്‍ദ്ദേശങ്ങള്‍ പ്രവര്‍ത്തിപ്പിക്കാന്‍ ആരംഭിക്കുന്നു.
3. സിസ്റ്റത്തില്‍  ഓരോ ഉപയോക്താവിനും ഒരു സമയത്ത് പ്രവര്‍ത്തിപ്പിക്കാനാകുന്ന പ്രോസസ്സുകളുടെ എണ്ണം തീരുമാനിക്കപ്പെട്ടിട്ടുണ്ടെങ്കില്‍ ആ പരിധി പാലിക്കപ്പെട്ടിട്ടുണ്ടോ എന്ന് പരിശോധിക്കപ്പെടുന്നു.
4. ഒരു പ്രോസസ്സ് ആരംഭിക്കാനാവശ്യമായ വിഭവങ്ങള്‍ സിസ്റ്റത്തില്‍ ബാക്കിയുണ്ടോ എന്ന് പരിശോധിക്കപ്പെടുന്നു (മെമ്മറി ഇതില്‍ പ്രധാനമാണ്)
5. പുതിയ ഒരു എന്‍ട്രി പ്രോസസ്സ് ടേബിളില്‍ സൃഷ്ടിക്കപ്പെടുന്നു. യു-ഏരിയക്കായി മെമ്മറി തയ്യാറാക്കുന്നു.
6. ഫോര്‍ക്ക് ഉപയോഗിച്ച പ്രോസസ്സിന്റെ ടെക്സ്റ്റ്, ഡാറ്റ, സ്റ്റാക്ക്, ഹീപ്പ് എന്നിവയുടെ കോപ്പി തയ്യാറാക്കപ്പെടുന്നു. ഇവിടെ ശരിക്കും കോപ്പി ഉണ്ടാക്കുകയില്ല. ടെക്സ്റ്റ് സെഗ്മന്റ് ആദ്യത്തെ പ്രോസസ്സിന്റെ തന്നെ ഉപയോഗിക്കപ്പെടും. ശരിക്കും കോപ്പികള്‍ ഉണ്ട് എന്ന് തോന്നിപ്പിക്കുകയും  അവിടെ പഴയ സെഗ്മെന്റുകളുടെ വിലാസം രേഖപ്പെടുത്തുകയും ആണ് ചെയ്യുന്നത്. സ്റ്റാക്ക്, ഡാറ്റ, ഹീപ്പ് സെഗ്മന്റുകള്‍ ടെക്സ്റ്റ് സെഗ്മന്റില്‍ നിന്നും വ്യത്യസ്തമായി മാറ്റങ്ങള്‍ വരുത്താന്‍ അനുവദിക്കപ്പെട്ടവയായതിനാല്‍ അവിടെ കോപ്പി ഓണ് റൈറ്റ് എന്ന സങ്കേതം ഉപയോഗിക്കും. അതായത് അവയില്‍ മാറ്റങ്ങള്‍ വരുത്തപ്പെടുന്നത് വരെ ആദ്യമുണ്ടായിരുന്നവ തന്നെ ഉപയോഗിക്കുകയും മാറ്റങ്ങള്‍ വരുത്തപ്പെട്ട ശേഷം മാത്രം പുതിയ പതിപ്പ് സൃഷ്ടിക്കുകയും ചെയ്യുന്നു.

ഇപ്പോള്‍ സിസ്റ്റത്തില്‍ ഒരേ പ്രോസസ്സിന്റെ രണ്ട് കോപ്പി ഉണ്ടായി. ഫലത്തില്‍ ഫോര്‍ക്ക് സിസ്റ്റം കോള്‍ ഉപയോഗിച്ച രണ്ട് പ്രോസസ്സുകള്‍. ഫോര്‍ക്ക് സിസ്റ്റം കോളിന് രണ്ട് വ്യത്യസ്ത റിട്ടേണ്‍ മൂല്യങ്ങള്‍ ഉണ്ട്. സാധാരണ ഫങ്ങ്ഷനുകള്‍ അവയെ വിളിച്ച ഒരു പ്രോസസ്സിലേക്ക് മാത്രമേ മൂല്യങ്ങള്‍ തിരികെ നല്‍കുകയുള്ളു. എന്നാല്‍ ഫോര്‍ക്ക് പേരന്റ് പ്രോസസ്സിലേക്കും ചൈല്‍ഡ് പ്രോസസ്സിലേക്കും ഓരോ മൂല്യങ്ങള്‍ മടക്കി നല്‍കും. വിജയകരമായ ഫോര്‍ക്ക് പേരന്റ് പ്രോസസ്സിലേക്ക് ചൈല്‍ഡ് പ്രോസസ്സിന്റെ പിഐഡിയും ചൈല്‍ഡ് പ്രോസസ്സിലേക്ക് പൂജ്യവും മടക്കി നല്‍കുന്നു. ഇത് ഉപയോഗിച്ചാണ് ഇപ്പോള്‍ പ്രവര്‍ത്തിക്കുന്നത് പേരന്റാണോ ചൈല്‍ഡ് ആണോ എന്ന് മനസ്സിലാക്കാന്‍ സാധിക്കുന്നത്. സി പ്രോഗ്രാമിങ്ങ് വശമുള്ളവര്‍ക്ക് ഈ ഉദാഹരണം പരീക്ഷിക്കാവുന്നതാണ്.

 #include <stdio.h>  
 #include <stdlib.h>  
 #include <unistd.h>  
   
 int main(void)  
 {  
     int pid;  
   
     pid = fork();  
     if (pid == -1) {  
         printf("fork failed..\n");  
         exit(-1);  
     }  
   
     if (pid == 0) {  
         printf("I am the child process. My PID is %d\n", getpid());  
         exit(0);  
     } else {  
         printf("I am the parent process PID is %d. Child PID is %d\n",getpid(), pid);  
     }  
   
     return 0;  
 }  

ഇതിനെ fork.c എന്ന ഫയലില്‍ സേവ് ചെയ്യുക. അതിനു ശേഷം ടെര്‍മിനലില്‍
gcc fork.c -o fork എന്ന് ടൈപ്പ് ചെയ്ത് എന്റര്‍ അമര്‍ത്തുക. പ്രവര്‍ത്തിപ്പിക്കാന്‍ ./fork എന്ന് ടൈപ്പ് ചെയ്ത് എന്റര്‍ അമര്‍ത്തുക. താഴെക്കാണുന്നതിന് സമാനമായ ഔട്ട്പുട്ട് ലഭിക്കും,
I am the parent process PID is 3691. Child PID is 3692
I am the child process. My PID is 3692
if സ്റ്റേറ്റ്മെന്റ് ഉപയോഗിക്കുമ്പോള്‍ സാധാരണയായി നിര്‍ദ്ദേശത്തിലെ ഒരു ഭാഗം മാത്രം പ്രവര്‍ത്തിക്കുന്നിടത്ത് ഇവിടെ രണ്ട് ഭാഗങ്ങളും പ്രവര്‍ത്തിക്കുന്നതായി കാണാം. ശരിക്കും  ഇത് രണ്ട് വ്യത്യസ്ത പ്രോസസ്സുകളില്‍ നിന്നാണ് വരുന്നത്. ആദ്യം ചൈല്‍ഡ്‌ പ്രവര്‍ത്തിക്കുമോ പേരന്റ് പ്രവര്‍ത്തിക്കുമോ എന്ന് പറയാന്‍ സാധിക്കുകയില്ല. സിസ്റ്റം കോള്‍ പൂര്‍ത്തിയായ ശേഷം പ്രോസസ്സ് വീണ്ടും യൂസര്‍ മോഡിലേക്ക് തന്നെ മടങ്ങി വരുന്നു.

ഒരു പുതിയ പ്രോസസ്സ് ഇവിടെ സൃഷ്ടിക്കപ്പെട്ടെങ്കിലും അത് ആദ്യത്തെ പ്രോസസ്സിന്റെ തന്നെ പകര്‍പ്പാണെന്ന് മനസ്സിലാക്കിയിരിക്കുമല്ലോ. എന്നാല്‍ നമുക്കാവശ്യം ഒരു പുതിയ പ്രോഗ്രാമിനെ പ്രവര്‍ത്തിപ്പിക്കലാണ്. ഇതിനായി ഉപയോഗിക്കുന്ന സിസ്റ്റം കോള്‍ ആണ് എക്സക്ക് (exec). ഈ സിസ്റ്റം കോള്‍ ചെയ്യുന്നത് അതിനെ ഉപയോഗിച്ച പ്രോസസ്സിന്റെ സെഗ്മന്റുകള്‍ മാറ്റി അവിടെ ഒരു പുതിയ പ്രോഗ്രാമില്‍ നിന്നുള്ള സെഗ്‌‌മന്റുകള്‍ ചേര്‍ക്കുകയാണ്. ഇതുവഴി ഒറിജിനല്‍ പ്രോസസ്സ് ഇല്ലാതാകുകയും പകരം പുതിയ പ്രോഗ്രാം പ്രോസസ്സായി അവിടെ വരികയും ചെയ്യുന്നു. ഇതിന്റെ പ്രവര്‍ത്തനം താഴെപ്പറയുന്നത് പോലെയാണ്.
1. എക്സെക്ക് സിസ്റ്റം കോള്‍ ഉപയോഗിക്കുമ്പോള്‍ പ്രതിപാദിക്കപ്പെട്ട എക്സിക്യൂട്ടബിള്‍ ഫയല്‍ ഡിസ്കില്‍ കണ്ടെത്തുക. (ഫയല്‍ അനുബന്ധമായ ക്രിയകളുടെ വിശദാംശങ്ങള്‍ക്കായി ഫയല്‍ സിസ്റ്റങ്ങളെക്കുറിച്ചുള്ള പോസ്റ്റുകള്‍ കാണുക)
2. ആ ഫയല്‍ സാധുവായ ഒരു പ്രോഗ്രാം ആണോ എന്ന് പരിശോധിക്കുക (elf ഫയലുകളെപ്പറ്റി നേരത്തെ പ്രദിപാദിച്ചിരുന്നു)
3. സാധുവായ ഒരു പ്രോഗ്രാം ആണെങ്കില്‍ അതില്‍ നിന്ന് വിവിധ സെഗ്മന്റുകളെക്കുറിച്ചുള്ള വിവരങ്ങള്‍ വായിക്കുകയും അവയെ മെമ്മറിയിലേക്ക് കൊണ്ടുവരികയും ചെയ്യുക.
4. നിലവിലെ സെഗ്മന്റുകളെ നശിപ്പിക്കുകയും അവക്ക് പകരം പുതിയ സെഗ്മെന്റുകള്‍ അവിടെ ചേര്‍ക്കുകയും ചെയ്യുക.
5. പുതിയ പ്രോഗ്രാമിന്റെ തുടക്കം മുതല്‍ പ്രവര്‍ത്തനം ആരംഭിക്കുക.

ഇവിടെ ശ്രദ്ധിക്കേണ്ട ഒരു പ്രധാന കാര്യം വിജയകരമായ ഒരു എക്സെക്ക് സിസ്റ്റം കോള്‍ ഫോര്‍ക്ക് സിസ്റ്റം കോള്‍ ചെയ്തതുപോലെ മൂല്യങ്ങളൊന്നും മടക്കി നല്‍കുന്നില്ല. ഒരു ഫങ്ങ്ഷന്‍ റിട്ടേണ്‍ ചെയ്യുന്നത് അതിനെ വിളിച്ച പ്രോസസ്സിലേക്കാണ്. ഇവിടെ എക്സെക്കിനെ വിളിച്ച പ്രോസസ്സ് ബാക്കിയില്ല. അവിടെ പുതിയ പ്രോഗ്രാം പ്രവര്‍ത്തനം തുടങ്ങിയിരിക്കുന്നു. അതിനാല്‍ തന്നെ വിജയകരമായ എക്സെക്കില്‍ നിന്ന് റിട്ടേണ്‍ ഇല്ല. (ഇത് മിക്കവാറും ഇന്റര്‍വ്യൂകളില്‍ ഒക്കെ ചോദിക്കാറുള്ള ഒരു ചോദ്യമാണ്) മുകളിലെ പ്രോഗ്രാമിനെ അല്‍പം പരിഷ്കരിച്ച് ls എന്ന പ്രോഗ്രാമിനെ എങ്ങനെ പ്രവര്‍ത്തിപ്പിക്കം എന്ന് നോക്കാം. ഷെല്ലുകള്‍ എങ്ങനെ പ്രവര്‍ത്തിക്കുന്നു എന്ന് മനസ്സിലാക്കാന്‍ ഇത് ഉപകരിക്കും. സി പ്രോഗ്രാമിങ്ങില്‍ എക്സെക്ക് നേരിട്ട് ഉപയോഗിക്കാന്‍ വിഷമമാണ്. അതിനാല്‍ സി ലൈബ്രറി നല്‍കുന്ന execl, execlp, execle, execv, execvp, execvpe എന്ന വകഭേദങ്ങളില്‍ ഒന്ന് ഉപയോഗിക്കാം. ഇവയൊക്കെ ഉള്ളില്‍ എക്സെക്ക് തന്നെയാണ് ഉപയോഗിക്കുന്നത്.

 #include <stdio.h>  
 #include <stdlib.h>  
 #include <unistd.h>  
   
 int main(void)  
 {  
     int pid, ret;  
   
     pid = fork();  
     if (pid == -1) {  
         printf("fork failed..\n");  
         exit(-1);  
     }  
   
     if (pid == 0) {    
         printf("I am the child process. Now executing ls\n");  
         ret = execl("/bin/ls", "ls", "/", NULL);  
         if (ret == -1) {   
             printf("exec failed\n");  
         }   
     } else {  
         printf("I am the parent process PID is %d. Child PID is %d\n",getpid(), pid);  
     }  
   
     return 0;  
 }  

ആദ്യത്തെ പ്രോഗ്രാമിനെ മേലെ കാണുന്നതുപോലെ മാറ്റുക. ബാക്കി നിര്‍ദ്ദേശങ്ങള്‍ പഴയത് തന്നെ. ഇവിടെ താരതമ്യേന എളുപ്പമുള്ള execl എന്ന രൂപമാണ് ഉപയോഗിച്ചിരിക്കുന്നത്. അതിലെ ആദ്യത്തെ പരാമീറ്റര്‍ എക്സിക്യൂട്ട് ചെയ്യണ്ട പ്രോഗ്രാമിന്റെ പാത്ത് ആണ്. ബാക്കിയുള്ളവ ആ പ്രോഗ്രാമിന് ഉള്ള ആര്‍ഗ്യുമെന്റുകള്‍. യൂണിക്സ് സിസ്റ്റങ്ങളില്‍ ഒരു പ്രോഗ്രാമിന്റെ ആദ്യത്തെ ആര്‍ഗ്യുമെന്റായി ആ പ്രോഗ്രാമിന്റെ തന്നെ പേര് നല്‍കുന്നതാണ് കീഴ്‌‌വഴക്കം. വിവിധ പേരുകളില്‍ ഉപയോഗിക്കുമ്പോള്‍ വിവിധ തരത്തില്‍ പ്രവര്‍ത്തിക്കുന്ന പ്രോഗ്രാമുകള്‍ തയ്യാറാക്കാന്‍ ഇതുവഴി സാധിക്കും. അതാണ് രണ്ടാമത്തെ ആര്‍ഗ്യുമെന്റായി ls എന്ന് തന്നെ കൊടുത്തിരിക്കുന്നത്. മൂന്നാമതെ ആര്‍ഗ്യുമെന്റ്‌‌ "/" ആണ്. / എന്ന പാത്തിലെ ഫയലുകളുടെ പട്ടിക നല്‍കാന്‍ ls പ്രോഗ്രാമിനോട് ആവശ്യപ്പെടുന്നതിനാണ് ഇത്. അവസാനമായി NULL എന്നത് സെന്റിനല്‍ ആര്‍ഗ്യുമെന്റ് അഥവാ സെന്റിനല്‍ എന്നറിയപ്പെടുന്നു. വ്യത്യസ്ത എണ്ണത്തിലുള്ള പരാമീറ്ററുകള്‍ സ്വീകരിക്കുന്ന ഫങ്ങ്ഷനുകളോട് ഇതാണ് അവസാനത്തെ പരാമീറ്റര്‍ എന്ന് സൂചിപ്പിക്കാന്‍ ഇവ ഉപയോഗിക്കുന്നു. (NULL എന്നത് സെന്റിനല്‍ അല്ല. അതിന് മറ്റ് ഉപയോഗങ്ങള്‍ ഉണ്ട്. ഇനി പരാമീറ്ററുകള്‍ ഇല്ല എന്നത് സൂചിപ്പിക്കാനായി ഉപയോഗിക്കുന്നവയെ ആണ് സെന്റിനല്‍ എന്ന് വിളിക്കുന്നത്. എക്സെക്ക് പ്രതീക്ഷിക്കുന്ന സെന്റിനല്‍ NULL ആണ്). ls കമാന്റ് -l എന്ന ആര്‍ഗ്യുമെന്റ് സ്വീകരിക്കും. ls -l എന്നുപയോഗിക്കുമ്പോള്‍ ലഭിക്കുന്ന രീതിയിലുള്ള ഔട്ട്പുട്ട് ലഭിക്കാന്‍  ret = execl("/bin/ls", "ls", "-l", "/", NULL); എന്നാക്കി ആ വരിയെ മാറ്റിയാല്‍ മതി.

ഒരു പ്രോസസ്സിലെ തന്നെ സ്വതന്ത്രമായ ഒരു ഭാഗം മറ്റൊരു പ്രോസസ്സ് പോലെ ഷെഡ്യൂള്‍ ചെയ്യാന്‍ സാധിക്കുന്ന തരത്തില്‍ പ്രവര്‍ത്തിപ്പിക്കുക എന്നതാണ് ത്രെഡുകള്‍ വഴി ചെയ്യുന്നത്. ഒരു പ്രോസസ്സില്‍ ചിലപ്പോള്‍ ത്രെഡുകള്‍ ഉണ്ടാകാം. ഈ ത്രെഡുകള്‍ക്ക് വ്യത്യസ്ത സ്റ്റാക്ക് സെഗ്‌‌മന്റുകള്‍ ഉണ്ടായിരിക്കുമെങ്കിലും ടെക്സ്റ്റ്, ഡാറ്റ തുടങ്ങിയ സെഗ്മന്റുകള്‍ ഒക്കെ ഒന്നുതന്നെ ആയിരിക്കും. ലിനക്സില്‍ ഒരു ത്രെഡ് സൃഷ്ടിക്കാന്‍ ഉപയോഗിക്കുന്ന സിസ്റ്റം കോള്‍ ക്ലോണ്‍ (clone) ആണ്. ഇത് ഒരു പ്രോഗ്രാമില്‍ നേരിട്ട് ഉപയോഗിക്കുന്നതിന് പകരം  പി-ത്രെഡ്‌ പോലെ ത്രെഡുകള്‍ കൈകാര്യം ചെയ്യാനുള്ള ലൈബ്രറികള്‍ എന്തെങ്കിലും  ഉപയോഗിക്കുന്ന രീതിയാണ് ശുപാര്‍ശ ചെയ്യപ്പെട്ടിരിക്കുന്നത്.

പ്രോസസ്സ് ടേബിള്‍, യു-ഏരിയ എന്നിവയെക്കുറിച്ച് വിശദമായി അടുത്ത പോസ്റ്റില്‍.

Saturday, October 13, 2012

പ്രോഗ്രാം, പ്രോസസ്സ് - 5

ഒരു ഓപ്പറേറ്റിങ്ങ് സിസ്റ്റം  നല്‍കുന്ന സേവനങ്ങള്‍ ഉപയോഗിക്കുന്നത് സിസ്റ്റം കോളുകള്‍ വഴിയാണ്. സാധാരണ പ്രോഗ്രാമിങ്ങ് ഭാഷകളൊക്കെ സിസ്റ്റം കോളുകള്‍ ഉപയോഗിക്കാനുള്ള ഫങ്‌‌ഷനുകള്‍ നല്‍കാറുണ്ട്. ജാവ പോലെയുള്ള വിര്‍ച്ച്വല്‍ മെഷീനുകള്‍ ഉപയോഗിക്കുന്ന അല്ലെങ്കില്‍ ഒരു ഇന്റര്‍പ്രിറ്റര്‍ കൈകാര്യം  ചെയ്യുന്ന  പ്രോഗ്രാമിങ്ങ് ഭാഷകളാണെങ്കില്‍ ഈ സിസ്റ്റം കോളുകള്‍ അവയുടെ ഇന്റര്‍പ്രിറ്റര്‍ തന്നെ കൈകാര്യം ചെയ്യും. പ്രോഗ്രാമര്‍ക്ക് അവയെക്കുറിച്ചറിയണ്ട കാര്യമില്ല. സി/സി++ ഭാഷകളില്‍ ഈ സിസ്റ്റം കോളുകള്‍ നേരിട്ട് ഉപയോഗിക്കാന്‍ സാധിക്കും. യൂണിക്സ്/ലിനക്സ് സിസ്റ്റങ്ങളില്‍ ഒരു പുതിയ പ്രോസസ് ഉണ്ടാക്കാനുള്ള സിസ്റ്റം കോള്‍ ഫോര്‍ക്ക്  (fork) ആണ്. നിലവിലുള്ള ഒരു പ്രോസസ് ഫോര്‍ക്ക് സിസ്റ്റം കോള്‍ ഉപയോഗിക്കുമ്പോള്‍  ആ പ്രോസസിന്റെ മറ്റൊരു പതിപ്പ് സൃഷ്ടിക്കപ്പെടുന്നു. ഈ പതിപ്പിനെ ചൈല്‍ഡ് പ്രോസസ്സ് എന്നും ഫോര്‍ക്ക് സിസ്റ്റം കോള്‍ ഉപയോഗിച്ച പ്രോസസിനെ പേരന്റ് പ്രോസസ്സ് എന്നും  വിളിക്കുന്നു. എല്ലാ പ്രോസസുകള്‍ക്കും ഒരു പ്രോസസ്സ് ഐഡി ഉണ്ടായിരിക്കും. പ്രോസസുകളെ കൈകാര്യം ചെയ്യാന്‍ ഈ പ്രോസസ്സ് ഐഡി ഉപയോഗിക്കാം. ഇതിനെ ചുരുക്കു പിഐഡി (PID) എന്ന് വിളിക്കുന്നു. ലിനക്സ് കെര്‍ണല്‍ അതിന്റെ പ്രാധമിക ക്രമീകരണങ്ങള്‍ ഒക്കെ നടത്തിയ ശേഷം ഇനിറ്റ് (init) എന്ന പ്രോസസ്സിന്റെ സൃഷ്ടിക്കുന്നു. ഈ പ്രോസസ് മാത്രമാണ് ഫോര്‍ക്ക് ഉപയോഗിക്കാതെ സൃഷ്ടിക്കപ്പെടുന്ന ഒരേ ഒരെണ്ണം. ഇനിറ്റ് പ്രോസസ്സിന്റെ പിഐഡി 1 ആയിരിക്കും. തുടക്കത്തില്‍ ആവശ്യമായ ബാക്കിയുള്ള പ്രോസസുകളെ ഒക്കെ സൃഷ്ടിക്കുന്നത് ഇനിറ്റ് ആണ്. അപ്പോള്‍ ഇനിറ്റ് ഒഴികെയുള്ള എല്ലാ പ്രോസസ്സുകള്‍ക്കും  ഒരു പേരന്റ് പ്രോസസ് ഉണ്ടാകും. ഈ പേരന്റ് പ്രോസസിനെ മനസ്സിലാക്കാന്‍ പേരന്റ് പ്രോസസ് ഐഡി - പിപിഐഡി (PPID) ഉപയോഗിക്കുന്നു. ഒരു ചൈല്‍ഡ് പ്രോസസ്സിന്റെ പേരന്റ് പ്രോസസ്സ് പ്രവര്‍ത്തനം നിര്‍ത്തിയാല്‍ ആ ചൈല്‍ഡ് പ്രോസസ്സിനെ ഓര്‍ഫണ്‍ പ്രോസസ്സ് എന്ന് വിളിക്കാം. എല്ലാ ഓര്‍ഫണ്‍ പ്രോസസ്സുകളുടെയും  പേരന്റ് പ്രോസസ്സ് ഇനിറ്റ് ആയിരിക്കും. കെര്‍ണല്‍ എല്ലാ പ്രോസസ്സുകളുടെയും ഒരു പട്ടിക സൂക്ഷിക്കും. ഇതിനെ പ്രോസസ്സ് ടേബിള്‍ എന്ന് വിളിക്കുന്നു. ഇത് എല്ലാ പ്രോസസ്സുകള്‍ക്കും പ്രോസസ്സ് ടേബിളില്‍ ഒരു സ്ഥലം അനുവദിച്ചിരിക്കും. ഇതിനെ ആ പ്രോസസ്സിന്റെ പ്രോസസ്സ് ടേബിള്‍ എന്‍ട്രി എന്ന് വിളിക്കാം. കൂടാതെ ഓരോ പ്രോസസ്സിനും യു-ഏരിയ എന്ന പേരില്‍ അതിനെപ്പറ്റിയുള്ള വിവരങ്ങള്‍ സൂക്ഷിച്ചിരിക്കുന്ന ഒരു സ്ഥലം കൂടിയുണ്ട്. ഒരു പ്രോസസ്സിലെ വിവിധ സെഗ്‌‌മന്റുകളെക്കുറിച്ച് നേരത്തേ പറഞ്ഞിരുന്നല്ലോ. കെര്‍ണലിനും  ഈ സെഗ്മെന്റുകള്‍ ഉണ്ടായിരിക്കും. അവയിലാണ് ഈ വിവരങ്ങള്‍ ശേഖരിക്കപ്പെടുക.

യൂസര്‍ സ്പേസ് - കെര്‍ണല്‍ സ്പേസ്
ഓപ്പറേറ്റിങ്ങ് സിസ്റ്റത്തിന്റെ ഹൃദയമായ കെര്‍ണല്‍ ആണ് ഒരു സിസ്റ്റത്തിലെ എല്ലാ പ്രവര്‍ത്തനങ്ങളെയും നിയന്ത്രിക്കുന്നത്. അതില്‍ ഘടിപ്പിച്ചിരിക്കുന്ന ഉപകരണങ്ങളെ പ്രവര്‍ത്തിപ്പിക്കുന്നതും  ഫയലുകളെ കൈകാര്യം ചെയ്യുന്നതും  എല്ലാം  കെര്‍ണല്‍ ആണ്. ഒരു ഫയല്‍ വായിക്കാനോ ഏതെങ്കിലും  ഉപകരണങ്ങളെ ഉപയോഗിക്കാനോ ഒരു പ്രോസസ്സിനും  അവകാശമില്ല. അത് ആവശ്യമായ സന്ദര്‍ഭങ്ങളില്‍ സിസ്റ്റം കോളുകള്‍ വഴി പ്രോസസ്സ് അത് കെര്‍ണലിനോട് ആവശ്യപ്പെടുന്നു. ആ പ്രോസസ്സിന് അതിനുള്ള അനുവാദം നല്‍കാമോ എന്ന് പരിശോധിച്ച ശേഷം കെര്‍ണല്‍ ആവശ്യമായ നടപടികള്‍ എടുക്കുന്നു. കെര്‍ണല്‍ പ്രവര്‍ത്തിക്കുന്ന അവസ്ഥ കൂടുതല്‍ അധികാരങ്ങളുള്ള (privileged) ഒന്നാണ്. ഇതിനെ കെര്‍ണല്‍ മോഡ് എന്ന് വിളിക്കുന്നു. സാധാരണ രീതിയില്‍ ഒരു പ്രോസസ്സ് പ്രവര്‍ത്തിക്കുന്ന അവസ്ഥ യൂസര്‍ മോഡ് എന്നും അറിയപ്പെടുന്നു. യൂസര്‍ മോഡില്‍ ഒരു പ്രോസസ്സിന് അധികാരങ്ങള്‍ വളരെ കുറവാണ്. പ്രോസസ്സ് ഒരു സിസ്റ്റം കോള്‍ ഉപയോഗിക്കുമ്പോള്‍ അത് യൂസര്‍മോഡില്‍ നിന്ന് കെര്‍ണല്‍ മോഡിലേക്ക് മാറുന്നു. കെര്‍ണലുമായി നേരിട്ട് ബന്ധപ്പെട്ടിരിക്കുന്ന വിവരങ്ങള്‍ എല്ലാം കെര്‍ണല്‍ സ്പേസ് എന്ന പദം കൊണ്ടാണ് സൂചിപ്പിക്കുന്നത്. അല്ലാത്തവ യൂസര്‍ സ്പേസും. ഒരു പ്രോഗ്രാമില്‍ ഉപയോഗിച്ചിരിക്കുന്ന ചരങ്ങള്‍ (വേരിയബിളുകള്‍) എല്ലാം  യൂസര്‍ സ്പേസില്‍ ആയിരിക്കും ഉണ്ടാകുന്നത്. പ്രോസസ്സ് ടേബിള്‍, യു-ഏരിയ എന്നിവയെല്ലാം കെര്‍ണല്‍ സ്പേസിലും.

പ്രോസസ്സിന്റെ വിവിധ അവസ്ഥകള്‍ (Process states)
ഒരു പ്രോസസ്സിന്റെ വിവിധ അവസ്ഥകള്‍ താഴെപ്പറയുന്നവയാണ്,
കടപ്പാട്: വിക്കിപീഡിയ
ഹാര്‍ഡ് ഡിസ്കില്‍ നിന്നും  പ്രോഗ്രാമിനെ മെമ്മറിയില്‍ എത്തിച്ചുകഴിഞ്ഞാല്‍ അത് ക്രിയേറ്റഡ് എന്ന അവസ്ഥയിലായിരിക്കും. സൃഷ്ടിക്കപ്പെട്ടു എന്ന അര്‍ഥത്തില്‍. ഒന്നിലധികം  പ്രോസസ്സുകള്‍ പ്രവര്‍ത്തിക്കുന്ന സിസ്റ്റത്തില്‍ സൃഷ്ടിക്കപ്പെട്ട ഉടനെ തന്നെ പ്രോസസ്സിന് പ്രവര്‍ത്തിച്ചു തുടങ്ങാനാകില്ല. ഒരു സമയത്ത് ഒരൊറ്റ പ്രോസസ്സിന് മാത്രമേ പ്രവര്‍ത്തിക്കാന്‍ സാധിക്കുകയുള്ളു എന്നതാണ് ഇതിന് കാരണം. അപ്പോള്‍ ആ പ്രോസസ്സ് കാത്തിരിപ്പ് (വെയിറ്റിങ്ങ്‌‌) അവസ്ഥയിലായിരിക്കും. ഓപ്പറേറ്റിങ്ങ് സിസ്റ്റം ഷെഡ്യൂള്‍ ചെയ്യുന്നതിനനുസരിച്ച് അതിന് പ്രവര്‍ത്തിച്ച് തുടങ്ങാന്‍ സാധിക്കുന്നു. പ്രവര്‍ത്തിച്ചുകൊണ്ടിരിക്കുന്ന അവസ്ഥയാണ് റണ്ണിങ്ങ്. മെയിന്‍ മെമ്മറിയുടെ ലഭ്യതയുടെ അടിസ്ഥാനത്തില്‍ ചിലപ്പോള്‍ പ്രോസസ്സിനെ മെമ്മറിയില്‍ നിന്നും  ഡിസ്കിലേക്ക് സ്വാപ്പ് ചെയ്യാന്‍ സാധ്യതയുണ്ട്. സ്വാപ്പിങ്ങിനെപ്പറ്റി മെമ്മറി മാനേജ്‌‌മെന്റിനെക്കുറിച്ചുള്ള പോസ്റ്റില്‍ വായിക്കാം. കാത്തിരിക്കുന്ന സമയത്ത് മെമ്മറിയില്‍ നിന്ന് ഡിസ്കിലേക്ക് മാറ്റപ്പെട്ട അവസ്ഥയാണ് ഇടതുവശത്ത് താഴെയുള്ളത്. ഇനിയുള്ള അവസ്ഥ ബ്ലോക്ക് ചെയ്യപ്പെട്ട അവസ്ഥയാണ്. ഒരു പ്രോസസ്സിന് പ്രവര്‍ത്തനം തുടരാന്‍ ഏതെങ്കിലും  ഉപകരണത്തില്‍ നിന്നുള്ള സിഗ്നല്‍ ആവശ്യമാണെന്ന് കരുതുക. ഇത് ചിലപ്പോള്‍ ഉപഭോക്താവ് കീബോര്‍ഡില്‍ എന്തെങ്കിലും  അമര്‍ത്താനായിരിക്കാം, ഇന്റര്‍നെറ്റില്‍ നിന്ന് ഒരു പാക്കറ്റ് ലഭിക്കാനായിരിക്കാം. ഇത് പൂര്‍ത്തിയാകുന്നത് വരെ ആ പ്രോസസ്സിന് തുടരാന്‍ സാധിക്കില്ല. ഈ അവസ്ഥയില്‍ ഓപ്പറേറ്റിങ്ങ് സിസ്റ്റം ആ പ്രോസസ്സിനെ ബ്ലോക്ക് ചെയ്‌‌ത് സി പി യു മറ്റൊരു പ്രോസസ്സിനായി വിട്ടു കൊടുക്കുന്നു. ആ അവസ്ഥയില്‍ ചിലപ്പോള്‍ പ്രോസസ്സ് മെമ്മറിയില്‍ നിന്നും  ഡിസ്കിലേക്ക് മാറ്റപ്പെട്ടേക്കാം. ഈ അവസ്ഥയാണ് വലതുവശത്ത് താഴെക്കാണുന്നത്.

ഫോര്‍ക്ക് സിസ്റ്റംകോളിന്റെ പ്രവര്‍ത്തനത്തെപ്പറ്റി വിശദമായി അടുത്ത പോസ്റ്റില്‍.

Sunday, October 07, 2012

പ്രോഗ്രാം, പ്രോസസ്സ് - 4

 പ്രോഗ്രാം
പ്രോസസ് എന്നത് മെമ്മറിയില്‍ ലോഡ് ചെയ്യപ്പെട്ട പ്രോഗ്രാം ആണെന്ന് നേരത്തേ‌ പറഞ്ഞു. പ്രോസസ്സുകള്‍ ആയി മാറുന്ന പ്രോഗ്രാമുകളെക്കുറിച്ച് ഈ ഭാഗത്തില്‍..

ലിനക്സിലെ ഫയല്‍ അനുമതികളില്‍ എക്സിക്യൂട്ടബിള്‍ എന്ന ഒരു അനുമതി ഉണ്ട്. ഇത് ഏത് ഫയലിന് വേണമെങ്കിലും  കൊടുക്കാവുന്നതാണ്. ഈ അനുവാദം ഉള്ളതുകൊണ്ട് മാത്രം  ഒരു ഫയല്‍ എക്സിക്യൂട്ടബിള്‍ ഫയല്‍ ആകുന്നില്ല. ഒരോ ഫയലുകളും  ഏത് തരത്തില്‍ ഉള്ളവയാണെന്ന് മനസ്സിലാക്കാന്‍ ലിനക്സില്‍ ഫയല്‍ (file) കമാന്റ് ഉപയോഗിക്കാവുന്നതാണ്. ചില ഉദാഹരണങ്ങള്‍ നോക്കൂ, 

subin@subin:~/Pictures/Tux$ file 100px-NewTux.png
100px-NewTux.png: PNG image data, 100 x 120, 8-bit/color RGBA, non-interlaced

subin@subin:/bin$ file bash
bash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, stripped

subin@subin:/lib$ file libfuse.so.2.8.6
libfuse.so.2.8.6: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped

ഈ പ്രോഗ്രാം  ഫയലിന്റെ പേരോ എക്സ്റ്റന്‍ഷനോ അടിസ്ഥാനമാക്കിയല്ല ഫയലിന്റെ തരം തീരുമാനിക്കുന്നത്. മിക്കവാറൂം  ബൈനറി വിവരങ്ങള്‍ അടങ്ങിയിരിക്കുന്ന ഫയലുകള്‍ക്കൊക്കെ ഒരു ക്രമീകരണ രീതി ഉണ്ടാകും. ആ ഫയലിലെ ആദ്യത്തെ ഏതാനും  ബൈറ്റുകളില്‍ ഒരു മാജിക് നമ്പര്‍ അടങ്ങിയിരിക്കും. ഈ മാജിക് നമ്പര്‍ ഓരോ തരത്തിലുള്ള ഫയലിനും  ഓരോന്നായിരിക്കും. മുകളിലെ ഉദാഹരണത്തില്‍ രണ്ടാമതും  മൂന്നാമതും  ഉള്ള ഫയലുകള്‍ ELF എന്ന തരത്തില്‍ പെട്ടവയാണ്. ലിനക്സിലെ എക്സിക്യൂട്ടബിള്‍ ഫയലിന്റെ ക്രമീകരണരീതികളില്‍ ഒന്നാണ് ELF. എക്സിക്യൂട്ടബിള്‍ ആന്‍ഡ്‌ ലിങ്കബിള്‍ ഫോര്‍മാറ്റ് എന്നതിന്റെ ചുരുക്കമാണിത്. ഇത് കൂടാതെ ഷെല്‍ സ്ക്രിപ്റ്റുകള്‍, പൈത്തണ്‍, പേള്‍ പ്രോഗ്രാമുകള്‍ എന്നിവയെയൊക്കെ എക്സിക്യൂട്ടബിളുകള്‍ ആയി പരിഗണിക്കും. എന്നാല്‍ ELF ഫയലുകള്‍ പോലെയല്ല അവ കൈകാര്യം ചെയ്യപ്പെടുന്നത്. അവയെ പ്രവര്‍ത്തിപ്പിക്കാനാവശ്യമായ പ്രോഗ്രാമുകളുടെ വിവരം ആ ഫയലുകളുടെ ആദ്യം രേഖപ്പെടുത്തിയിരിക്കും. ഷെല്‍ സ്ക്രിപ്റ്റുകളുടെ ഒക്കെ ഫയലിലെ ആദ്യത്തെ വരി മിക്കവാറും  #!/bin/bash എന്നായിരിക്കും. /bin/bash എന്ന പ്രോഗ്രാമുപയോഗിച്ചാണ് ആ ഫയലിനെ പ്രവര്‍ത്തിപ്പിക്കേണ്ടത് എന്നര്‍ഥം. എന്നാല്‍ ELF ഫയലുകളെ കെര്‍ണല്‍ നേരിട്ട് പ്രവര്‍ത്തിപ്പിക്കുകയാണ് ചെയ്യുന്നത്. ELF ഫയലുകളിലെ വിവരങ്ങള്‍ വിവിധ വിഭാഗങ്ങളില്‍ ആയാണ് ക്രമീകരിച്ചിരിക്കുക. മുകളിലെ ഉദാഹരണത്തില്‍ രണ്ടാമത് കാണുന്നത് ഒരു എക്സിക്യൂട്ടബിള്‍ ഫയലും  മൂന്നാമത്തേത് ഒരു ഷെയേര്‍ഡ്‌ ലൈബ്രറിയും  ആണ്. ഇവയെക്കുറിച്ച് പിന്നീട് പറയാം. ഈ ഫയലുകളില്‍ ഒക്കെ ഉണ്ടാകുന്ന വിവിധ ഭാഗങ്ങള്‍ (സെഗ്‌‌മെന്റ്) ചുവടെ (ഇത് ഒരു സി കമ്പൈലര്‍ ഉണ്ടാക്കുന്ന എക്സിക്യൂട്ടബിളിനെ അടിഥാനമാക്കിയാണ്),

1. .text: പ്രോഗ്രാമിലെ നിര്‍ദ്ദേശങ്ങള്‍. ഇവക്കനുസരിച്ചാണ് പ്രോഗ്രാം  പ്രവര്‍ത്തിക്കുന്നത്.
2. .data: ഒരു സി പ്രോഗ്രാമിലെ മൂല്യം തീരുമാനിക്കപ്പെട്ട ഗ്ലോബല്‍ വേരിയബിളുകള്‍, സ്റ്റാറ്റിക് വേരിയബിളുകള്‍ എന്നിവയൊക്കെ.
3. .bss: മൂല്യം തീരുമാനിക്കപ്പെട്ടിട്ടില്ലാത്ത ഗ്ലോബല്‍ വേരിയബിളുകള്‍.
4. .stack: പ്രോഗ്രാമിലെ വിവിധ ഫങ്ഷനുകള്‍ക്ക് പ്രവര്‍ത്തിക്കാനാവശ്യമായ വിവരങ്ങള്‍. പ്രോഗ്രാമിന്റെ ആരംഭത്തില്‍ ഇതില്‍ മെയിന്‍ ഫങ്ങ്ഷനിലെ ലോക്കല്‍/ഓട്ടോമാറ്റിക് വേരിയബിളുകള്‍, റിട്ടേണ്‍ അഡ്രസ്സ്, കമാന്റ് ലൈന്‍ ആര്‍ഗ്യുമെന്റുകള്‍, എന്‍വയോണ്‍മെന്റ് വേരിയബിളുകള്‍ എന്നിവയായിരിക്കും  ഉണ്ടാവുക. മറ്റൊരു ഫങ്ങ്ഷന്‍ വിളിക്കപ്പെടുമ്പോള്‍ ആ ഫങ്ങ്‌‌ഷന്റെ ലോക്കല്‍ വേരിയബിളുകള്‍, അതിന്റെ ആര്‍ഗ്യുമെന്റുകള്‍, അതിന്റെ റിട്ടേണ്‍ അഡ്രസ് തുടങ്ങിയ വിവരങ്ങള്‍ ഉള്‍ക്കൊള്ളിച്ച് ഒരു പുതിയ ഉപ ഭാഗം  ഇതിനുള്ളില്‍ സൃഷ്ടിക്കപ്പെടുന്നു.
5. .heap: പ്രോഗ്രാം  പ്രവര്‍ത്തിക്കുന്ന സമയത്ത് അതിന് കൂടുതല്‍ മെമ്മറി ആവശ്യമായി വന്നാല്‍ അത് അനുവദിക്കാനുള്ള സ്ഥലം.
(മുകളിലുള്ള സി പ്രോഗ്രാമിങ്ങുമായി ബന്ധപ്പെട്ട പദങ്ങള്‍ വിശദീകരിക്കാന്‍ കൂടുതല്‍ സ്ഥലവും  സമയവും  വേണ്ടിവരുമെന്നതിനാല്‍ അവയുടെ വിശദീകരണം ഒഴിവാക്കുന്നു. അവ എന്താണെന്ന് സൂചിപ്പിക്കുന്ന വിക്കി ലേഖനത്തിലേക്ക് കണ്ണികള്‍ നല്‍കിയിട്ടുണ്ട്)

ആധുനിക കമ്പൈലറുകള്‍ ഇവക്ക് പുറമേ മറ്റ് പല ഭാഗങ്ങളും  എക്സിക്യൂട്ടബിള്‍ ഫയലുകളില്‍ ഉള്‍പ്പെടുത്താറുണ്ട്. ജി ഡി ബി പോലെയുള്ള ഡീബഗ്ഗര്‍ പ്രോഗ്രാമുകള്‍ക്കാവശ്യമായ വിവരങ്ങള്‍ Dwarf എന്ന ക്രമീകരണ രീതി ഉപയോഗിച്ച് ചില എക്സിക്യൂട്ടബിള്‍ ഫയലുകളില്‍ കാണും. (Elf എന്ന പേരിന്റെ കൂടെ നില്‍ക്കാന്‍ Dwarf എന്ന് പേരിട്ടതാണ്. ഇവ രണ്ടും മാന്ത്രിക ജീവികളുടെ പേരാണല്ലോ.) മറ്റുള്ള ബൈനറി എക്സിക്യൂട്ടബിള്‍ ക്രമീകരണ രീതികളിലും  ഈ ഭാഗങ്ങള്‍ ഒക്കെ ഉണ്ടാകും. Elf ഒരു ഉദാഹരണമായി എടുത്തത് യൂണിക്സ്/ലിനക്സ് സിസ്റ്റങ്ങള്‍ അത് ഉപയോഗിക്കുന്നു എന്നതിനാലാണ്. എക്സിക്യൂട്ടബിള്‍ ഫയലുകളെ കുറിച്ചുള്ള വിവരങ്ങള്‍ ലഭിക്കാനും  അവയെ അപഗ്രഥിക്കാനും  മറ്റുമായി വിവിധ പ്രോഗ്രാമുകള്‍ ലഭ്യമാണ്. ഉദാഹരണത്തിന്, എക്സിക്യൂട്ടബിള്‍ ഫയലിലെ വിവിധ സെഗ്മന്റുകളുടെ വലിപ്പം അറിയാന്‍ size, ഫയലിലെ വിവിധ ചിഹ്നങ്ങളുടെ വിവരങ്ങള്‍ ലഭിക്കാന്‍ nm, elf ഫയലുകളിലെ വിവിധ വിവരങ്ങള്‍ക്കായി readelfഎന്നിവ.

കമ്പൈലര്‍ ഒരു എക്സിക്യൂട്ടബിള്‍ ഫയല്‍ ഉണ്ടാക്കിക്കഴിഞ്ഞാല്‍ അതില്‍ പ്രവര്‍ത്തനസമയത്ത് അത്യാവശ്യമല്ലാത്ത വിവിധ വിവരങ്ങള്‍ ഉണ്ടായിരിക്കും. സാധാരണ ഉപഭോക്താക്കള്‍ക്ക് ആവശ്യമില്ലാത്ത ഈ വിവരങ്ങള്‍ ഒഴിവാക്കുന്നത് ഫയലുകളുടെ വലിപ്പം കുറക്കാന്‍ സഹായിക്കും. ഇങ്ങനെയുള്ള വിവരങ്ങള്‍ ഒഴിവാക്കുന്ന പ്രക്രിയയെ സ്ട്രിപ്പിങ്ങ് എന്ന് പറയുന്നു. strip എന്ന പ്രോഗ്രാം  ഉപയോഗിച്ച് ഇത് ചെയ്യാവുന്നതാണ്. ആദ്യം  നല്‍ലിയിരിക്കുന്ന ഫയല്‍ കമാന്റ് ഉദാഹരണങ്ങളില്‍ അവസാനം stripped എന്ന് പരാമര്‍ശിച്ചിട്ടുള്ളത് ശ്രദ്ധിക്കൂ.

യൂണിക്സ്/ലിനക്സ് സിസ്റ്റങ്ങളില്‍ പ്രോസസുകള്‍ തുടങ്ങുന്നത്, അവസാനിപ്പിക്കുന്നത് എന്നിവയെക്കുറിച്ച് അടുത്ത പോസ്റ്റില്‍.