Skip to content

Latest commit

 

History

History
352 lines (308 loc) · 29.7 KB

curriculum.md

File metadata and controls

352 lines (308 loc) · 29.7 KB

Curriculum: Linux System Programming, chapter by chapter

The curriculum walks through Linux System Programming (2nd edition, Robert Love) one chapter at a time. Every exercise cites the book section it drills, so the exercises can be read alongside the book.

Total exercises: 140 across 12 chapters.

Chapter 1: Introduction and Essential Concepts (00_introduction)

Book pages 1-24.

Exercise Objective Book section
00_introduction/01_write_syscall Write bytes to a file descriptor with write(2) and handle a short write. Ch. 1, System Calls and the C Library (pp. 3-4)
00_introduction/02_errno_strerror Read errno after a failed open() and describe it with strerror(). Ch. 1, Error Handling (pp. 21-23)
00_introduction/03_errno_saved Keep the errno value from a failed call before other calls overwrite it. Ch. 1, Error Handling (pp. 21-23)
00_introduction/04_permission_bits Turn st_mode permission bits into an ls-style rwx string. Ch. 1, Permissions (pp. 19-20)
00_introduction/05_user_group_ids Report the real and effective user and group IDs of the process. Ch. 1, Users and Groups (pp. 18-19)
00_introduction/06_process_ids Collect the IDs that place a process in the system hierarchy. Ch. 1, Processes and the process hierarchy (pp. 16-18)
00_introduction/07_file_types Tell regular files, directories, and symbolic links apart. Ch. 1, Files and the Filesystem (pp. 10-16)
00_introduction/08_errno_classification Map the errno values from Table 1-2 onto a retry strategy. Ch. 1, Error Handling (pp. 21-23)
00_introduction/09_sysconf_limits Query runtime limits with sysconf() and detect its error return. Ch. 1, Getting Started with System Programming (pp. 24)
00_introduction/10_hard_and_soft_links Create both kinds of link and inspect what each one points at. Ch. 1, Hard links and Symbolic links (pp. 12-14)

Chapter 2: File I/O (01_file_io)

Book pages 25-66.

Exercise Objective Book section
01_file_io/01_open_flags Create a file atomically with O_CREAT and O_EXCL. Ch. 2, Opening Files and the flags for open (pp. 26-31)
01_file_io/02_umask_and_modes See how the process umask clears bits from the mode passed to open(). Ch. 2, Permissions of New Files (pp. 31-33)
01_file_io/03_creat_and_truncate Create an empty file with creat() and empty an existing one with O_TRUNC. Ch. 2, The creat() Function (pp. 33-34)
01_file_io/04_read_all Loop over read() until the requested length or end-of-file. Ch. 2, Reading All the Bytes (pp. 35-36)
01_file_io/05_eintr_and_eagain Retry read() on EINTR and report EAGAIN as not-ready instead of failing. Ch. 2, Nonblocking Reads and Other Error Values (pp. 36-38)
01_file_io/06_append_mode Use O_APPEND so every write lands at the current end of the file. Ch. 2, Append Mode (pp. 41-42)
01_file_io/07_synchronized_io Flush a file descriptor's data with fsync() and fdatasync(). Ch. 2, Synchronized I/O and the O_SYNC flag (pp. 44-48)
01_file_io/08_lseek Move the file position with SEEK_SET, SEEK_CUR, and SEEK_END. Ch. 2, Seeking with lseek (pp. 49-52)
01_file_io/09_pread_pwrite Read and write at an absolute offset without moving the file position. Ch. 2, Positional Reads and Writes (pp. 52-53)
01_file_io/10_ftruncate Resize an open file with ftruncate() and notice that extension adds zeros. Ch. 2, Truncating Files (pp. 53-54)
01_file_io/11_poll Wait for readability on a descriptor with poll(). Ch. 2, Multiplexed I/O (pp. 54-62)
01_file_io/12_select Build a descriptor set and wait for one of its members to become readable. Ch. 2, Multiplexed I/O and pselect (pp. 54-62)
01_file_io/13_cloexec Set and query the FD_CLOEXEC flag with fcntl() and O_CLOEXEC. Ch. 2, Flags for open (O_CLOEXEC) (pp. 27-28)

Chapter 3: Buffered I/O (02_buffered_io)

Book pages 67-90.

