The Linux Programming Interface 03 System Programming Concepts 系统编程观念

来源:互联网 发布:电视直播哪个软件最好 编辑:程序博客网 时间:2024/04/29 10:03

The Linux Programming Interface

System Programming Concepts

(1) 本节主要概括

Whenever we make a system call or call a library function, we should always check the return status of the call in order to determine if it was successful. We describe how to perform such checks, and present a set of functions that are used in most of the example programs in this book to diagnose errors from system calls and library functions.

(2)系统调用

比较难,设计操作寄存器,抽象理解。

If the return of the system call service routine indicated an error, the wrapper function sets the global variable errno using this value. The wrapper function then returns to the caller, providing an integer return value indicating the success or failure of the system call.

When a negative value is returned, the C library wrapper function negates it(to make it positive), copies the result into errno, and returns -1 as the function result of the wrapper to indicate an error to the calling program.

(3) 打印glibc的版本,可以调用gnu_get_libc_version()函数

  #include <stdio.h>  #include <gnu/libc-version.h>    int main() {      printf("%s\n", gnu_get_libc_version());      return 0;  }

输出: 2.19

(4)Handing Errors from System Calls and Library Functions

Many hours of debugging time can be wasted because a check was not made on the status return of a system call or library function that "couldn't possibly fail".

fd = open(pathname, flags, mode);

if (fd == -1) {

    /* Code to handle the error */

}

When a system call fails, it sets the global integer variable errno to a positive value that identifies the specific error. Including the <errno.h> header file provides a declaration of errno, as well as a set of constants for the various error numbers.

(5) commence 开始,着手

(6) errno

cnt = read(fd, buf, numbytes);if (cnt == -1) {    if (errno == EINTR) {fprintf(stderr, "read was interrrupted by a signal\n");    } else {    /* Some other error occurred */}

Therefore, when checking for an error, we should always first check if the function return value indicates an error, and only then examine errno to determine the cause of the error.

(7) perror and strerror

A common course of action after a failed system call is to print an error message based on the errno value. The perror() and strerror() library functions are provided for this purpose.

fd = open(pathname, flags, mode);if (fd == -1) {   perror("open");   exit(EXIT_FAILURE);}

  1 #include <stdio.h>  2 #include <gnu/libc-version.h>  3 #include <sys/stat.h>  4 #include <fcntl.h>  5 #include <stdlib.h>  6   7 int main() {  8     printf("%s\n", gnu_get_libc_version());  9     int fd = open("tmp/temp", O_WRONLY|O_CREAT); 10     if (fd == -1) { 11         perror("open"); 12         exit(EXIT_FAILURE); 13     } 14     return 0; 15 }

输出:

2.19
open: No such file or directory

(8) 通过库函数处理错误

  1 #include <stdio.h>  2 #include <gnu/libc-version.h>  3 #include <sys/stat.h>  4 #include <fcntl.h>  5 #include <stdlib.h>  6 #include <errno.h>  7 #include <string.h>  8   9 int main() { 10     printf("%s\n", gnu_get_libc_version()); 11     int fd = open("tmp/temp", O_WRONLY|O_CREAT); 12     if (fd == -1) { 13         perror("open"); 14         char *str = strerror(errno); 15         printf("%s\n", str); 16         exit(EXIT_FAILURE); 17     } 18     return 0; 19 }

output:

wang@wang:~/test$ ./a.out
2.19
open: No such file or directory
No such file or directory

(09) 作者定义了一些方便使用的函数,比如getNum(), gnFail(), 有空可以分析其源码定义。

(10) 移植相关定义

Defining multiple macros is additive, so that we could, for example, use the following cc command to explicitly select the same macro setting as are provided by default:

$ cc -D_POSIX_SOURCE -D_POSIX_C_SOURCE=199506 -D_BSD_SOURCE -D_SVID_SOURCE prog.c

(11) system date types

Each of these types is defined using the C typedef feature. For example, the pid_t data type is intended for representing process IDs, and on Linux/x86-32 this type is defined as follows:

typedef int pid_t;

Most of the standard system data types have names ending in _t. Many of them are declared in the header file <sys/types.h>.

打印类型

  1 #include <stdio.h>  2 #include <sys/types.h>  3 #include <unistd.h>  4   5 int main() {  6    pid_t mypid;  7    mypid = getpid();  8    printf("My PID is %ld\n", (long)mypid);  9    return 0; 10 }

output:

wang@wang:~/test$ ./a.out
My PID is 1226

(12)不同的系统中参数存放的顺序可能不同

struct sembuf {   unsigned short sem_num;   short sem_op;   short sem_flg;}
(13)

Therefore, this macro might not be present on some UNIX implementations. In order to portably handle such possibilities, we can use the C preprocessor #ifdef directive, as in the following example:

#ifdef WCOREDUMP

    /* Use WCOREDUMP() macro */

#endif

(14)  总结

System call allow processes to request services from the kernel. Even the simplest system calls have a significant overhead by comparison with a user-space function call, since the system must temporarily switch to kernel mode to execute the system call, and the kernel must verify system call arguments and transfer data between user memory and kernel memory.

    The standard C library provides a multitude of library functions that perform a wide range of tasks. Some library functions employ system calls to do their work; others perform tasks entirely within user space. On Linux, the usual standard C library implementation that is used is glibc.

    Most system calls and library functions return a status indicating whether a call has succeeded or failed. Such status returns should always be checked.

    We introduced a number of functions that we have implemented for use i the example programs in this book. The tasks performed by these function include diagnosing errors and parsing command-line arguments.

    We discussed various guidelines and techniques that can help us write portable system programs that run on any standards-conformant system.

    When compiling an application, we can define various feature test macros that control the definition exposed by header files. This is useful if we want to ensure that a program conforms to some formal or implementation -defined standards.

    We can improve the portability of system programs by using the system data types defined in various standards, rather than native C types. SUSv3 specifies a wide range of system data types that an implementation should support and that an application should employ.

(15)课后练习

主要是使用reboot函数的第二个参数

man 2 reboot

This   system   call  will  fail  (with  EINVAL)  unless  magic  equals
       LINUX_REBOOT_MAGIC1   (that   is,   0xfee1dead)   and   magic2   equals
       LINUX_REBOOT_MAGIC2  (that  is, 672274793).  However, since 2.1.17 also
       LINUX_REBOOT_MAGIC2A  (that  is,  85072278)  and  since   2.1.97   also
       LINUX_REBOOT_MAGIC2B   (that  is,  369367448)  and  since  2.5.71  also
       LINUX_REBOOT_MAGIC2C (that is, 537993216) are permitted as  values  for
       magic2.  (The hexadecimal values of these constants are meaningful.)

打印LINUX_REBOOT_MAGIC2

#include <unistd.h>#include <linux/reboot.h>#include <stdio.h>int main() {    printf("%lx\n", (long)LINUX_REBOOT_MAGIC2);    return 0;}

输出:

wang@wang:~/src/workspace/test$ ./a.out
28121969

使用reboot重启电脑,注意需要root权限。

#include <unistd.h>#include <linux/reboot.h>#include <stdio.h>int main() {    printf("%lx\n", (long)LINUX_REBOOT_MAGIC2);    reboot(RB_AUTOBOOT);    return 0;}


0 0
原创粉丝点击