intheopenfileobjectthatis,thecurrentpositionatwhichthenextreadorwriteoperationwilltakeplace.Sequentialaccessisimplicitlyassumed:theread()andwrite()systemcallsalwaysrefertotheposition of the current file pointer.To modify the value,a program must explicitly invoke thelseek()systemcall.Whenafileisopened,thekernelsetsthefilepointertothepositionofthefirstbyte in the file (offset 0)The lseek()system call requires the following parameters:newoffset -lseek(fd,offset, whence);which have the following meanings:fdIndicatesthefiledescriptoroftheopenedfileoffsetSpecifiesa signed integervaluethat will beused forcomputingthenewposition of thefilepointerwhenceSpecifieswhetherthenewpositionshould becomputedbyaddingtheoffsetvaluetothenumbero(offsetfromthebeginning ofthefile),thecurrentfilepointer,ortheposition ofthelastbyte (offsetfromtheendofthefile)Theread()systemcall requiresthefollowingparameters:nread = read(fd, buf, count);which havethefollowingmeanings:fdIndicates thefile descriptorof theopened filebuf36
36 in the open file object that is, the current position at which the next read or write operation will take place. Sequential access is implicitly assumed: the read( ) and write( ) system calls always refer to the position of the current file pointer. To modify the value, a program must explicitly invoke the lseek( ) system call. When a file is opened, the kernel sets the file pointer to the position of the first byte in the file (offset 0). The lseek( ) system call requires the following parameters: newoffset = lseek(fd, offset, whence); which have the following meanings: fd Indicates the file descriptor of the opened file offset Specifies a signed integer value that will be used for computing the new position of the file pointer whence Specifies whether the new position should be computed by adding the offset value to the number 0 (offset from the beginning of the file), the current file pointer, or the position of the last byte (offset from the end of the file) The read( ) system call requires the following parameters: nread = read(fd, buf, count); which have the following meanings: fd Indicates the file descriptor of the opened file buf
Specifies theaddress of the buffer in the process's address space to which thedata will betransferredcountDenotesthenumberof bytestoreadWhen handling such a system call, the kernel attempts to read count bytes from the file having thefile descriptor fd, starting from the current value of the opened file's offset field.In somecasesend-of-file,emptypipe,and soonthekerneldoesnot succeed inreadingall countbytes.Thereturnednreadvaluespecifiesthenumberofbyteseffectivelyread.Thefilepointeralso isupdatedby adding nreadto its previous value.Thewrite()parameters are similar.1.5.6.3. Closing a fileWhen a process does not need to access the contents of a file anymore, it can invoke the systemcall:res = close(fd);which releases the open file object corresponding to the file descriptor fd.Whena processterminates,thekernelclosesall itsremainingopenedfiles.1.5.6.4.Renaminganddeletinga fileTo rename or delete a file, a process does not need to open it. Indeed, such operations do not acton the contents of the affectedfile,butrather on thecontents of one or moredirectories.Forexample,thesystemcall:res = rename(oldpath, newpath);changes thenameofa file link,whilethesystem call:res = unlink(pathname);decreasesthefile linkcountandremovesthecorrespondingdirectoryentry.Thefileisdeletedonlywhenthelinkcountassumesthevalue01.6.AnOverviewofUnixKernels37
37 Specifies the address of the buffer in the process's address space to which the data will be transferred count Denotes the number of bytes to read When handling such a system call, the kernel attempts to read count bytes from the file having the file descriptor fd, starting from the current value of the opened file's offset field. In some casesend-of-file, empty pipe, and so onthe kernel does not succeed in reading all count bytes. The returned nread value specifies the number of bytes effectively read. The file pointer also is updated by adding nread to its previous value. The write( ) parameters are similar. 1.5.6.3. Closing a file When a process does not need to access the contents of a file anymore, it can invoke the system call: res = close(fd); which releases the open file object corresponding to the file descriptor fd. When a process terminates, the kernel closes all its remaining opened files. 1.5.6.4. Renaming and deleting a file To rename or delete a file, a process does not need to open it. Indeed, such operations do not act on the contents of the affected file, but rather on the contents of one or more directories. For example, the system call: res = rename(oldpath, newpath); changes the name of a file link, while the system call: res = unlink(pathname); decreases the file link count and removes the corresponding directory entry. The file is deleted only when the link count assumes the value 0. 1.6. An Overview of Unix Kernels
Unix kernels provide an execution environment in which applications may run. Therefore, thekernel must implement a set of services and corresponding interfaces.Applications usethoseinterfaces and do not usually interact directly with hardware resources.1.6.1.TheProcess/KernelModelAs already mentioned,a CPU can run in either User Mode or Kernel Mode.Actually,some CPUs canhavemorethantwo executionstates.For instance,the80x86microprocessorshavefourdifferentexecutionstates.ButallstandardUnixkernelsuseonlyKernelModeandUserModeWhen a program is executed in User Mode, it cannot directly access the kernel data structures orthe kernel programs.when an application executes in Kernel Mode,however,these restrictions nolongerapply.EachCPUmodel provides special instructionsto switch fromUserModetoKernelModeandviceversa.AprogramusuallyexecutesinUserModeandswitchestoKernelModeonlywhenrequestinga serviceprovidedbythekernel.Whenthekernel has satisfiedtheprogram'srequest, it puts the program back in User Mode.Processes are dynamic entities that usually have a limited life span within the system. The task ofcreating,eliminating,andsynchronizing the existing processesisdelegatedtoa groupof routinesinthekernel.Thekernel itself is not a process but a process manager.The process/kernel model assumes thatprocesses that require a kernel service use specific programming constructs called system calls.Each systemcallsets up thegroup ofparametersthat identifiestheprocessrequest and thenexecutesthehardware-dependentCPUinstructiontoswitchfromUserModetoKernelMode.Besidesuserprocesses,Unixsystemsincludeafewprivilegedprocessescalledkernelthreadswiththefollowing characteristics:.Theyrun inKernel Mode in thekernel address space.Theydo not interact withusers,and thus do not requireterminal devices.They are usually created during system startup and remain alive until the system is shutdown.On a uniprocessor system, only one process is running at a time,and it may run either in User orin Kernel Mode.If it runs in Kernel Mode, the processor is executing some kernel routine.Figure1-2 illustrates examples of transitions between Userand Kernel Mode.Process 1 in UserModeissuesa systemcall,after whichtheprocess switchestoKernel Mode,andthe systemcall isserviced. Process 1 then resumes execution in User Mode until a timer interrupt occurs, and thescheduler is activatedinKernel Mode.Aprocessswitchtakesplace,andProcess2 startsits38
38 Unix kernels provide an execution environment in which applications may run. Therefore, the kernel must implement a set of services and corresponding interfaces. Applications use those interfaces and do not usually interact directly with hardware resources. 1.6.1. The Process/Kernel Model As already mentioned, a CPU can run in either User Mode or Kernel Mode . Actually, some CPUs can have more than two execution states. For instance, the 80 x 86 microprocessors have four different execution states. But all standard Unix kernels use only Kernel Mode and User Mode. When a program is executed in User Mode, it cannot directly access the kernel data structures or the kernel programs. When an application executes in Kernel Mode, however, these restrictions no longer apply. Each CPU model provides special instructions to switch from User Mode to Kernel Mode and vice versa. A program usually executes in User Mode and switches to Kernel Mode only when requesting a service provided by the kernel. When the kernel has satisfied the program's request, it puts the program back in User Mode. Processes are dynamic entities that usually have a limited life span within the system. The task of creating, eliminating, and synchronizing the existing processes is delegated to a group of routines in the kernel. The kernel itself is not a process but a process manager. The process/kernel model assumes that processes that require a kernel service use specific programming constructs called system calls . Each system call sets up the group of parameters that identifies the process request and then executes the hardware-dependent CPU instruction to switch from User Mode to Kernel Mode. Besides user processes, Unix systems include a few privileged processes called kernel threads with the following characteristics: They run in Kernel Mode in the kernel address space. They do not interact with users, and thus do not require terminal devices. They are usually created during system startup and remain alive until the system is shut down. On a uniprocessor system, only one process is running at a time, and it may run either in User or in Kernel Mode. If it runs in Kernel Mode, the processor is executing some kernel routine. Figure 1-2 illustrates examples of transitions between User and Kernel Mode. Process 1 in User Mode issues a system call, after which the process switches to Kernel Mode, and the system call is serviced. Process 1 then resumes execution in User Mode until a timer interrupt occurs, and the scheduler is activated in Kernel Mode. A process switch takes place, and Process 2 starts its
execution in User Mode until a hardware device raises an interrupt. As a consequence of theinterrupt,Process2switchestoKernelModeandservicestheinterrupt.Figure1-2.TransitionsbetweenUserandKernelModeProcess2Process1Process1Process2USERMODEKERNELMODESystemcllInteruptSchedulerhandlerhandlerSystemcallTimer interuptDevice interuptTimeUnixkernelsdomuchmorethanhandlesystemcalls;infact,kernel routinescanbeactivatedinseveral ways:Aprocess invokesasystemcall.TheCPUexecuting theprocess signals an exception,which isanunusual condition suchasaninvalidinstruction.Thekernelhandlestheexceptiononbehalfoftheprocessthatcausedit.Aperipheral device issues an interrupt signal totheCPUtonotify itofan eventsuchasarequestfor attention,a status change,or the completion ofan I/ooperation.Each interruptsignal is dealt by a kernel program called an interrupt handler.Because peripheral devicesoperate asynchronouslywith respect to the CpU,interrupts occur atunpredictable times.Akernelthreadisexecuted.Becauseit runs inKernel Mode,thecorresponding programmustbeconsideredpartofthekernel1.6.2.ProcesslmplementationToletthekernel manageprocesses,eachprocess is representedbyaprocessdescriptorthatincludes information about the current state of the process.Whenthe kernel stops the execution of aprocess,it saves the currentcontents of severalprocessor registers in the process descriptor.These include:Theprogramcounter(PC)andstackpointer(SP)registers。Thegeneralpurposeregisters39
39 execution in User Mode until a hardware device raises an interrupt. As a consequence of the interrupt, Process 2 switches to Kernel Mode and services the interrupt. Figure 1-2. Transitions between User and Kernel Mode Unix kernels do much more than handle system calls; in fact, kernel routines can be activated in several ways: A process invokes a system call. The CPU executing the process signals an exception, which is an unusual condition such as an invalid instruction. The kernel handles the exception on behalf of the process that caused it. A peripheral device issues an interrupt signal to the CPU to notify it of an event such as a request for attention, a status change, or the completion of an I/O operation. Each interrupt signal is dealt by a kernel program called an interrupt handler. Because peripheral devices operate asynchronously with respect to the CPU, interrupts occur at unpredictable times. A kernel thread is executed. Because it runs in Kernel Mode, the corresponding program must be considered part of the kernel. 1.6.2. Process Implementation To let the kernel manage processes, each process is represented by a process descriptor that includes information about the current state of the process. When the kernel stops the execution of a process, it saves the current contents of several processor registers in the process descriptor. These include: The program counter (PC) and stack pointer (SP) registers The general purpose registers
The floating point registersTheprocessor control registers (Processor Status Word)containing information about theCPUstateThememory management registers usedtokeep track of the RAMaccessed bythe processWhen thekernel decides to resume executinga process, it uses the proper process descriptorfieldsto loadtheCPUregisters.Becausethestoredvalueoftheprogramcounterpointstothe instructionfollowing the last instruction executed, the process resumes execution at the point where it wasstopped.When a process is not executing on the CpU,it is waiting for some event.Unix kernels distinguishmanywaitstates,whichareusuallyimplementedbyqueuesofprocessdescriptors;each(possiblyempty)queue corresponds tothesetof processes waiting fora specificevent.1.6.3.ReentrantKernelsAll Unixkernelsarereentrant.ThismeansthatseveralprocessesmaybeexecutinginKernelModeat the same time.Of course,on uniprocessor systems,only oneprocess canprogress,butmanycan beblocked inKernel Modewhen waitingfortheCPUorthecompletion ofsomeI/Ooperation.Forinstance,afterissuingareadtoadiskonbehalfofaprocess,thekernel letsthediskcontrollerhandleitandresumesexecutingotherprocesses.Aninterruptnotifiesthekernelwhenthedevicehas satisfied the read, so theformer process can resume theexecution.One wayto provide reentrancy is to write functions so that they modify only local variables and donot alter global datastructures.Suchfunctions are called reentrantfunctions.But a reentrantkernelisnot limitedonlytosuchreentrantfunctions(althoughthat ishowsomereal-timekernelsare implemented).Instead, the kernel can include nonreentrant functions and use lockingmechanismstoensurethatonlyoneprocesscanexecuteanonreentrantfunctionatatime.If a hardware interrupt occurs,a reentrantkernelisableto suspend the current runningprocessevenifthatprocessisinKernelMode.Thiscapabilityisveryimportant,becauseitimprovesthethroughputof thedevice controllersthat issue interrupts.Oncea devicehasissued an interrupt,itwaits until the CPUacknowledges it.If thekernel is abletoanswerquickly,thedevice controllerwillbeable toperform othertasks while the CPU handles the interrupt.Nowlet'slookatkernelreentrancyandits impactontheorganizationofthekernel.Akernelcontrolpathdenotes thesequence of instructionsexecuted bythekerneltohandle a systemcall,anexception,or aninterrupt.40
40 The floating point registers The processor control registers (Processor Status Word) containing information about the CPU state The memory management registers used to keep track of the RAM accessed by the process When the kernel decides to resume executing a process, it uses the proper process descriptor fields to load the CPU registers. Because the stored value of the program counter points to the instruction following the last instruction executed, the process resumes execution at the point where it was stopped. When a process is not executing on the CPU, it is waiting for some event. Unix kernels distinguish many wait states, which are usually implemented by queues of process descriptors ; each (possibly empty) queue corresponds to the set of processes waiting for a specific event. 1.6.3. Reentrant Kernels All Unix kernels are reentrant. This means that several processes may be executing in Kernel Mode at the same time. Of course, on uniprocessor systems, only one process can progress, but many can be blocked in Kernel Mode when waiting for the CPU or the completion of some I/O operation. For instance, after issuing a read to a disk on behalf of a process, the kernel lets the disk controller handle it and resumes executing other processes. An interrupt notifies the kernel when the device has satisfied the read, so the former process can resume the execution. One way to provide reentrancy is to write functions so that they modify only local variables and do not alter global data structures. Such functions are called reentrant functions . But a reentrant kernel is not limited only to such reentrant functions (although that is how some real-time kernels are implemented). Instead, the kernel can include nonreentrant functions and use locking mechanisms to ensure that only one process can execute a nonreentrant function at a time. If a hardware interrupt occurs, a reentrant kernel is able to suspend the current running process even if that process is in Kernel Mode. This capability is very important, because it improves the throughput of the device controllers that issue interrupts. Once a device has issued an interrupt, it waits until the CPU acknowledges it. If the kernel is able to answer quickly, the device controller will be able to perform other tasks while the CPU handles the interrupt. Now let's look at kernel reentrancy and its impact on the organization of the kernel. A kernel control path denotes the sequence of instructions executed by the kernel to handle a system call, an exception, or an interrupt