Exercise Objective Book section
02_buffered_io/01_stream_open_modes Use the fopen() modes for reading, truncating, and appending. Ch. 3, Opening Files and Modes (pp. 71-72)
02_buffered_io/02_fdopen_and_fileno Attach a stream to an existing descriptor and get it back with fileno(). Ch. 3, Opening a Stream via File Descriptor (pp. 72-73)
02_buffered_io/03_user_buffering See that a small write stays in the stream buffer until fflush(). Ch. 3, User-Buffered I/O and Block Size (pp. 69-70)
02_buffered_io/04_fgetc_fputc Read with fgetc() until EOF and write with fputc(). Ch. 3, Reading a Character at a Time and Writing a Single Character (pp. 74-78)
02_buffered_io/05_ungetc Use ungetc() to look one character ahead without losing it. Ch. 3, Reading a Character at a Time (pp. 74-75)
02_buffered_io/06_fgets_lines Read whole lines and notice the newline that fgets() keeps. Ch. 3, Reading an Entire Line (pp. 75-76)
02_buffered_io/07_fread_fwrite Move an array of structures in and out of a file in binary form. Ch. 3, Reading Binary Data and Writing Binary Data (pp. 76-79)
02_buffered_io/08_fseek_ftell Measure a stream with fseek/ftell and restore a position with fgetpos/fsetpos. Ch. 3, Seeking a Stream and Obtaining the Current Stream Position (pp. 79-82)
02_buffered_io/09_setvbuf_unbuffered Switch a stream to _IONBF and watch the bytes reach the file at once. Ch. 3, Controlling the Buffering (pp. 84-86)
02_buffered_io/10_feof_ferror_clearerr Tell end-of-file and errors apart with feof(), ferror(), and clearerr(). Ch. 3, Errors and End-of-File (pp. 82-83)
02_buffered_io/11_fileno_raw_mix Flush a stream and then read the same bytes through its descriptor. Ch. 3, Obtaining the Associated File Descriptor and Critiques of Standard I/O (pp. 83-90)
02_buffered_io/12_line_buffering Request line buffering and see the buffer flushed at each newline. Ch. 3, Controlling the Buffering (pp. 84-86)
02_buffered_io/13_stream_locking Hold the stream lock while reading a line with getc_unlocked(). Ch. 3, Thread Safety and Unlocked Stream Operations (pp. 86-88)
02_buffered_io/14_manual_file_locking Lock a whole file with flock() and a region with lockf(). Ch. 3, Manual File Locking (pp. 86-89)

Chapter 4: Advanced File I/O (03_advanced_file_io)

Book pages 91-136.

Exercise Objective Book section
03_advanced_file_io/01_writev_readv Move several buffers with one readv() or writev() call. Ch. 4, Scatter/Gather I/O (pp. 92-97)
03_advanced_file_io/02_epoll_basic Create an epoll instance, register a descriptor, and wait for it. Ch. 4, Event Poll (pp. 97-104)
03_advanced_file_io/03_epoll_ctl Use EPOLL_CTL_MOD and EPOLL_CTL_DEL and read their error codes. Ch. 4, Controlling Epoll (pp. 98-101)
03_advanced_file_io/04_epoll_edge_triggered Ask for EPOLLET and notice that unread data does not retrigger. Ch. 4, Edge- Versus Level-Triggered Events (pp. 103-104)
03_advanced_file_io/05_mmap_read Read a whole file through a mapping and treat its bytes as unsigned. Ch. 4, Mapping Files into Memory (pp. 104-109)
03_advanced_file_io/06_mmap_shared_write Change file contents through MAP_SHARED and sync the mapping. Ch. 4, mmap and Synchronizing a File with a Mapping (pp. 104-114)
03_advanced_file_io/07_mprotect Change mapped memory with mprotect() and read its error code. Ch. 4, Changing the Protection of a Mapping (pp. 112-113)
03_advanced_file_io/08_mremap Grow a mapping with mremap() and keep the old contents. Ch. 4, Resizing a Mapping (pp. 111-112)
03_advanced_file_io/09_posix_fadvise Tell the kernel how a file will be accessed with posix_fadvise(). Ch. 4, The posix_fadvise System Call (pp. 118-120)
03_advanced_file_io/10_posix_fallocate Preallocate file space with posix_fallocate() and check its status. Ch. 4, Advice for Normal File I/O (pp. 118-121)
03_advanced_file_io/11_mmap_private_vs_shared See that only a shared mapping writes through to the file. Ch. 4, mmap and Advantages and Disadvantages of mmap (pp. 104-111)

