Clone: (compare to fork(): need more parameters (which mem to copy, func_addr to start) —system call to create a copy of the calling thread —new thread —CLONE_VM(from man clone): If CLONE_VM is set, the calling process and the child process run in the same memory space. In particular, memory writes per‐ formed by the calling process or by the child process are also visible in the other process. Moreover, any memory mapping or unmapping performed with mmap(2) or munmap(2) by the child or calling process also affects the other process. If CLONE_VM is not set, the child process runs in a separate copy of the memory space of the calling process at the time of clone(). Memory writes or file mappings/unmappings performed by one of the processes do not affect the other, as with fork(2) How to make a system call: inside libc: for example read(fd, addr, size): eax <— SYS_CALL_NUMBER ebx <— arg1 ecx <— arg1 … <— arg1 … <— arg1 int 0x80 for int 0x80: There’s a table: IVT(Interrupt Vector Table): 0x0 addr0 0x1 addr1 . . . . 0x80 addr80 . . . . At 0x80, the addr80 is the signal_handler for 0x80, and it might looks like: int handle_sys_call(){ { … if (eax == SYS_READ) { … sys_read(get value from registers); … } … } eax <— return value ( For return value, kernel has -4096 < return_value < 0 for failed system calls, but libc will wrap it into errno, and return -1 instead) At the interruption, current process will be suspended(save the context) and switch to the handler. (Handler uses kernel stack, not the callers) We usually don’t call clone() directly. The Pthread library calls it for us when we call pthread_create. Thread — pthread(create, join, exit) — TCB (thread control block) (from wiki) (TCB) is a data structure in the operating system kernel which contains thread-specific information needed to manage it. The TCB is "the manifestation of a thread in an operating system". An example of information contained within a TCB is: Stack pointer: Points to thread's stack in the process. — TLS (thread local storage) (from wiki) (TLS) is the method by which each thread in a given multithreaded process can allocate locations in which to store thread-specific data. Dynamically bound (run-time) thread-specific data is supported by way of the TLS API (TlsAlloc, TlsGetValue, TlsSetValue, and TlsFree). If we want threads have some global vars and their values can be different in different threads(and only that thread itself can access its value), how can we do? use global array, like int x[SIZE]; … x[tid] += 1 cons: Each thread will have access to other thread’s value 2. (inside libc), have a map for different thread_ids and their corresponding addresses. To use this method: __thread int x = 2; This will make x private inside the thread, libc will handle the map stuff, find the real address Some knowledge about auto/static/register/extern auto: defines a local variable as having a local lifetime static: A static global variable or a function is "seen" only in the file it's declared in. register: The register keyword in C (rarely ever seen anymore) is only a hint to the compiler that it may be useful to keep a variable in a register for faster access. extern: useful when need variable in another file. Example for extern: In file a.c: int x = 0; (declaration, definition, initialization) in file b.c: extern int x; (declaration) (Only one definition, maybe more dec) Compiler will figure out where x is, if a and b are linked, when compiling. All threads share the same VM. ----------------------------------------- | text | ----------------------------------------- | data | ----------------------------------------- | ... | ----------------------------------------- | ... | ----------------------------------------- | stack_thread1 | ----------------------------------------- | ... | ----------------------------------------- | stack_thread2 | ----------------------------------------- | ... | ----------------------------------------- | stack_thread2 | ----------------------------------------- | ... | ----------------------------------------- | stack | ----------------------------------------- Each thread has its own stack: Stack_thread frame: ----------------------------------------- |(Child_thread) (content in its stack) | ----------------------------------------- | TLS | ----------------------------------------- | TCB | ----------------------------------------- There’s difference between pthread_id and thread_id pthread id (pthread_t), maintained by libc, local to the process, to get: pthread_self. thread id (TID), maintained by kernel, unique in whole OS, to get: 1. use assembly code. (Not sure about the detail) 2. syscall(sys_gettid) Try print getpid() and syscall(sys_getpid) after restarted from the checkpoint in hw1, they should be different, libc will buffer the pid(There are other things that different after the restarting).