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.
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) |
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) |
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) |
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) |
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) |
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) |
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) |
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) |
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) |
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) |
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) |
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) |
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 oferrnoacross intervening library calls.- File descriptors, the per-process file table, and fd lifetime
through
open,read,write,close,dup, andlseek. open()flags (O_CREAT,O_EXCL,O_TRUNC,O_APPEND,O_CLOEXEC,O_SYNC,O_DIRECT),creat(), file mode bits, andumask.- Partial reads and writes,
EINTRretry loops, nonblocking I/O andEAGAIN, 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, andpoll. - User-buffered and standard I/O: block size,
setvbuf,fflush,fread/fwrite,fgets,fseek/ftell,fgetpos/fsetpos,feof/ferror/clearerr, andfileno/fdopen. - Stream locking:
flockfile,ftrylockfile,funlockfile, and thegetc_unlocked/putc_unlockedfamily. - Scatter/gather I/O with
readvandwritev. epoll:epoll_create1,epoll_ctl,epoll_wait, and edge- versus level-triggered event notification.- Memory mapping:
mmap,munmap,mprotect,msync,mremap,MAP_SHAREDversusMAP_PRIVATE, and file-backed mappings. - I/O advice and prefetch:
posix_fadvise,readahead, andposix_fallocate. - Programs, processes, and threads;
pid_t; the process hierarchy;getpid,getppid,getpgrp/getpgid/getsid. - The
execfamily andfork()semantics. - Process termination:
exit,_exit,atexit,on_exit,wait,waitpid,waitid,SIGCHLD, and zombies. - Users and groups: real, effective, and saved IDs; the
setuidfamily 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_*, andprlimit. - Pthreads:
pthread_create,pthread_join,pthread_detach,pthread_self,pthread_equal,pthread_exit, andpthread_cancel. - Races, mutexes, condition variables, and thread-safe code.
- File metadata:
stat/fstat/lstat,st_modedecoding,chmod,fchmod,umask,chown, andutime. - Extended attributes:
setxattr,getxattr,listxattr. - Directories:
getcwd,chdir,mkdir,rmdir,opendir,readdir,closedir, anddirfd. - 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/zeromappings.- Stack allocation:
alloca, variable-length arrays, and when each allocation mechanism is appropriate. - Memory manipulation:
memset,memcmp,memmove,memchr, andmemfrob. - Locking memory:
mlock,mlockall,munlock,mincore, andRLIMIT_MEMLOCK. - Signals: signal identifiers,
signalversussigaction, handlers, execution and inheritance, andstrsignal. - Sending signals:
kill,raise,killpg, permissions, andsigqueuepayloads. - Signal sets (
sigemptyset,sigfillset,sigaddset,sigismember), blocking withsigprocmask,sigpending,sigsuspend,sigwait, andsigtimedwait. - 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, andCLOCKS_PER_SEC. - Clocks:
clock_gettime,clock_getres,CLOCK_REALTIME,CLOCK_MONOTONIC,CLOCK_PROCESS_CPUTIME_ID, andtimes(). - Formatting and parsing time:
ctime,gmtime,localtime,strftime,strptime,mktime, anddifftime. - Sleeping:
sleep,usleep,nanosleep,clock_nanosleep,selectas 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, computedgoto,__thread, and__attribute__((cleanup)).
00_introduction-errno, headers, file types, IDs.01_file_ioand02_buffered_io- the two I/O vocabularies.03_advanced_file_io-readv,epoll, andmmap.04_process_managementand05_advanced_processes.06_threading- pthreads, mutexes, and races.07_files_directories- metadata, links, directories,inotify.08_memory_management- the address space and the allocator.09_signals- handlers, sets,sigaction, and payloads.10_time- clocks, sleeping, and timers.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.