Chapter 5: Process Management (04_process_management)

Book pages 137-176.

Exercise Objective Book section
04_process_management/01_child_pid_and_ppid Observe that a child's parent PID is the PID of the process that forked it. Ch. 5, Programs, Processes, and Threads (pp. 137-140)
04_process_management/02_fork_return_value Recognize the three values fork() can return. Ch. 5, The fork System Call (pp. 145-148)
04_process_management/03_exec_family Replace a child's image with execvp() and report its exit status. Ch. 5, The Exec Family of Calls (pp. 140-145)
04_process_management/04_exit_status_decoding Tell a normal exit and a signal death apart with the W* macros. Ch. 5, Terminating a Process and Waiting for Terminated Child Processes (pp. 148-154)
04_process_management/05_wait_and_waitpid Reap a child with wait() and poll one with waitpid(WNOHANG). Ch. 5, Waiting for Terminated Child Processes (pp. 151-156)
04_process_management/06_zombies_and_waitid Inspect a terminated child with WNOWAIT and reap it afterwards. Ch. 5, Zombies and Even More Waiting Versatility (pp. 156-163)
04_process_management/07_exit_and_underscore_exit See that _exit() skips the stdio flush that exit() performs. Ch. 5, Terminating a Process (pp. 148-151)
04_process_management/08_atexit_order See that atexit handlers run in reverse order of registration. Ch. 5, atexit and on_exit (pp. 149-151)
04_process_management/09_real_effective_ids Read all three user IDs and change the effective one. Ch. 5, Real, Effective, and Saved User and Group IDs (pp. 163-167)
04_process_management/10_process_groups Put a child into a process group of its own with setpgid(). Ch. 5, Sessions and Process Groups (pp. 167-172)
04_process_management/11_new_session Call setsid() in a child and confirm the child leads a new session. Ch. 5, Session System Calls and Daemons (pp. 167-175)
04_process_management/12_exec_environment Give a new program its own environment with execve(). Ch. 5, The Exec Family of Calls (pp. 140-145)

Chapter 6: Advanced Process Management (05_advanced_processes)

Book pages 177-210.

Exercise Objective Book section
05_advanced_processes/01_yielding Hand the processor back with sched_yield() at the right moment. Ch. 6, Yielding the Processor and Legitimate Uses (pp. 181-183)
05_advanced_processes/02_nice_values Use getpriority() and setpriority() and handle the -1 return value. Ch. 6, Process Priorities and nice (pp. 183-186)
05_advanced_processes/03_nice_a_child Change the priority of a child before it finishes. Ch. 6, getpriority and setpriority (pp. 184-186)
05_advanced_processes/04_processor_affinity Read, restrict, and restore a process's CPU affinity mask. Ch. 6, Processor Affinity (pp. 186-190)
05_advanced_processes/05_scheduling_policies Ask which policy a process uses and what priorities that policy accepts. Ch. 6, Linux Scheduling Policies and Priorities (pp. 192-199)
05_advanced_processes/06_round_robin_interval Fetch a process's round-robin interval and convert its units. Ch. 6, sched_rr_get_interval (pp. 199-201)
05_advanced_processes/07_getrlimit Inspect soft and hard limits with getrlimit(). Ch. 6, Resource Limits (pp. 204-209)
05_advanced_processes/08_setrlimit Lower the soft limit of the current process and restore it afterwards. Ch. 6, Setting and Retrieving Limits (pp. 205-209)
05_advanced_processes/09_filesize_limit See RLIMIT_FSIZE stop a child that writes past the limit. Ch. 6, The Limits (pp. 204-209)

Chapter 7: Threading (06_threading)

Book pages 211-240.

