私のオペレーティングシステムのテキストから、アプリケーションとライブラリはシステムコールによってカーネルと対話します。
しかし、私の知る限り、Windows、OS X、Linuxでは、システムコールの投稿にC言語しか使用できません。
JavaアプリケーションでI/Oを最適化したいとき、それは私を困らせました-システムコールを直接使用することができないため、Javaによって要求されるシステムコールを推測する必要があります_ API(たぶん、JVMソースコードを読むべきでしょうか?しかし、期限に間に合わせるのに時間がかかりすぎるのではないかと心配していました)、その後、推測してI/Oを最適化します。
それ以来、システムコールがC言語に限定されている理由と、Python、Java、および他の多くのプログラミング言語でそれができない理由を知りました。
編集:
OS X、Windows、LinuxはすべてCで実装されていることは知っていますが、それでも疑問があります。
OSが特定のプログラミング言語で実装されている場合、そのプログラミング言語でのみシステムコールをリクエストできますか?その理由は何ですか?
Windows、OS X、Linuxでは、C言語のみを使用してシステムコールをポストできます。
実際、これは少なくともLinuxに関しては間違っています。
[〜#〜] abi [〜#〜] で定義されているように、実際の システムコール はCと同じ 呼び出し規約 を使用していません。詳細はもちろんプロセッサ固有です(そのため、x86-64に焦点を当てましょう)。
(私はここですべての詳細を正確に確信していません、チェックする必要があります;私は数年前にそれらについて読みました...)
実際のシステムコールは、SYSENTER
やSYSCALL
などの機械語命令を使用し、システムコールの番号を渡します(おそらく%eax
)とその引数(さまざまな(明確に指定された)プロセッサレジスタ)。ただし、スタックポインタはまったく使用しません。したがって、(マシンコードで)原則として、スタックなしで、または無効な%rsp
(例:nilに設定)。対照的に、C関数の呼び出しには、有効なスタックポインターが必要です(ほとんどの引数がレジスターで渡される場合でも)。
実際のシステムコールは、異なる戻り規則を使用します。 carry bitが設定されている場合、システムコールは失敗し、%eax
にはerrno
コードが含まれています。キャリービットがクリアされている場合、システムコールは成功しており、%rax
にはその結果が含まれます。
したがって、一部のプログラミング言語の実装では、Cライブラリを回避することもできます。たとえば、Schemeの bones です。また、libc
を使用せず、Cの呼び出し規則を使用せずに、Linux用のアセンブラーでプログラムをコーディングできます。
したがって、 C標準ライブラリ 'の実装には、(すべてのシステムコールに対して)小さなwrapping関数が必要です。 Cで read(2) "システムコール"関数を呼び出すと、実際には小さなラッパーが呼び出されます。
Linux Assembler HowTo が詳細を説明しています。 高度なLinuxプログラミング もご覧ください。ただし、Linux kernel のソースコードとC標準ライブラリも確認する必要があります(例 musl-libc には非常に読みやすいコードがあります)。
OSが特定のプログラミング言語で実装されている場合、そのプログラミング言語でのみシステムコールをリクエストできますか?
これは間違っています。カーネルへの呼び出し規約(SYSENTER
など...を使用)はCの場合と同じではありません。システムコールは他の方法でコーディングできます。
Linuxでは、一部の低レベルユーティリティ関数はnotシステムコール(exhaustivelysyscalls(2) ...);にリストされています特に dlopen(3) & pthread_create(3) & getaddrinfo(3) などのDNS関数はseveralシステムコール。 nsswitch.conf(5) も参照してください。また、一部のシステムコール(例: clock_gettime(2) ...)は vdso(7) トリックでカーネルのオーバーヘッドを回避します。
OSDev wikiも参照してください。
システムコールがC言語に限定されている理由と、Python、Javaおよびその他の多くのプログラミング言語)ではそれができないのはなぜですか?
すでに説明したように、システムコールはCに限定されていません。ただし、Cは非常に便利です(- lingua franca またはポータブルとして)アセンブラのような言語)。そのため、ほとんどのプログラミング言語の実装者はこれを使用しており、C標準ライブラリのシステムコールを呼び出すライブラリを提供することがよくあります。 [〜#〜] posix [〜#〜] のような標準も、Cコードの観点から「システム」関数(例 mmap )を正規化および定義しています。したがって、プログラミング言語の実装者はCのコードに関心を持っています(この実装は簡単にportable からさまざまなUnix- likeまたはPOSIXのようなシステム;つまり、ほぼsameCソースコード-たとえばLua、Guile、またはOcaml-実装はさまざまな上で動作する可能性がありますMacOSX、Linux、FreeBSD、TrueOS、さらにはGNU Hurd)のようなシステム。 bones は、LinuxからMacOSXまたはTrueOSへの移植が よりもはるかに困難です。 guile 、ほとんど同じプログラミング言語(Scheme方言の一部)を実装していても。
python、Javaおよびその他の多くのプログラミング言語でこれを行うことができないのはなぜですか?
実際には、これらすべての言語実装(プログラミング言語は仕様いくつかの文書に書かれています;ソフトウェアではありませんソフトウェアはlibc
を使用して移植性の問題を回避しています。
(Linuxとは異なり、一部の* BSDシステムシステムコールのIIRCはマシンスタックに引数を渡しますが、それを確認する必要があります)
しかし、私の知る限り、Windows、OS X、Linuxでは、システムコールの投稿にC言語しか使用できません。
ここでの前提は実際には正しくありません。最終的には、カーネルがトラップの発生を予期している一連の命令をプロセッサに実行させることです。これらの命令を実行できる言語であれば、システムコールを直接実行できます。コメント内の MichałPolitowskiによって引用された錆の例 は、この動作の完璧な例です。
おなじみのシステムコールはCで記述されています。これは、アセンブリのすぐ上にある、システム内で2番目に低い共通分母であるためです。これにより、開発者は、read(2)
やioctl(2)
などの特定の関数が必要な場合に、ネイティブのリンケージメカニズムを使用して呼び出すことができる、既知の標準に裏打ちされた、移植性のあるポータブルな実装を利用できます。この種のものはコンピューティングの黎明期から知られている量であるため、ほとんどすべての言語は、ネイティブオブジェクトコードを呼び出す機能を提供します。
JavaアプリケーションでI/Oを最適化したいとき、それは私を困らせました-システムコールを直接使用することができないため、Javaによって要求されたシステムコールを推測する必要があります_ API ...
Javaはこのようにして意図的に構築されました。Javaとプロセッサの間に抽象化の層を設ける代わりに、同じコードをどこでも実行できます。あなたはそれがどのように起こるかを知っているか気にするはずはありません。それでも、Javaには、Javaネイティブインターフェイスと呼ばれるローカルシステムへのエスケープハッチがあります。 JNIは楽園ですべてを行うことはできず、システムの残りの部分の海底に冒険しなければならない場合があるという暗黙の承認です。
ネイティブシステムコールを実行することで得られるものの少なくとも一部は、JNIを経由することで相殺されることをお勧めします。 I/Oの純粋なJavaソリューションに対してベンチマークを行うと、コミットする前に十分な時間を費やすことになります。また、パフォーマンス要件がそのような最適化を必要とするほど厳格であることを事前に知っている場合は、Javaがプロジェクトの言語として適切ではなかった可能性があります。
C++とDelphi(特に)は、システムコールの名前をインポートして、追加の作業なしで呼び出すことができます。 C#には言語機能( Marshalling )があり、同じことをしているように見えますが、実際にはインターフェイスで何かを行います。
代わりに、Cによって一般化された 呼び出し規約 に制限されます。また、規約によって、C関数宣言であるかのように文書化される傾向があります。