Skip to content

阅读 Linux System Programming

cheyiliu edited this page Oct 15, 2014 · 12 revisions

写在前面

走马观花地看了一遍,重点针对自己不熟悉的概念,同时和一些常用api混个脸熟。

Preface

I recommend the following command to compile a source file:

$ gcc -Wall -Wextra -O2 -g -o snippet snippet.

This compiles the source file snippet.c into the executable binary snippet, enabling many warning checks, significant but sane optimizations, and debugging.

Chapter 1 Introduction and Essential Concepts

  • System calls (often shorted to syscalls) are function invocations made from user space—your text editor, favorite game, and so on—into the kernel (the core internals of the system) in order to request some service or resource from the operating system. System calls range from the familiar, such as read( ) and write( ), to the exotic, such as get_thread_area( ) and set_tid_address( ).

  • The C library (libc) is at the heart of Unix applications. Even when you’re programming in another language, the C library is most likely in play, wrapped by the higher-level libraries, providing core services, and facilitating system call invocation.

  • The C Compiler In Linux, the standard C compiler is provided by the GNU Compiler Collection (gcc).

  • APIs and ABIs

    • An API defines the interfaces by which one piece of software communicates with another at the source level. It provides abstraction by providing a standard set of interfaces—usually functions—that one piece of software (typically, although not necessarily, a higher-level piece) can invoke from another piece of software (usually a lower-level piece). It is common to call an API a “contract.” This is not correct, at least in the legal sense of the term, as an API is not a two-way agreement. The API user (generally, the higher-level software) has zero input into the API and its implementation. It may use the API as-is, or not use it at all: take it or leave it! The API acts only to ensure that if both pieces of software follow the API, they are source compatible; that is, that the user of the API will successfully compile against the implementation of the API.

    • an ABI defines the low-level binary inter- face between two or more pieces of software on a particular architecture. It defines how an application interacts with itself, how an application interacts with the kernel, and how an application interacts with libraries. An ABI ensures binary compatibility, guaranteeing that a piece of object code will function on any system with the same ABI, without requiring recompilation. ABIs are concerned with issues such as calling conventions, byte ordering, register use, system call invocation, linking, library behavior, and the binary object format. The calling convention, for example, defines how functions are invoked, how argu- ments are passed to functions, which registers are preserved and which are mangled, and how the caller retrieves the return value.

  • Standards xxx

  • Concepts of Linux Programming

    • Files and the Filesystem
    • Processes
    • Users and Groups
    • Permissions
    • Signals
Signals are a mechanism for one-way asynchronous notifications. A signal may be
sent from the kernel to a process, from a process to another process, or from a pro-
cess to itself. Signals typically alert a process to some event, such as a segmentation
fault, or the user pressing Ctrl-C.
  • Interprocess Communication
  • Headers
  • Error Handling

CHAPTER 2 File I/O

CHAPTER 3 Buffered I/O

CHAPTER 4 Advanced File I/O

Chapter 5 Process Management

  • Daemons

A daemon is a process that runs in the background, not connecting to any control-
ling terminal. Daemons are normally started at boot time, are run as root or some
other special user (such as apache or postfix), and handle system-level tasks. As a
convention, the name of a daemon often ends in d (as in crond and sshd), but this is
not required, or even universal.
The name derives from Maxwell’s demon, an 1867 thought experiment by the physi-
cist James Maxwell. Daemons are also supernatural beings in Greek mythology,
existing somewhere between humans and the gods and gifted with powers and divine
knowledge. Unlike the demons of Judeo-Christian lore, the Greek daemon need not
be evil. Indeed, the daemons of mythology tended to be aides to the gods, performing
tasks that the denizens of Mount Olympus found themselves unwilling to do—much
as Unix daemons perform tasks that foreground users would rather avoid.
A daemon has two general requirements: it must run as a child of init, and it must
not be connected to a terminal.
In general, a program performs the following steps to become a daemon:

  1. Call fork( ). This creates a new process, which will become the daemon.
  2. In the parent, call exit( ). This ensures that the original parent (the daemon’s
    grandparent) is satisfied that its child terminated, that the daemon’s parent is no
    longer running, and that the daemon is not a process group leader. This last
    point is a requirement for the successful completion of the next step.
  3. Call setsid( ), giving the daemon a new process group and session, both of
    which have it as leader. This also ensures that the process has no associated con-
    trolling terminal (as the process just created a new session, and will not assign
    one).
  4. Change the working directory to the root directory via chdir( ). This is done
    because the inherited working directory can be anywhere on the filesystem. Dae-
    mons tend to run for the duration of the system’s uptime, and you don’t want to
    keep some random directory open, and thus prevent an administrator from
    unmounting the filesystem containing that directory.
  5. Close all file descriptors. You do not want to inherit open file descriptors, and,
    unaware, hold them open.
  6. Open file descriptors 0, 1, and 2 (standard in, standard out, and standard error)
    and redirect them to /dev/null.
    Following these rules, here is a program that daemonizes itself:
#include
#include
#include
#include
#include
#include
#include
<sys/types.h>
<sys/stat.h>
<stdlib.h>
<stdio.h>
<fcntl.h>
<unistd.h>
<linux/fs.h>
int main (void)
{
pid_t pid;
int i;
/* create new process */
pid = fork ( );
if (pid == -1)
return -1;
else if (pid != 0)
exit (EXIT_SUCCESS);
/* create new session and process group */
if (setsid ( ) == -1)
return -1;
/* set the working directory to the root directory */
if (chdir ("/") == -1)
return -1;
/* close all open files--NR_OPEN is overkill, but works */
for (i = 0; i < NR_OPEN; i++)
close (i);
/* redirect fd's 0,1,2 to /dev/null */
open ("/dev/null", O_RDWR);
/* stdin */
dup (0);
/* stdout */
dup (0);
/* stderror */
/* do its daemon thing... */
return 0;
}

Most Unix systems provide a daemon( ) function in their C library that automates
these steps, turning the cumbersome into the simple:

#include <unistd.h>
int daemon (int nochdir, int noclose);

If nochdir is nonzero, the daemon will not change its working directory to the root
directory. If noclose is nonzero, the daemon will not close all open file descriptors.
These options are useful if the parent process already set up these aspects of the dae-
monizing procedure. Normally, though, one passes 0 for both of these parameters.
On success, the call returns 0. On failure, the call returns -1, and errno is set to a
valid error code from fork( ) or setsid( ).

Chapter 6 Advanced Process Management

Chapter 7 File and Directory bManagement

  • Monitoring File Events, android java端 FileObserver就是基于这个实现的。记一笔加深印象。

Chapter 8 Memory Management

Chapter 9 Signals

  • Signals are software interrupts that provide a mechanism for handling asynchronous events. These events can originate from outside the system—such as when the user generates the interrupt character (usually via Ctrl-C)—or from activities within the program or kernel, such as when the process executes code that divides by zero. As a primitive form of interprocess communication (IPC), one process can also send a sig- nal to another process.
  • The key point is not just that the events occur asynchronously—the user, for exam- ple, can press Ctrl-C at any point in the program’s execution—but also that the program handles the signals asynchronously. The signal-handling functions are regis- tered with the kernel, which invokes the functions asynchronously from the rest of the program when the signals are delivered.

Chapter 10 Time

  • Unix systems represent absolute time as the number of elapsed seconds since the epoch, which is defined as 00:00:00 UTC on the morning of 1 January 1970. UTC (Universal Time, Coordinated) is roughly GMT (Greenwich Mean Time) or Zulu time. Curiously, this means that in Unix, even absolute time is, at a low level, rela- tive.
Clone this wiki locally