<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title>Linux - Category - Wandering World</title>
        <link>http://chinyu1229.github.io/categories/linux/</link>
        <description>Linux - Category - Wandering World</description>
        <generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>chinyu0916@gmail.com (Chinyu)</managingEditor>
            <webMaster>chinyu0916@gmail.com (Chinyu)</webMaster><copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright><lastBuildDate>Thu, 09 Sep 2021 21:13:12 &#43;0800</lastBuildDate><atom:link href="http://chinyu1229.github.io/categories/linux/" rel="self" type="application/rss+xml" /><item>
    <title>Linux Chapter 25 ProcessTermination</title>
    <link>http://chinyu1229.github.io/2021-09-09-linux_chapter_25_processtermination/</link>
    <pubDate>Thu, 09 Sep 2021 21:13:12 &#43;0800</pubDate>
    <author>Author</author>
    <guid>http://chinyu1229.github.io/2021-09-09-linux_chapter_25_processtermination/</guid>
    <description><![CDATA[Process Termination _exit() and exit() 有兩種方式可以終止程式：
 abnormal - 由訊號觸發，預設是終止程式（可以core dump) normally - 使用_exit()終止程式  1 2  #include&lt;unisted.h&gt;void _exit(int status);    status:定義終止狀態，在parent process可以呼叫wait()以取得狀態 結束狀態為 0 ，表示process順利結束。非0表示異常終止 非0狀態沒有固定規則，每個應用程式有自己的規則要參考他們的文件 普遍為SUSv3制訂的：EXIT_SUCCESS(0) EXIT_FAILURE(1)  程式通常不會直接呼叫_exit()，因為會直接終止，通常會呼叫exit()，因為可以在真正呼叫_exit()前執行一些動作
1 2  #include&lt;stdlib.h&gt;void exit(int status);   會進行以下動作：
 以反向註冊順序，呼叫exit處理常式 flush stdio的串流緩衝區 使用status 提供的值執行_exit() system call  與在main() 中return 終止程式或執行到main()結尾終止的方式，return n; 等同於 exit(n)
 不等價的時候：若在exit的過程中有任何步驟存取main()的區域函數時，從main return會產生不可預期的行為。例如在呼叫setvbuf() 或 setbuf()時使用main()的區域函數時就會發生不等價的情況  行程終止的動作  關閉open file descriptor、directory stream、message catalog descriptor、conversion descriptor 關閉open file descriptor 後，會釋放此形成所有的file lock 解除任何加載的System V共享記憶體段，並將每個區段對應的shm_nattchcounter減去1 解除行程使用mmap()建立的記憶體映射   Exit Handler 在行程終止前執行一些操作，以應用程式的函式庫來說，行程終止前需要清理在生命週期間有用到的函式庫，因此需要exit handler來保證在終止前（結束時）會清理]]></description>