Exercise Objective Book section
06_threading/01_create_and_join Run work on a second thread and collect the result after pthread_join(). Ch. 7, The Pthread API and Creating Threads (pp. 226-230)
06_threading/02_thread_ids Compare thread identifiers with pthread_equal(). Ch. 7, Thread IDs (pp. 229-230)
06_threading/03_thread_arguments Pass a struct to a thread and hand a value back through pthread_join(). Ch. 7, Creating Threads and Joining and Detaching Threads (pp. 227-234)
06_threading/04_detached_threads Create a detached thread and see that it cannot be joined. Ch. 7, Joining and Detaching Threads (pp. 233-234)
06_threading/05_mutex_counter Protect a shared counter with a mutex and check the pthread return values. Ch. 7, Synchronization and Pthread Mutexes (pp. 222-239)
06_threading/06_trylock Use pthread_mutex_trylock() to report whether a lock is held. Ch. 7, Mutexes and Deadlocks (pp. 222-226)
06_threading/07_condition_variable Block a thread until another thread signals that the data is ready. Ch. 7, Synchronization and Pthreads (pp. 218-239)
06_threading/08_pthread_once Run an initialization exactly once, no matter how many threads ask. Ch. 7, The Pthread API (pp. 227-228)
06_threading/09_thread_specific_data Give each thread its own value with a thread-specific data key. Ch. 7, Further Study and the Pthread API (pp. 228-239)
06_threading/10_thread_cancellation Cancel a running thread and recognize PTHREAD_CANCELED when joining it. Ch. 7, Terminating Threads (pp. 230-233)

Chapter 8: File and Directory Management (07_files_directories)

Book pages 241-292.

Exercise Objective Book section
07_files_directories/01_stat_family Describe a file by path and by descriptor, and keep the type bits in st_mode. Ch. 8, The Stat Family (pp. 241-246)
07_files_directories/02_permissions Set permissions by path with chmod() and by descriptor with fchmod(). Ch. 8, Permissions (pp. 246-248)
07_files_directories/03_ownership Read a file's owner and see which chown() calls an ordinary user may make. Ch. 8, Ownership (pp. 248-250)
07_files_directories/04_extended_attributes Attach, read, test, and remove a user extended attribute. Ch. 8, Extended Attributes and Extended Attribute Operations (pp. 250-253)
07_files_directories/05_working_directory Read and change the process working directory with getcwd() and chdir(). Ch. 8, The Current Working Directory (pp. 260-265)
07_files_directories/06_creating_directories Create directories with mkdir() and remove empty ones with rmdir(). Ch. 8, Creating and Removing Directories (pp. 265-268)
07_files_directories/07_reading_a_directory Walk a directory stream with opendir(), readdir(), and closedir(). Ch. 8, Reading a Directory's Contents (pp. 268-271)
07_files_directories/08_symbolic_links Create a symbolic link, read its target, and detect a dangling link. Ch. 8, Symbolic Links and Unlinking (pp. 273-277)
07_files_directories/09_hard_links Give one inode a second name and watch st_nlink change. Ch. 8, Hard Links (pp. 271-273)
07_files_directories/10_copying_and_moving Copy a file by hand and move it with rename(). Ch. 8, Copying and Moving Files (pp. 277-280)
07_files_directories/11_device_nodes Recognize character devices and use /dev/null and /dev/urandom. Ch. 8, Device Nodes and The Random Number Generator (pp. 280-281)
07_files_directories/12_out_of_band_data Ask a descriptor how many bytes are waiting with ioctl(FIONREAD). Ch. 8, Out-of-Band Communication (pp. 281-283)
07_files_directories/13_inotify Create an inotify instance, watch a directory, and read the events it reports. Ch. 8, Monitoring File Events (pp. 283-292)

Chapter 9: Memory Management (08_memory_management)

Book pages 293-332.

Exercise Objective Book section
08_memory_management/01_address_space Read /proc/self/maps and count the memory regions it lists. Ch. 9, The Process Address Space and Memory Regions (pp. 293-296)
08_memory_management/02_malloc_and_free Allocate an array on the heap, use it, and release it exactly once. Ch. 9, Allocating Dynamic Memory (pp. 296-301)
08_memory_management/03_calloc_zeroes Ask for zeroed memory and see the difference from a recycled block. Ch. 9, Allocating Arrays (pp. 298-299)
08_memory_management/04_realloc_growth Grow a block with realloc() and initialize only the new elements. Ch. 9, Resizing Allocations (pp. 299-301)
08_memory_management/05_free_and_clear Release a block and clear the caller's pointer, remembering that free(NULL) is fine. Ch. 9, Freeing Dynamic Memory (pp. 301-303)
08_memory_management/06_alignment Allocate memory with an alignment requirement and verify it. Ch. 9, Alignment (pp. 303-307)
08_memory_management/07_allocator_queries Ask how big an allocated block really is and trim the heap. Ch. 9, Fine-Tuning with malloc_usable_size and malloc_trim (pp. 314-315)
08_memory_management/08_program_break Move the end of the data segment with sbrk() and put it back with brk(). Ch. 9, Managing the Data Segment (pp. 307-308)
08_memory_management/09_anonymous_mappings Get zeroed memory with MAP_ANONYMOUS and with a mapping of /dev/zero. Ch. 9, Anonymous Memory Mappings and Mapping /dev/zero (pp. 308-311)
08_memory_management/10_stack_allocations Copy a string with alloca() and use a variable-length array. Ch. 9, Stack-Based Allocations and Variable-Length Arrays (pp. 316-320)
08_memory_management/11_memory_functions Use memset, memchr, memmove, and memfrob on raw bytes. Ch. 9, Manipulating Memory (pp. 321-325)
08_memory_management/12_locking_memory Pin a mapping with mlock() and query it with mincore(). Ch. 9, Locking Memory and Is a Page in Physical Memory (pp. 325-329)

