ホームページ  >  記事  >  運用・保守  >  Linux で ls を実行するとどのようなシステム コールが発生しますか?

Linux で ls を実行するとどのようなシステム コールが発生しますか?

WBOY
WBOYオリジナル
2022-03-18 11:05:004007ブラウズ

Linux では、ls を実行すると read および exec システム コールが発生します。シェル コマンドを実行すると fork および exec が呼び出されますが、ls によって発生するシステム コールに fork がないことを strace で確認するには、ls コマンドを実行する必要があります。ディレクトリ内のファイルがリストされるため、read を呼び出す必要があります。

Linux で ls を実行するとどのようなシステム コールが発生しますか?

#このチュートリアルの動作環境: linux7.3 システム、Dell G3 コンピューター。

Linux で ls を実行すると、どのようなシステム コールが発生しますか?

答えは、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
open システム コール現在のディレクトリ file を開き、取得したファイル記述子を返します。ファイルが O_RDONLY フラグを使用して開かれていることがわかります。

ファイルが O_RDONLY または O_RDWR フラグで開かれている限り、

read() システム コールを使用してファイルからバイト [3] を読み取ることができます。

したがって、

lsread システム コールを使用する必要があります。さらに、プロセスを作成するシェル コマンドはすべて exec システム コールを使用します。

戻って、これらの概念についての疑問を整理してみましょう:

    ls を含むプログラムはどのように実行されるのでしょうか?
  1. open システム コールは、現在のディレクトリ内のファイルを開き、取得したファイル記述子を返します。では、ファイル記述子とは何でしょうか?
1 プロセスの実行方法

実行中の各プログラムはプロセスと呼ばれます[1]

Unix はプロセスを作成し、新しいプロセス イメージをロードします。イメージの分離。この利点は、両方の操作を管理するための余裕ができることです。プロセスを作成した後、通常は子プロセスを新しいプロセス イメージに置き換えます。したがって、シェル コマンドはプロセスを作成し、exec システム コールを使用します。

たとえば、シェル コマンド ラインで ps コマンドを実行すると、シェル プロセスは実際に fork を呼び出して新しい子プロセスをコピーし、その後 exec システム コールを使用して新しく生成された子プロセスを ps プロセスに完全に置き換えます。

exec 関数を使用して現在のプロセスを新しいプロセスに置き換えます。新しいプロセスは元のプロセスと同じ PID を持ちます。 exec という名前では、複数の関連関数で構成される完全なシリーズです [4]

fork を呼び出して新しいプロセスを作成した後、親プロセスと子プロセスはほぼ同一になります [1、p398]。

フォークとは UNIX の用語です。プロセス (実行中のプログラム) がフォークされると、基本的にコピーされ、フォーク後の両方のプロセスは現在の実行ポイントから実行を継続し、各プロセスは独自のプロセスを持ちます。記憶のコピー。

元のプロセスは親プロセスであり、新しいプロセスは子プロセスです。

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
*/

プログラムで別のプログラムの実行を開始したいが、そのプログラムの実行を継続したい場合はどうすればよいですか?つまり、fork と exec の使用を組み合わせます [6][1, p397]

例 ([6] から変更):

#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
*/
最初に Fork し、次に子プロセスが呼び出します。 exec コマンドを使用してプログラムを実行します。エラー コマンド、パラメータが必要なコマンド、およびパラメータを必要としないコマンドに対応する出力を提供します。

2 ファイル記述子 (fd)

すべてのデバイスをファイルとみなすことができます。

对内核而言,所有打开的文件都通过文件描述符引用[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.

3 系统调用包含在哪些头文件中呢?

包括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]。

4 文件I/O

[7]中提到大多数文件I/O用到的5个函数为:open/read/write/lseek/close

4.1 函数read

调用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 サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。