</item><item>
    <title>Linux Chapter 24 CreateProcess</title>
    <link>http://chinyu1229.github.io/2021-06-20-linux_chapter_24_createprocess/</link>
    <pubDate>Sun, 20 Jun 2021 17:13:12 &#43;0800</pubDate>
    <author>Author</author>
    <guid>http://chinyu1229.github.io/2021-06-20-linux_chapter_24_createprocess/</guid>
    <description><![CDATA[CreateProcess fork() exit() wait() execev() 簡介  fork()  parent process經由呼叫fork()建立一個 child process child獲得parent的stack segment、data segment、heap segment、text segment 可說是把parent process一分為二   exit()  terminate a process 將佔用的所有資源歸還給kernel parent 可以利用 wait()來取得結束的狀態(status)   wait()  若child process還未呼叫exit()，那wait()會suspend parent process，直到有任一child process terminated 可以取得status   execve()  Load a new program到目前process的記憶體 丟去現存的text segment 重新建立 stack segment、data segment、heap segment    大致流程圖
fork() 1 2 3  #include &lt;unistd.h&gt;pid_t fork(void); In parent: returns process ID of child on success, or –1 on error; in successfully created child: always returns 0    呼叫後將存在兩個process，且每個process都會從fork()的返回處繼續執行 兩個process擁有不同的stack segment、data segment、heap segment、text segment副本（child可以再修改，且不影響parent） 返回pid == 0是child process 返回pid !]]></description>
</item><item>
    <title>Linux Chapter 21 Signal 處理常式</title>
    <link>http://chinyu1229.github.io/2021-06-02-linux_chapter_21_signal%E8%99%95%E7%90%86%E5%B8%B8%E5%BC%8F/</link>
    <pubDate>Wed, 02 Jun 2021 22:10:12 &#43;0800</pubDate>
    <author>Author</author>
    <guid>http://chinyu1229.github.io/2021-06-02-linux_chapter_21_signal%E8%99%95%E7%90%86%E5%B8%B8%E5%BC%8F/</guid>
    <description><![CDATA[Linux Chapter 21 Signal 處理常式 訊號處理常式設計  設定一個全域flag，接著離開。主程式會週期性的檢測此flag，若有被設定為flag，會進行適當的反應 會做出幾種類型的清理動作，接著結束行程或使用非區域跳躍（nonlocal goto）解開unwind the stack，並將控制權交回給主程式（是先定義的位置）  可重入函式與非同步訊號安全函式 可重入與不可重入 訊號處理常式與multiple thread的概念有關，前者可能會在任意時間點非同步的中斷程式執行，所以主程式與訊號處理常式會變成在同一個行程中，2個獨立的thread(非同步執行) 若函式可以在同一個行程的各thread中同步且安全的執行，此函式稱為是可重入的（reentrant）
 SUSv3對可重入的定義是: 當兩條或多條thread呼叫函式時，即便是彼此互相交叉執行，也能保證效果與各thread以未定義順序呼叫時一致  若函式會更新全域或靜態的資料結構，可能就是不可重入的函式（只使用local變數的函式保證是可重入）。
 可能發生的情況： 若主程式在呼叫malloc()期間，受到一個同樣呼叫malloc()的訊號處理常式中斷，則此linklist可能會遭到破壞，因此malloc()的函式家族與使用這些函式的其他函式庫函式都是不可重入。 其他會傳回靜態配置的記憶體，也是不可重入的，crypt() getpwnam() gethostbyname() getservbyname() 函式的內部紀錄是使用靜態的資料結構也是不可重入的，例如scanf() printf()，他們會有緩衝的I/O更新內部資料結構，所以在訊號處理常式使用printf()也在主程式呼叫printf()，緩衝區的資料會交錯，導致得到非期望的輸出結果，甚至是整個程式crush  標準的非同步訊號安全函式（async-signal-safe functions）  指可以安全地從訊號處理常式進行呼叫。 當函式是reentrant函式，或是不會受到訊號處理常式中斷，可以稱函式為async-signal-safe function man page: https://man7.org/linux/man-pages//man7/signal-safety.7.html  在訊號處理常式內使用errno 因為可能會更新errno變數，會導致函式reentrant，因為可能會覆寫主程式之前呼叫函式設定的errno值。 所以可以先儲存errno的值，並在函式執行完畢之後，回存errno
1 2 3 4 5 6 7  void handler(int sig) { int sErrno; sErrno = errno; /* can execute a function that might modify errno */ errno = sErron; }   全域變數與sig_atomic_t資料型別 全域變數有reetrant問題，但有時需要在主程式與訊號處理常式之間共用全域變數，要能正確處理即可以保證安全。 常見的設計是：]]></description>
</item><item>
    <title>Linux Chapter 20 Signal 基本概念</title>
    <link>http://chinyu1229.github.io/2021-05-29-linux_chapter_20_signal-%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5/</link>
    <pubDate>Sat, 29 May 2021 23:10:12 &#43;0800</pubDate>
    <author>Author</author>
    <guid>http://chinyu1229.github.io/2021-05-29-linux_chapter_20_signal-%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5/</guid>
    <description><![CDATA[Linux Chapter 20 Signal 基本概念 概念 signal 可以通知行程（process）有事件發生，也可以稱為軟體中斷，多數情況下都無法預測訊號抵達的時間。
行程可以送出訊號給另外一個行程，在此可以做為synchronization 或者 IPC 的技術。
訊號類型與預設行為 可以在signal(7)使用手冊列出訊號名稱，或是參考書上p.430 下圖列出簡易版訊號表： 改變訊號處置 Unix系統提供兩種 1.signal() 2. sigaction()
 signal()提供設定訊號的原始API 介面比sigaction()簡單 sigaction()是建立訊號處置常式首推的API signal() 是基於 sigaction()實作的函式  1 2 3  #include&lt;signal.h&gt;void (*signal(int sig, void (*handler)(int))); Return previous signal disposition on success,or SIG_ERR on error    handler可以用以下的值取代  SIG_DFL:將訊號處置 重新設定為預設值，適用於還原先前signal()呼叫改變的訊號處置 SIG_IGN:忽略該訊號，行程也不會知道有此訊號    訊號處理常式 範例：
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  #include&lt;signal.]]></description>
</item><item>
    <title>Linux Chapter 5 - 檔案IO深入探討</title>
    <link>http://chinyu1229.github.io/2021-05-20-%E6%AA%94%E6%A1%88i_o%E6%B7%B1%E5%85%A5%E6%8E%A2%E8%A8%8E/</link>
    <pubDate>Thu, 20 May 2021 17:40:12 &#43;0800</pubDate>
    <author>Author</author>
    <guid>http://chinyu1229.github.io/2021-05-20-%E6%AA%94%E6%A1%88i_o%E6%B7%B1%E5%85%A5%E6%8E%A2%E8%A8%8E/</guid>
    <description><![CDATA[檔案I/O深入探討 原子與競速條件 以互斥的方式建立檔案 在open()中設定O_EXCL與O_CREAT可以在檔案已存在的時候回傳錯誤，確保process本身是檔案的建立者
將資料附加到檔案 當我們有多個process要增加資料到同一個檔案 會有下列這種寫法
1 2 3 4  if(lseek(fd,0,SEEK_END)==-1) errExit(&#34;lseek&#34;); if(write(fd, buf, len)!=len) fatal(&#34;Partial/failed write&#34;);   會有race condtion問題，第一個process在lseek()與write()之間被第二個相同的行程中斷，那兩個行程會在寫入之前將他們的file offset設定到相同位置，因此會產生互相覆蓋的現象
 為了避免此問題，必須讓移往檔案結尾下一個byte操作與寫入操作都是原子操作，我們可以使用O_APPENDflag達成  檔案操作控制 1 2 3  #include&lt;fcntl.h&gt;int fcntl(int fd, int cmd,...); Return value on success depends on cmd, returns -1 on error   用途之一是用來取得或修改access mode,以及一個開啟檔案的開啟檔案狀態flag 取得設定的cmd : F_GETFL
1 2 3  int flags, accessMode; flags = fcntl(fd, F_GETFL); if(flags == -1) errExit(&#34;fcntl&#34;);   可以使用 &amp; 操作去判斷目前的開啟檔案狀態flag]]></description>
</item><item>
    <title>Linux Chapter 13 - 檔案IO緩衝區</title>
    <link>http://chinyu1229.github.io/2021-05-20-%E6%AA%94%E6%A1%88i_o%E7%B7%A9%E8%A1%9D%E5%8D%80/</link>
    <pubDate>Thu, 20 May 2021 01:04:12 &#43;0800</pubDate>
    <author>Author</author>
    <guid>http://chinyu1229.github.io/2021-05-20-%E6%AA%94%E6%A1%88i_o%E7%B7%A9%E8%A1%9D%E5%8D%80/</guid>
    <description><![CDATA[檔案I/O緩衝區 The Linux programming interface chapter 13
核心緩衝區概述 system call read() &amp; write()在操作磁碟檔案時不會直接對磁碟存取，而是單純在使用者空間緩衝區與核心緩衝區快取（kernel buffer cache）之間複製資料。 例如： write(fd, &quot;abc&quot;,3) 在後續的某個時間點，核心會將其緩衝區的資料寫入磁碟
如果在此期間，另外一個process試圖讀取檔案的這幾個bytes，則核心將自動從緩衝區提供資料，而不是從檔案讀取。同理於read()期間有write() process的情況
緩衝區大小對效能的影響  system cpu time：主要是測量使用者空間與核心空間之間資料傳輸所消耗的時間  包含CPU的處理, 等待I/O I/O的處理,作業系統處理提供一些服務額外的時間，以及系統閒置的時間   Elapsed time : 完整的程式在這個系統裡面執行的時間  當緩衝區大小為1byte，需要呼叫大約一億次的system call，而緩衝區大小為4096bytes時，system call次數約為24000，當超過此設定值，效能的改善就開始不明顯，是因為在使用者空間和核心空間之間複製資料以及執行實際I/O所需的時間相較之下，read()和write()的system call 成本就顯得微不足道。
＊ 結論： 若我們正對檔案進行大量的資料讀寫，則以大區塊緩衝資料來減少system call 即可提升系統效能
stdio函式庫的緩衝 操作磁碟檔案時，對大型區塊資料使用緩衝可以降低system call。
設定一個stdio stream的緩衝模式 1 2  #include&lt;stdio.h&gt;int setvbuf(FILE *stream, char *buf, int mode, size_t size);   在開啟串流之後，必須在對串流進行任何其他的stdio函式之前先呼叫setbuf() 因為setbuf()將影響後續的stdio操作對串流的行為
 參數  stream:可以識別要修改的檔案stream緩衝區 buf &amp; size 指定使用的緩衝區  若buf不為NULL則以其指向的size大小區塊作為stream的緩衝區，因為stdio接著會使用buf指向的緩衝區，所以應該以靜態配置或使用malloc()於heap做動態配置，不應該配置為stack裡面的區域變數，否則當函式返回時會釋放stack frame，導致混亂 若buf為NULL，stdio會自動配置一個緩衝區提供stream使用（除非我們選擇無緩衝的I/O)。在SUSv3允許但不要求實作時使用size來決定緩衝區的大小   mode指定緩衝區的類型     範例 1 2 3 4  #defind BUF_SIZE 1024 static char buf[BUF_SIZE]; if(setvbuf(stdout, buf, _IOFBF) !]]></description>
</item><item>
    <title>Linux Chapter 4 - 檔案IO</title>
    <link>http://chinyu1229.github.io/2021-05-19-%E6%AA%94%E6%A1%88io/</link>
    <pubDate>Wed, 19 May 2021 17:40:12 &#43;0800</pubDate>
    <author>Author</author>
    <guid>http://chinyu1229.github.io/2021-05-19-%E6%AA%94%E6%A1%88io/</guid>
    <description><![CDATA[檔案I/O 概述 全部執行I/O的系統呼叫都是透過檔案描述符來控制開啟的檔案，各類型的檔案在開啟之後，都能以檔案描述符進行操控。
標準檔案符 shell平時會將以下三個檔案描述符保持一直開啟，可以使用I/O redirection進行適當的修改
   file descriptor 用途 POSIX 名稱 stdio stream     0 標準輸入 STDIN_FILENO stdin   1 標準輸出 STDOUT_FILENO stdout   2 標準錯誤 STDERR_FILENO stderr    開啟檔案 open()
1 2 3 4 5  #include&lt;sys/stat.h&gt;#include&lt;fcntl.h&gt;int open(const char *pathname, int flags, ... /*mode_t mode*/); Return file descriptor on success, -1 on error   flags -&gt; 為位元mask 指定檔案的存取模式 mode -&gt; 指定了檔案的存取權限（如果open()沒有指定O_CREATflags可以省略）]]></description>
</item></channel>
</rss>
