プログラムが動く原理を理解する➀ プログラム実行から見たOSの存在とは

# 目次
1. [この記事の動機](#anchor1)
2. [断り](#anchor2)
3. [参考にした資料](#anchor3)
4. [何について書くか](#anchor4)
5. [前提](#anchor5)
6. [OSについて知ると何がいいのか](#anchor6)
7. [OSの定義について](#anchor7)
8. [OSの恩恵](#anchor8)
9. [OSにお願いする方法](#anchor9)
10. [まとめ](#anchor10)
11. [おわりに](#anchor11)

<a id="anchor1"></a>
## この記事の動機
以前どうやってプログラムは動いているんだろう？
と疑問に思っていたこともあり自分なりに少し勉強したので
学習の復習と忘れた頃に読み返すという名目でアウトプットしてみたという記事です。

<a id="anchor2"></a>
## 断り
当方は、この分野にはまだまだ足を踏み入れたばかりの初心者です。
知ってる人が読むとnoob記事かもしれませんが
その時はコメントで指摘を頂ければ最高に喜びますので
どうぞよろしくお願いします($・・)/~~~

<a id="anchor3"></a>
## 参考にした資料
- [なぜプログラムは動くのか 第2版](https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AF%E3%81%AA%E3%81%9C%E5%8B%95%E3%81%8F%E3%81%AE%E3%81%8B-%E7%AC%AC%EF%BC%92%E7%89%88-%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E5%9F%BA%E7%A4%8E%E7%9F%A5%E8%AD%98-%E7%9F%A2%E6%B2%A2%E4%B9%85%E9%9B%84/dp/4822283151)
- [Linuxシステムコール徹底ガイド](https://postd.cc/the-definitive-guide-to-linux-system-calls/)
- [【C言語】open関数の使い方、正しく理解していますか？](https://progzakki.sanachan.com/program-lang/c/how-to-use-open/)
- [【C言語】write関数の使い方、間違っていませんか？](https://progzakki.sanachan.com/program-lang/c/how-to-use-write/)

<a id="anchor4"></a>
## 何について書くか
今回はOSについて書きます。

<a id="anchor5"></a>
## 前提
OSについて書きますが、OSにもたくさん種類がありそれぞれ仕組みが異なる所もあります。
そこでこの記事では簡素化を目指し、この記事でのOSとはLinux64bit/Ubuntu20.04LTS/kernelVer5.4を指し、OSとカーネルは同意義として扱っていきますのでご了承下さい。

<a id="anchor6"></a>
## OSについて知ると何がよいのか
現在プログラム(アプリケーション)を実行するにはOSの上で実行する事になるはずです。
プログラム実行にはOSの機能をハチャメチャに使う事が多いのでOSについて知っておかないと、プログラムが動く原理を理解できないからです。

<a id="anchor7"></a>
## OSの定義について
まずOSの定義について「なぜプログラムは動くのか 第2版」より引用すると
>OSとはコンピュータを動作させ為に不可欠な制御プログラムと、その制御プログラムの配下で基本的な操作環境を提供するソフトウェアの総称です。

との事です。
分かりずらいですが、要するには基本的な事はOSが担当しますよという事です。
この「基本的な事」というのが何を指しているのかが分かりずらい為、OSの理解が鈍くなってしまうのだと思っています。

<a id="anchor8"></a>
## OSの恩恵
まずOSの何がいいのか、その恩恵の一つに「OSはアプリケーションを作る側にハードウェアを意識させずプログラムを組ませてくれる」という事です。(よくOSはハードウェアを抽象化してくれると表現されます)

例えば、もしOSがなければモニターへの出力やファイル作成(ディスクへの書き込み)などを行いた場合、僕たちはハードウェアを操作するプログラムを0から書いてハードウェアを操作しなければいけません。
しかし、OSがそれらのメンドクサイ作業を受け持ってくれる事で僕たちは簡単にモニターへの出力やファイル作成といった操作をする事が出来ます。

ではその面倒な作業を受け持ってくれた結果、どのようにして僕たちはOSにお願いをすればいいのでしょうか？

<a id="anchor9"></a>
## OSにお願いする方法

### OSは僕たちに何を提供し、僕たちは何をすればいいのか
OSは僕たちにモニターへの出力やファイル操作というお願いを受け付ける窓口を提供します。
そして僕たちはこの窓口に対してモニターへの出力やファイル操作などのお願いを送るわけです。
この窓口というのはあくまでかみ砕いた表現で実際は、システムコールといわれるモノをプログラム(ソースコード)から呼び出す事でOSにお願いしています。
※モニターへの出力やファイル操作以外にもっと沢山の「基本的な事」をシステムコールとして提供してくれます。

イメージとしてはこんな感じでしょうか。
分かりずらかったらごめんなさい。
`僕達 ➤ お願いを送る → 窓口 → OS ➤ お願いを受け取って ➤ ハードウェアを操作する
プログラム ➤ システムコールを呼び出す → OS ➤ システムコールを受け取って ➤ ハードウェアを操作する`


### プログラムからOSにお願いをする方法
では早速ソースコードからOSにお願いをする(システムコールを呼び出す)方法を見ていきましょう
具体的にはC言語で実装した場合、以下の様になります。

``` c:run.c
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#define FILE_NAME "./out.txt"

int main(void)
{
    // 変数定義
    int fd = -1;
    int byte_num = -1;
    char buf[13] = "Hello world!!";

    // ファイルのオープン
    fd = open(FILE_NAME, (O_WRONLY | O_CREAT), 0664);  // 書き込み専用でファイルを開く

    if(fd == -1) {  // ファイルオープン失敗
        fprintf(stdout, "ファイルオープンエラー\n");
        return -1;
    }

    // ファイルへ書き込む
    byte_num = write(fd, buf, sizeof(buf));

    if(byte_num == -1) {  // ファイル書き込み失敗
        close(fd);
        fprintf(stdout, "ファイル書き込み失敗\n");
        return -1;
    }

    // ファイルを閉じる
    close(fd);

    return 0;


}
```

out.txtというテキストファイルを作成(オープン)し、その後作成したout.txtファイルに「Hello World!!」を書き込む簡単なプログラムです。
汚いコードでごめんなさい。

今回はファイル操作にはopen,close,writeを使いましたが、この関数は内部的にアセンブリで書かれた処理によってシステムコールを呼び出しています。この様な関数はシステムコールラッパーと呼ばれています。
又、ラッパー関数とシステムコールの名前は同名である事が多いようです。
[[システムコールとライブラリのラッパー関数]](https://manpages.ubuntu.com/manpages/focal/ja/man2/syscalls.2.html#:~:text=%E3%81%84%E3%81%A4%E3%82%82%E3%81%A8%E3%81%84%E3%81%86%E8%A8%B3%E3%81%A7%0A%20%20%20%20%20%20%20%E3%81%AF%E3%81%AA%E3%81%84%E3%81%8C%E3%80%81%E6%99%AE%E9%80%9A%E3%81%AF%E3%80%81%E3%83%A9%E3%83%83%E3%83%91%E3%83%BC%E9%96%A2%E6%95%B0%E3%81%AE%E5%90%8D%E5%89%8D%E3%81%AF%E3%81%9D%E3%81%AE%E9%96%A2%E6%95%B0%E3%81%8C%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B%20%20%20%20%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%82%B3%E3%83%BC%E3%83%AB%E3%81%AE%E5%90%8D%E5%89%8D%E3%81%A8%E5%90%8C%E3%81%98%E3%81%A7%E3%81%82%0A%20%20%20%20%20%20%20%E3%82%8B%E3%80%82)

もしこのシステムコールという仕組みがなければ僕たちは、0からハードウェアを操作するアセンブリのプログラムを書いてファイル操作をしなければいけません。しかしそのメンドクサイ作業をOSさんが受け持ってくれているおかげで僕たちはハードウェア操作を気にする事無くプログラムを書いていく事が出来るのです。
 

※ また今回利用したopen,close,write以外にも沢山のシステムコールを使う事が出来ます。
　 [[その他のシステムコールの種類:Linux/Ubuntu]](https://manpages.ubuntu.com/manpages/focal/ja/man2/syscalls.2.html)

<a id="anchor10"></a>
## まとめ
プログラムを実行する時に必ずお世話になるのがOSさんです。
それはOSさんに処理をお願いする事で、メンドウな作業を僕たちの代わりに引き受けてくれるからです。
そしてこのOSさんにお願いをする方法というのがシステムコールになります。
僕たちはこのシステムコールをプログラム(ソースコード)から呼び出すことで目的の処理を実行している訳ですね。

それではタイトルの回収です。
プログラム実行から見たOSの存在とは？
↓
**本来プログラマがやらなければならないメンドウな作業を、肩代わりしてくれる存在**

<a id="anchor11"></a>
## おわりに
今回はOSについて書きましたが、今後もプログラムの原理について学んだことを少しずつ記事にしていきます。
どうぞよろしくお願いします。:kissing_heart: