Linux では、ls を実行すると read および exec システム コールが発生します。シェル コマンドを実行すると fork および exec が呼び出されますが、ls によって発生するシステム コールに fork がないことを strace で確認するには、ls コマンドを実行する必要があります。ディレクトリ内のファイルがリストされるため、read を呼び出す必要があります。
#このチュートリアルの動作環境: linux7.3 システム、Dell G3 コンピューター。
答えは、read および exec シリーズです。
シェル コマンドの実行メカニズムは fork exec、fork はクローン、execve は変換です。 ls コマンドはディレクトリ内のファイルをリストするため、read も呼び出されます。
シェルは、fork コマンドと exec コマンドを通じて Linux カーネルにアクセスします。fork コマンドは同じスレッドを作成できます。
strace を使用して、ls によって引き起こされるシステム コールを確認します。フォークがないのは事実ですが、シェル コマンドを実行すると fork が呼び出されるからです。
##execve 変換とは、新しいプロセスを作成し、元のプロセスを新しいプロセスに置き換えることです。
まず、システムコールとは何なのかについて説明しましょう。 ユーザーは、UNIX/Linux によって直接提供される少数の関数 (
システム コール [1]) を使用して、ファイルやデバイスにアクセスして制御できます。
strace ls コマンドを使用すると、ls コマンド [2] で使用されるシステム コールを表示できます。出力の一部は次のとおりです。
open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3 getdents64(3, /* 68 entries */, 32768) = 2240 getdents64(3, /* 0 entries */, 32768) = 0 close(3) = 0
read() システム コールを使用してファイルからバイト [3] を読み取ることができます。
ls は
read システム コールを使用する必要があります。さらに、プロセスを作成するシェル コマンドはすべて exec システム コールを使用します。
たとえば、シェル コマンド ラインで ps コマンドを実行すると、シェル プロセスは実際に fork を呼び出して新しい子プロセスをコピーし、その後 exec システム コールを使用して新しく生成された子プロセスを ps プロセスに完全に置き換えます。
fork() の戻り値で区別できます。
親プロセスの fork 呼び出しは新しい子プロセスの pid (プロセス ID) を返しますが、子プロセスの fork 呼び出しは 0
たとえば:#include<unistd.h> #include<stdio.h> #define LEN 10 int main() { pid_t id=getpid(); printf("Main pid: %d \n",id); int i; pid_t res=fork(); if(res==0) { for(i =0;i<LEN;i++) { pid_t id1=getpid(); printf("%d ",id1); printf("Child process:%d\n",i); } } else { printf("res %d\n",res); for(i=0;i<LEN;i++) { pid_t id2=getpid(); printf("%d ",id2); printf("parent process:%d\n",i); } } printf("THE END\n"); return 0; } /*output Main pid: 10965 res 10966 10965 parent process:0 10965 parent process:1 10965 parent process:2 10965 parent process:3 10965 parent process:4 10965 parent process:5 10965 parent process:6 10965 parent process:7 10965 parent process:8 10965 parent process:9 10966 Child process:0 10966 Child process:1 THE END 10966 Child process:2 10966 Child process:3 10966 Child process:4 10966 Child process:5 10966 Child process:6 10966 Child process:7 10966 Child process:8 10966 Child process:9 THE END */
#include<string.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include<unistd.h> char command[256]; void main() { int rtn; /*子进程的返回数值*/ while(1) { /* 从终端读取要执行的命令 */ printf( ">" ); fgets( command, 256, stdin ); command[strlen(command)-1] = 0; if ( fork() == 0 ) {/* 子进程执行此命令 */ execlp( command, NULL ); /* 如果exec函数返回,表明没有正常执行命令,打印错误信息*/ perror( command ); exit( errno ); } else {/* 父进程, 等待子进程结束,并打印子进程的返回值 */ pid_t sonid=wait ( &rtn ); printf(" child pid: %d\n",sonid); printf( " child process return %d\n", rtn ); } } } /*output:错误命令、需要参数命令、正确命令 >aa aa: No such file or directory child pid: 11230 child process return 512 >echo A NULL argv[0] was passed through an exec system call. child pid: 11231 child process return 134 >ps child pid: 11247 child process return 139 */
对内核而言,所有打开的文件都通过文件描述符引用[7]。文件描述符是非负整数,范围是[0,OPEN_MAX -1]。现在OPEN_MAX 一般为64
但是[7]又说对于FreeBSD 8.0,Linux 3.2.0 ,Mac OS X 10.6.8等, fd变化范围几乎无限,只受到存储器数量、int字长以及系统管理员所配置的软限制和硬限制的约束。。。why?
当open或者create一个新文件时,内核向进程返回一个文件描述符。
当读、写一个文件时,使用open或create返回的文件描述符标识该文件,将其作为参数传送给read / write
按照惯例,fd为0 / 1 / 2分别关联STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO。这些常量也定义在unistd.h
.
包括exec、fork、read、write在内,许多系统调用包含在unistd.h
头文件中
POSIX,Portable Operating System Interface。是UNIX系统的一个设计标准,很多类UNIX系统也在支持兼容这个标准,如Linux。unistd.h
是POSIX标准定义的unix类系统定义符号常量的头文件,包含了许多UNIX系统服务的函数原型[5]。在该头文件,用于访问设备驱动程序的底层函数(系统调用)有这五个:open/close/read/write/ioctl
[1]。
[7]中提到大多数文件I/O用到的5个函数为:open/read/write/lseek/close
调用read函数从打开文件中读数据。
#include<unistd.h> ssize_t read(int filedes, void *buf, size_t nbytes);
返回值:
成功,读出的字节数;
失败,-1;
遇到文件尾,0
有多种情况可使实际读到的字节数少于要求读的字节数:
例如,若在到达文件尾端之前还有30个字节,而要求读100个字节,则read返回30,下一次再调用read时,它将回0。
当从终端设备读时,通常一次最多读一行
当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。
当从管道或FIFO读时,如若管道包含的字节少于所需的数量,那么read将只返回实际可用的字节数。
当从某些面向记录的设备(例如磁盘)读时,一次最多返回一个记录。
当某一信号造成中断,而已经读了部分数据量时。读操作从文件的当前偏移量出开始,在成功返回之前,该偏移量将增加实际独到的字节数
read的经典原型定义则是:
int read(int fd, char*buf, unsigned nbytes);
相关推荐:《Linux视频教程》
以上がLinux で ls を実行するとどのようなシステム コールが発生しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。