Chapter 10: Signals (09_signals)

Book pages 333-362.

Exercise Objective Book section
09_signals/01_signal_identifiers Recognize signal numbers and the two signals that cannot be caught. Ch. 10, Signal Identifiers and Basic Signal Management (pp. 334-345)
09_signals/02_signal_handlers Install a handler with sigaction() and watch raise() run it. Ch. 10, Basic Signal Management (pp. 340-341)
09_signals/03_sigaction_with_info Receive the siginfo_t structure by requesting SA_SIGINFO. Ch. 10, Advanced Signal Management and The siginfo_t Structure (pp. 355-361)
09_signals/04_signal_sets Build and inspect signal sets with the sigset_t helpers. Ch. 10, Signal Sets and More Signal Set Functions (pp. 350-351)
09_signals/05_blocking_signals Block a signal, see it become pending, and watch it arrive when unblocked. Ch. 10, Blocking Signals and Retrieving Pending Signals (pp. 351-353)
09_signals/06_sigsuspend Wait for a signal atomically by replacing the signal mask with sigsuspend(). Ch. 10, Waiting for a Set of Signals (pp. 353-355)
09_signals/07_sigwait Block a signal and collect it synchronously with sigwait(). Ch. 10, Waiting for a Set of Signals (pp. 353-355)
09_signals/08_sending_signals Kill a child process and test for a process's existence with signal 0. Ch. 10, Sending a Signal and Examples (pp. 346-348)
09_signals/09_signal_permissions Send signals to yourself and check the error codes kill() reports. Ch. 10, Sending a Signal and Permissions (pp. 346-347)
09_signals/10_signal_inheritance Ignore a signal in the parent and see the child ignore it too. Ch. 10, Execution and Inheritance (pp. 344-345)
09_signals/11_sigqueue_payload Carry an integer with sigqueue() and read it from si_value. Ch. 10, Sending a Signal with a Payload (pp. 361-362)
09_signals/12_async_signal_safety Write a byte to a pipe from a handler, because write() is async-signal-safe. Ch. 10, Reentrancy and Guaranteed-Reentrant Functions (pp. 348-350)

Chapter 11: Time (10_time)

Book pages 363-394.

Exercise Objective Book section
10_time/01_time_types Read the time of day as a timeval and convert a timespec to microseconds. Ch. 11, Time's Data Structures (pp. 366-367)
10_time/02_breaking_down_time Turn a time_t into calendar fields with gmtime_r() and format them. Ch. 11, Breaking Down Time (pp. 367-368)
10_time/03_parsing_time Write a local timestamp with strftime() and read it back with strptime(). Ch. 11, Breaking Down Time and Playing with Time (pp. 367-380)
10_time/04_process_time Measure consumed CPU time with clock() and times(). Ch. 11, A Type for Process Time (pp. 368-370)
10_time/05_monotonic_clock Read CLOCK_REALTIME and CLOCK_MONOTONIC and see that the second never runs backwards. Ch. 11, POSIX Clocks and Getting the Current Time of Day (pp. 369-374)
10_time/06_clock_resolution Ask each clock how precisely it can be read. Ch. 11, Time Source Resolution (pp. 370-371)
10_time/07_process_cpu_clock Use CLOCK_PROCESS_CPUTIME_ID and see it ignore time spent sleeping. Ch. 11, A Type for Process Time and POSIX Clocks (pp. 368-372)
10_time/08_sleeping Sleep for a duration and restart the sleep when a signal interrupts it. Ch. 11, Sleeping with Nanosecond Resolution (pp. 383-385)
10_time/09_alarm Arm and cancel an alarm, and read back the time that was left. Ch. 11, Simple Alarms (pp. 386-387)
10_time/10_interval_timers Arm a timer with setitimer() and inspect it with getitimer(). Ch. 11, Interval Timers (pp. 387-389)
10_time/11_posix_timers Create a timer with timer_create(), arm it, and wait for its signal. Ch. 11, Advanced Timers (pp. 389-394)
10_time/12_absolute_sleep Wait until an absolute time with clock_nanosleep(). Ch. 11, An Advanced Approach to Sleep and Overruns (pp. 385-386)

