Top Banner
Operating Systems, 112 Practical Session 1, System Calls
29

Operating Systems, 112 Practical Session 1, System Calls.

Dec 19, 2015

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Operating Systems, 112 Practical Session 1, System Calls.

Operating Systems, 112

Practical Session 1, System Calls

Page 2: Operating Systems, 112 Practical Session 1, System Calls.

System Calls

• A System Call is an interface between a user application and a service provided by the operating system (or kernel).

• These can be roughly grouped into five major categories:

1. Process control (e.g. create/terminate process)2. File Management (e.g. read, write)3. Device Management (e.g. logically attach a device)4. Information Maintenance (e.g. set time or date)5. Communications (e.g. send messages)

Page 3: Operating Systems, 112 Practical Session 1, System Calls.

System Calls - motivation

• A process is not supposed to access the kernel. It can’t access the kernel memory or functions.

• This is strictly enforced (‘protected mode’) for good reasons:

• Can jeopardize other processes running.• Cause physical damage to devices.• Alter system behavior.

• The system call mechanism provides a safe mechanism to request specific kernel operations.

Page 4: Operating Systems, 112 Practical Session 1, System Calls.

System Calls - interface

• Calls are usually made with C/C++ library functions:

User Application C - Library Kernel System Call

getpid() Load arguments,eax _NR_getpid,kenel mode (int 80) Call

Sys_Call_table[eax] sys_getpid()

returnsyscall_exit

resume_userspace

return

User-Space Kernel-Space

Remark: Invoking int 0x80 is common although newer techniques for “faster” control transfer are provided by both AMD’s and Intel’s architecture. Kernel 2.5 of Linux began using this approach when available.

Page 5: Operating Systems, 112 Practical Session 1, System Calls.

System Calls – tips

• Kernel behavior can be enhanced by altering the system calls themselves: imagine we wish to write a message (or add a log entry) whenever a specific user is opening a file. We can re-write the system call open with our new open function and load it to the kernel (need administrative rights). Now all “open” requests are passed through our function.

• We can examine which system calls are made by a program by invoking strace<arguments>.

Page 6: Operating Systems, 112 Practical Session 1, System Calls.

Process control

• Fork• pid_t fork(void);

• Fork is used to create a new process. It creates an exact duplicate of the original process (including all file descriptors, registers, instruction pointer, etc’…).

• Once the call is finished, the process and its copy go their separate ways. Subsequent changes to one should not effect the other.

• The fork call returns a different value to the original process (parent) and its copy (child): in the child process this value is zero, and in the parent process it is the PID of the child process.

• When fork is invoked the parent’s information should be copied to its child – however, this can be wasteful if the child will not need this information (see exec()…). To avoid such situations, Copy On Write (COW) is used for the data section.

Page 7: Operating Systems, 112 Practical Session 1, System Calls.

Copy On Write (COW)

• How does Linux manage COW?

Parent Process

DATA STRUCTURE(task_struct)

RW

Child Process

DATA STRUCTURE(task_struct)

RO

fork()

Copying is expensive. The child process will point to the parent’s

pages

write information

protection fault!

Well, no other choice but to allocate a new

RW copy of each required page

RW

Page 8: Operating Systems, 112 Practical Session 1, System Calls.

Process control

An example:int i = 3472;printf("my process pid is %d\n",getpid());

