Skip to content

Linux: What you need to know

void *In this chapter, we will overview some disparate properties of Unix/Linux.

EVERYTING IS A FILE

Device files are supposed to represent physical devices.

BASIC ASSUMPTIONS OF MEMORY MANAGEMENT

In Unix/Linux, a running user process can always assume that

  1. All the 4G memory space of the processor is available as a linear array to use.
  2. It doesnt share this memory with any other process. It only sees the OS, other than itself, in the memory.
  3. It sees the OS as a set of library functions. It calls these library functions with the help of system calls. There is 200+ system calls in Linux.
  4. Out of this available 4G memory space, only 0G-3G is available to the user process. The range 3G-4G is used by kernel.
  5. We have said that 0G-3G is available to the user process. But this space is not given automatically to the user process by the OS. At the time the user process is loaded to the memory, OS only gives enough memory for the code+static data+stack etc. If the user process wants to use dynamic memory, it has to ask for this extra memory from the OS. This is usually done via the C library fuction malloc() or Linux system call mmap(). I dont know the internals of malloc(), but most probably it uses mmap() system call behind the scenes. As mentioned, the most that a user process use is 3G.

Of course, these are all illusions created by the OS. Usually, the system has much less memory than 4G, it has many processes running in parallel, and all these processes share this little memory. Hence, this illusory 4G memory, all belonging to a single user process+OS, is called the “virtual memory“. The much less glamorous reality is called the “physical memory“. We will see how OS do this magic when we investigate the linux internals.

MEMORY MAPPING

mmap system call allocates a linear region of virtual memory of a given length for our process and returns a pointer to that region. Optionally, it can also map a file into this linear region.

The signature for mmap is

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

void *addr is a virtual memory address. This addr is just a suggetion. Kernel may pick a different address. If left NULL, kernel will pick a possible addr.
size_t length is a length
int prot is a set of protection flags.  PROT_READ, PROT_WRITE, PROT_EXEC
int flags can be MAP_PRIVATE, MAP_ANONYMOUS, MAP SHARED
int fd is a file descriptor. Used only when a file is mapped into virtual memory.
off_t is an offset inside the file.

This system call can be used in two different ways:

  • When MAP_ANONYMOUS is set, it just allocates a linear region of virtual memory (addr, addr+length) in the user space for our process. In a sense, works like the malloc() library function of C. The start address addr is just a suggestion, as the kernel may decide to allocate the memory in a different place.
  • When MAP_ANONYMOUS is not set, system still allocates a linear region of memory (addr, addr+length) in the user space for our process. But, in addition to that, a section of a file between (offset, offset+length) is mapped into this linear region and can be seen by our process as a linear array.

On success, mmap returns a pointer to the start of the mapped area. On failure, it returns (void *) -1

PROCESSES vs. THREADS

http://www.csc.villanova.edu/~mdamian/threads/posixthreads.html
https://blog.wayofthepie.dev/linux/linux-procs-and-threads/
http://lemuria.cis.vtc.edu/~pchapin/TutorialPthread/pthread-Tutorial.pdf
https://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html

PROCESS AND THREAD CREATION

All processes and threads are created by three system calls: clone, fork and vfork. We will investigate them below.

CLONE

Unlike fork(2), clone allows the child process to share parts of its execution context with the calling process

The signature of this system call is:

int clone (int (*fn)(void *arg), void *child_stack, int flags,
	      void *arg, pid_t *parent_tid, void *tls, pid_t *child_tid );
  • int (*fn)(void *arg) is a pointer to a function that will do the work in the thread
  • void *child_stack is a pointer to the top of the stack for the thread,
  • int flags are the flags for this clone call (more on those later),
  • void *arg is a pointer to an argument to pass to this thread.
  • pid_t parent_tid, child_tid: parent and child thread id.
  • void* tls: thread local storage.