Chapter A: GCC Extensions to the C Language (11_gcc_extensions)

Book pages 395-406.

Exercise Objective Book section
11_gcc_extensions/01_inline_functions Ask the compiler to inline a small function with always_inline. Appendix A, Inline Functions (pp. 395-400)
11_gcc_extensions/02_pure_and_const_functions Mark functions that only depend on their arguments or on memory. Appendix A, Pure Functions and Constant Functions (pp. 400-403)
11_gcc_extensions/03_noreturn_functions Mark a function noreturn and see the child process exit with its status. Appendix A, Functions That Do Not Return (pp. 400-401)
11_gcc_extensions/04_allocation_attributes Hint at fresh memory with the malloc attribute and insist on using results. Appendix A, Functions That Allocate Memory and Forcing Callers to Check the Return Value (pp. 401-403)
11_gcc_extensions/05_typeof Build type-generic macros with typeof and statement expressions. Appendix A, Getting the Type of an Expression (pp. 405-406)
11_gcc_extensions/06_packed_and_aligned Remove struct padding with packed and raise a type's alignment with aligned. Appendix A, Packing a Structure and Increasing the Alignment of a Variable (pp. 403-405)
11_gcc_extensions/07_offsetof_and_alignof Report member offsets and type alignment with offsetof and alignof. Appendix A, Getting the Alignment of a Type and The Offset of a Member Within a Structure (pp. 407-415)
11_gcc_extensions/08_case_ranges Use a GNU case range to classify characters in one case label. Appendix A, Case Ranges (pp. 415-417)
11_gcc_extensions/09_branch_annotation Tell the compiler which side of a branch is likely with __builtin_expect. Appendix A, Branch Annotation and Placing Global Variables in a Register (pp. 405-408)
11_gcc_extensions/10_void_pointer_arithmetic Step a void pointer by bytes, the GNU C way. Appendix A, Void and Function Pointer Arithmetic (pp. 418-420)
11_gcc_extensions/11_return_address Ask for the address a function will return to. Appendix A, Obtaining the Return Address of a Function (pp. 415-416)
11_gcc_extensions/12_deprecated_and_unused Mark an old entry point deprecated and keep a helper without warnings. Appendix A, Marking Functions as Deprecated, Used, or Unused (pp. 403-405)

Cross-cutting knowledge checklist