fork_id=fork(); if (fork_id==0){

i= 6794; printf(“child pid %d, i=%d\n",getpid(),i);

} else printf(“parent pid %d, i=%d\n",getpid(),i); return 0;

Output:my process pid is 8864child pid 8865, i=6794parent pid 8864, i=3472

Program flow:

i = 3472

fork_id=0i = 6794

PID = 8864

PID = 8865

fork ()

fork_id = 8865i=3472

Is this the only possible output?

Running the above code on some systems will almost always return this value. Why?

Page 9: Operating Systems, 112 Practical Session 1, System Calls.

Process control - zombies

• When a process ends, the memory and resources associated with it are deallocated.

• However, the entry for that process is not removed from its parent process table.

• This allows the parent to collect the child’s exit status.

• When this data is not collected by the parent the child is called a “zombie”. Such a leak is usually not worrisome in itself, however, it is a good indicator for problems to come.

Page 10: Operating Systems, 112 Practical Session 1, System Calls.

Process control - zombies

• In some (rare) occasions, a zombie is actually desired – it may, for example, prevent the creation of another child process with the same pid.

• Zombies are not the same as orphan processes (a process whose parent ended and is then adopted by init (process id 1)).

• Zombies can be detected with ps –el (marked with ‘Z’).

• Zombies can be collected with the wait system call.

Page 11: Operating Systems, 112 Practical Session 1, System Calls.

Process control

• Wait• pid_t wait(int *status);• pid_t waitpid(pid_t pid, int *status, int options);

• The wait command is used for waiting on child processes whose state changed (the process terminated, for example).

• The process calling wait will suspend execution until one of its children (or a specific one) terminates.

• Waiting can be done for a specific process, a group of processes or on any arbitrary child with waitpid.

• Once the status of a process is collected that process is removed from the process table of the collecting process.

• Kernel 2.6.9 and later also introduced waitid(…) which gives finer control.

Page 12: Operating Systems, 112 Practical Session 1, System Calls.

Process control

• exec*• int execv(const char *path, char *const argv[]);• int execvp(const char *file, char *const argv[]);• exec….

• The exec() family of function replaces current process image with a new process image (text, data, bss, stack, etc).

• Since no new process is created, PID remains the same.• Exec functions do not return to the calling process unless

an error occurred (in which case -1 is returned and errno is set with a special value).

• The system call is execve(…)

Page 13: Operating Systems, 112 Practical Session 1, System Calls.

errno• The <errno.h> header file includes the integer errno variable.• This variable is set by many functions (including sys calls) in the event of

an error to indicate what went wrong.• errnos value is only relevant when the call returned an error (usually -1).• A successful call to a function may also change the errno value.• errno may be a macro.• errno is thread local meaning that setting it in one thread does not affect

its value in any other thread.• Be wary of mistakes such as:

• If (call()==-1){printf(“failed…”);if (errno==…..)

}

• Code defensively! Use errno often!

Page 14: Operating Systems, 112 Practical Session 1, System Calls.

Process control – simple shell#define……int main(int argc, char **argv){

…while(true){type_prompt();read_command(command, params);pid=fork();if (pid<0){if (errno==EAGAIN)printf(“ERROR can not allocate sufficient memory\n”);coutinue;}if (pid>0)wait(&status);elseexecvp(command,parmas);}

Page 15: Operating Systems, 112 Practical Session 1, System Calls.

File management• In POSIX operating systems files are accessed via a file descriptor (Microsoft

Windows uses a slightly different object: file handle).• A file descriptor is an integer specifying the index of an entry in the file

descriptor table held by each process. • A file descriptor table is held be each process, and contains details of all open

files. The following is an example of such a table:

• File descriptors can refer to files, directories, sockets and a few more data objects.

FD Name Other information

0 Standard Input (stdin) …

1 Standard Output (stdout) …

2 Standard Error (stderr) …

Page 16: Operating Systems, 112 Practical Session 1, System Calls.

File management

• Open• int open(const char *pathname, int flags);• int open(const char *pathname, int flags, mode_t mode);

• Open returns a file descriptor for a given pathname.• This file descriptor will be used in subsequent system calls (according

to the flags and mode)• Flags define the access mode: O_RDONLY (read only), O_WRONLY

(write only), O_RDRW (read write). These can be bit-wised or’ed with more creation and status flags such as O_APPEND, O_TRUNC, O_CREAT.

• Close• Int close(int fd);

• Closes a file descriptor so it no longer refers to a file. • Returns 0 on success or -1 in case of failure (errno is set).

Page 17: Operating Systems, 112 Practical Session 1, System Calls.

File management

• Read• ssize_t read(int fd, void *buf, size_t count);

• Attempts to read up to count bytes from the file descriptor fd, into the buffer buf.

• Returns the number of bytes actually read (can be less than requested if read was interrupted by a signal, close to EOF, reading from pipe or terminal).

• On error -1 is returned (and errno is set).• Note: The file position advances according to the number of bytes read.

• Write• ssize_t write(int fd, const void *buf, size_t count);

• Writes up to count bytes to the file referenced to by fd, from the buffer positioned at buf.

• Returns the number of bytes actually wrote, or -1 (and errno) on error.

Page 18: Operating Systems, 112 Practical Session 1, System Calls.

File management

• lseek• off_t lseek(int fildes, off_t offset, int whence);

• This function repositions the offset of the file position of the file associated with fildes to the argument offset according to the directive whence.

• Whence can be set to SEEK_SET (directly to offset), SEEK_CUR (current+offset), SEEK_END (end+offset).

• Positioning the offset beyond file end is allowed. This does not change the size of the file.

• Writing to a file beyond its end results in a “hole” filled with ‘\0’ characters (null bytes).

• Returns the location as measured in bytes from the beginning of the file, or -1 in case of error (and set errno).

Page 19: Operating Systems, 112 Practical Session 1, System Calls.

File management

• Dup• int dup(int oldfd);• int dup2(int oldfd, int newfd);

• The dup commands create a copy of the file descriptor oldfd.• After a successful dup command is executed the old and new file

descriptors may be used interchangeably. • They refer to the same open file descriptions and thus share

information such as offset and status. That means that using lseek on one will also affect the other!

• They do not share descriptor flags (FD_CLOEXEC).• Dup uses the lowest numbered unused file descriptor, and dup2 uses

newfd (closing current newfd if necessary).• Returns the new file descriptor, or -1 in case of an error (and set

errno).

Page 20: Operating Systems, 112 Practical Session 1, System Calls.

File management

Consider the followingexample:

fileFD= open(“file.txt”…);

close(1); /* closes file handle 1, which is stdout.*/

fd =dup(fileFD); /* will create another file handle. File handle 1 is free, so it will be allocated. */

close(fileFD); /* don’t need this descriptor anymore.*/

printf(“this did not go to stdout”);

As a result (abstract):0 stdin …

1 stdout …

2 stderr …

3 file.txt …

0 stdin …

1 file.txt …

2 stderr …

A similar idea can be useful for IPC (with pipe(…))

Page 21: Operating Systems, 112 Practical Session 1, System Calls.

File management - example#define……#define RW_BLOCK 10 int main(int argc, char **argv){ int fdsrc, fddst; ssize_t readBytes, wroteBytes; char *buf[RW_BLOCK]; char *source = argv[1]; char *dest = argv[2];

fdsrc=open(source,O_RDONLY); if (fdsrc<0){ perror("ERROR while trying to open source file:"); exit(-1); } fddst=open(dest,O_RDWR|O_CREAT|O_TRUNC, 0666); if (fddst<0){ perror("ERROR while trying to open destination file:"); exit(-2); }

perror() produces a message on the standard error output describing the last error encountered during a call to a system call. Use with care: the message is not cleared when non erroneous calls are made.

Bitwise OR: open for both reading and writing, if the file does not exist create it and always start at 0.

exit() system call.

Page 22: Operating Systems, 112 Practical Session 1, System Calls.

File management - example lseek(fddst,20,SEEK_SET); do{ readBytes=read(fdsrc, buf, RW_BLOCK); if (readBytes<0){

if (errno == EIO){ printf("I/O errors detected, aborting.\n"); exit(-10);

}exit (-11);

} wroteBytes=write(fddst, buf, readBytes); if (wroteBytes<RW_BLOCK) if (errno == EDQUOT) printf("ERROR: out of quota.\n"); else if (errno == ENOSPC) printf("ERROR: not enough disk space.\n"); } while (readBytes>0); lseek(fddst,0,SEEK_SET); write(fddst,"\\*WRITE START*\\\n",16); close(fddst); close(fdsrc); return 0;}

Start writing at offset 20. If the file is opened with hexedit, the first 20 bytes will be 00.

Using errno directly.

Adding an extra comment at the beginning of the file.

Page 23: Operating Systems, 112 Practical Session 1, System Calls.

Fork – example (1)How many lines of “Hello” will be printed in the following example:

int main(int argc, char **argv){int i;for (i=0; i<10; i++){

fork();printf(“Hello \n”);

}return 0;

}

Page 24: Operating Systems, 112 Practical Session 1, System Calls.

Fork – example (1)How many lines of “Hello” will be printed in the following example:

int main(int argc, char **argv){int i;for (i=0; i<10; i++){

fork();printf(“Hello \n”);

}return 0;

}

Program flow:

Total number of printf calls:

i=0

i=1

i=2

Page 25: Operating Systems, 112 Practical Session 1, System Calls.

Fork – example (2)How many lines of “Hello” will be printed in the following example:

int main(int argc, char **argv){int i;for (i=0; i<10; i++){

printf(“Hello \n”);fork();

}return 0;

}

Page 26: Operating Systems, 112 Practical Session 1, System Calls.

Fork – example (2)How many lines of “Hello” will be printed in the following example:

int main(int argc, char **argv){int i;for (i=0; i<10; i++){

printf(“Hello \n”);fork();

}return 0;

}

Program flow:

Total number of printf calls:

i=0

i=1

i=2

Page 27: Operating Systems, 112 Practical Session 1, System Calls.

Fork – example (3)How many lines of “Hello” will be printed in the following example:

int main(int argc, char **argv){int i;for (i=0; i<10; i++)

fork(); printf(“Hello \n”);return 0;

}

Page 28: Operating Systems, 112 Practical Session 1, System Calls.

Fork – example (3)How many lines of “Hello” will be printed in the following example:

int main(int argc, char **argv){int i;for (i=0; i<10; i++)

fork(); printf(“Hello \n”);return 0;

}

Program flow:

Total number of printf calls:

i=0

i=1

i=2

Page 29: Operating Systems, 112 Practical Session 1, System Calls.

Tips

• Information sources are abundant:• The internet.• Man pages (apropos).• In Linux it is often useful (and easy) to examine the

included header files. You can easily find their location by using the whereis command (you may also find which useful).

• MSDN – this is less relevant to our course, but it also includes code examples.

• A list of system calls on CS dept. computers: /usr/include/asm/unistd_32.h