📂
build a OS
  • Learn OS with me
  • OS Interfaces
    • OS interfaces
    • I/O and File descriptors
    • Process and Memory
    • Pipes
    • File
  • OS Organization
    • OS Organization
    • Challenge yourself
  • Memory Management
    • XV6 Virtual Memory
    • Page Table
      • Part 1: How to translate address
      • Part 2: Create an Address Space
      • Part 3: How Page Table is used
      • Part 4: Page Fault and Swap
      • Part 5: How to operate on page tables
    • xv6 buddy allocator
      • How to display physical memory
    • Memory Management Walk Through
  • Traps and Interrupts
    • Trap Home Page
      • 系统调用的核心原理
    • What is trapframe
    • What is trampoline
    • Traps from kernel space
    • How fork() works
    • How system calls get into/out of the kernel
    • How exec() works
  • Scheduling
    • XV6 CPU Scheduling
    • How unix pipes work?
    • How does wait(), exit(), kill() work?
  • File System
    • Overview and Disk Layout
    • Buffer Cache
    • Design Inode Layer
    • Inode Content
    • Block Allocator
    • Design a log system for crash recovery
    • Directory Layer
    • Path names
    • File Descriptor Layer
    • FS System Calls
    • XV6 VS Real World
    • Make Xv6 File disk management system
    • Write FS simulator in python
    • How Redirect Shell command works
  • Concurrency
    • Spinlock
    • How linux select work
    • Hardware Support Locking
    • Exercise: Implement atomic counter
    • Locking in Xv6
    • Concurrency in Xv6
    • Exercise: Socket Programming with Event loop
  • Labs
    • Lab 1 Xv6 and Unix utilities
    • Lab 2 Shell
    • Lab 3 Buddy Allocator
    • Lab 4 Lazy
    • Lab 5 Copy-on-Write Fork for xv6
    • Lab 6 RISC-V assembly
    • Lab 6 Uthread: switching between threads
    • Lab 6 Alarm
    • Lab 7 Lock
    • Lab 8 File System: Large Files
    • Lab 8 File System: Symbolic links
    • Lab 9 mmap
    • Lab 10 Networking Part 1
    • Lab 10 Networking Part 2
  • Hardware, Device, Assembly
    • RISC-V assembly
    • Assembly: Access and Store information in Memory
    • Start xv6 and the first process
    • Why first user process loads another program?
    • What does kernel.ld do in XV6?
    • XV6 Device Driver
Powered by GitBook
On this page
  • I/O redirection
  • fork copies fd table, but file offset is shared.
  • Summary

Was this helpful?

  1. OS Interfaces

I/O and File descriptors

A fd is a small integer representing a kernel-managed object that a process may read/write. A process obtains a fd by opening a file, directory, device, pipe, or socket. In unix, a file has different types that what it currently represents.

Every process has a private space of file descriptors starting at zero. Xv6 kernel uses fd as an index into a per-process table.

By convention, fd 1(standard input), fd 2(standard output), fd3 (standard error). xv6 shell ensure the 3 fds are open when starting up.

read and write system calls advance the file by offset (how much it reads or writes), so next time, the read/write starts from the new offset.

One interesting aspect is program like cat does not know whether it is reading from file, console, socket, or pipe. It does not know whether it is printing to a console, or a file. The use of fds and the conventions allows some simple implementation of user programs.

close releases fd, making it free for reuse. A newly allocated fd is always the lowest-numbered unused descriptor of the current process. Unix shell utilizes this feature with fork, to implement smart I/O redirection, and implement pipe.

I/O redirection

fork copies parent’s file descriptor tables, with its memory. The system call exec replaces the calling process’ memory but preserves its file table.

Example how command cat < input.txt works

char *argv[2];
argv[0] = “cat”;
argv[1] = 0;
if(fork() == 0) {
  close(0);
  open(“input.txt”, O_RDONLY);
  exec(“cat”, argv);
}

After the child closes file descriptor 0, open is guaranteed to use that file descriptor for the newly opened input.txt: 0 will be the smallest available file descriptor. Cat then executes with file descriptor 0 (standard input) referring to input.txt

fork copies fd table, but file offset is shared.

The underlying file offset is shared between parent and child.

if(fork() == 0) {
  write(1, “hello “, 6);
  exit(0);
} else {
  wait(0);
  write(1, “world\en”, 6);
}

dup system call is similar. Duplicates an existing file descriptor, returning a new fd that refers to the same I/O object. Both file descriptors share the an offset.

fd = dup(1);
write(1, “hello “, 6);
write(fd, “world\en”, 6);

Do you know why the file offset is shared?

fd is basically an index pointing to an actual file object. The file is shared between parent, and child. After fork or dup, the reference count of the file is incremented.

Fun Fun Command

ls existing-file non-existing-file > tmp1 2>&1 The 2>&1 tells the shell to give the command a file descriptor 2 that is a duplicate of descriptor 1. Both the name of the existing file and the error message for the non-existing file will show up in the file tmp1.

Summary

File descriptors are a powerful abstraction, because they hide the details of what they are connected to: a process writing to file descriptor 1 may be writing to a file, to a device like the console, or to a pipe.

PreviousOS interfacesNextProcess and Memory

Last updated 5 years ago

Was this helpful?