The following Linux and POSIX areas are covered by the exercises and the supporting documentation:

  • System calls versus the C library, APIs versus ABIs, the POSIX/SUS/C standards story, and Linux header conventions (_POSIX_C_SOURCE, feature-test macros).
  • errno, error reporting, strerror, and save/restore of errno across intervening library calls.
  • File descriptors, the per-process file table, and fd lifetime through open, read, write, close, dup, and lseek.
  • open() flags (O_CREAT, O_EXCL, O_TRUNC, O_APPEND, O_CLOEXEC, O_SYNC, O_DIRECT), creat(), file mode bits, and umask.
  • Partial reads and writes, EINTR retry loops, nonblocking I/O and EAGAIN, append-mode atomicity, and short writes.
  • Synchronized I/O: fsync, fdatasync, sync, syncfs.
  • pread/pwrite, truncate/ftruncate, sparse files, and seeking past end-of-file.
  • Multiplexed I/O with select, pselect, and poll.
  • User-buffered and standard I/O: block size, setvbuf, fflush, fread/fwrite, fgets, fseek/ftell, fgetpos/fsetpos, feof/ferror/clearerr, and fileno/fdopen.
  • Stream locking: flockfile, ftrylockfile, funlockfile, and the getc_unlocked/putc_unlocked family.
  • Scatter/gather I/O with readv and writev.
  • epoll: epoll_create1, epoll_ctl, epoll_wait, and edge- versus level-triggered event notification.
  • Memory mapping: mmap, munmap, mprotect, msync, mremap, MAP_SHARED versus MAP_PRIVATE, and file-backed mappings.
  • I/O advice and prefetch: posix_fadvise, readahead, and posix_fallocate.
  • Programs, processes, and threads; pid_t; the process hierarchy; getpid, getppid, getpgrp/getpgid/getsid.
  • The exec family and fork() semantics.
  • Process termination: exit, _exit, atexit, on_exit, wait, waitpid, waitid, SIGCHLD, and zombies.
  • Users and groups: real, effective, and saved IDs; the setuid family and privileged helpers.
  • Sessions, process groups, job control, and daemonization.
  • Scheduling: nice, getpriority/setpriority, sched_yield, the CFS, and CPU affinity.
  • Real-time policies: SCHED_FIFO, SCHED_RR, SCHED_BATCH, SCHED_IDLE, sched_setscheduler, and priority ranges.
  • Resource limits: getrlimit/setrlimit, RLIMIT_*, and prlimit.
  • Pthreads: pthread_create, pthread_join, pthread_detach, pthread_self, pthread_equal, pthread_exit, and pthread_cancel.
  • Races, mutexes, condition variables, and thread-safe code.
  • File metadata: stat/fstat/lstat, st_mode decoding, chmod, fchmod, umask, chown, and utime.
  • Extended attributes: setxattr, getxattr, listxattr.
  • Directories: getcwd, chdir, mkdir, rmdir, opendir, readdir, closedir, and dirfd.
  • Links: link, unlink, symlink, readlink, rename, and copying files.
  • Device nodes, /dev/urandom, and out-of-band data.
  • inotify: instances, watch descriptors, event masks, and monitoring file events.
  • The process address space, pages, memory regions, and /proc/self/maps.
  • Dynamic memory: malloc, calloc, realloc, free, posix_memalign, malloc_usable_size, and allocator statistics.
  • brk/sbrk, anonymous memory mappings, MAP_ANONYMOUS, and /dev/zero mappings.
  • Stack allocation: alloca, variable-length arrays, and when each allocation mechanism is appropriate.
  • Memory manipulation: memset, memcmp, memmove, memchr, and memfrob.
  • Locking memory: mlock, mlockall, munlock, mincore, and RLIMIT_MEMLOCK.
  • Signals: signal identifiers, signal versus sigaction, handlers, execution and inheritance, and strsignal.
  • Sending signals: kill, raise, killpg, permissions, and sigqueue payloads.
  • Signal sets (sigemptyset, sigfillset, sigaddset, sigismember), blocking with sigprocmask, sigpending, sigsuspend, sigwait, and sigtimedwait.
  • Reentrancy and async-signal-safe functions.
  • Advanced signal handling: siginfo_t, si_code, SA_SIGINFO, SA_RESTART, and interrupted system calls.
  • Time types: time_t, struct timeval, struct timespec, clockid_t, and CLOCKS_PER_SEC.
  • Clocks: clock_gettime, clock_getres, CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, and times().
  • Formatting and parsing time: ctime, gmtime, localtime, strftime, strptime, mktime, and difftime.
  • Sleeping: sleep, usleep, nanosleep, clock_nanosleep, select as a portable sleep, and overruns.
  • Timers: alarm, setitimer/getitimer, and POSIX timers (timer_create, timer_settime, timer_delete).
  • The GCC extensions real system code relies on: typeof, statement expressions, __attribute__, __builtin_*, case ranges, zero-length arrays, computed goto, __thread, and __attribute__((cleanup)).

Suggested learning path

  1. 00_introduction - errno, headers, file types, IDs.
  2. 01_file_io and 02_buffered_io - the two I/O vocabularies.
  3. 03_advanced_file_io - readv, epoll, and mmap.
  4. 04_process_management and 05_advanced_processes.
  5. 06_threading - pthreads, mutexes, and races.
  6. 07_files_directories - metadata, links, directories, inotify.
  7. 08_memory_management - the address space and the allocator.
  8. 09_signals - handlers, sets, sigaction, and payloads.
  9. 10_time - clocks, sleeping, and timers.
  10. 11_gcc_extensions - the GNU C that the kernel and glibc are written in.

Do not read the solutions until you have run the exercise and looked at the compiler or test output. The point is to learn the feedback loop, not to collect green checkmarks.