[讀書心得] The Linux Programming Interface 第 11 章:系統限制

1
2
$ getconf NAME_MAX ~/Desktop
255

前言

每個 Unix 系統對各種系統功能與資源受限,並提供(或是選擇不提供)由各種標準定義的選項,例如:

  • 一個行程能同時開啟多少個檔案?
  • 系統是否支援即時訊號?
  • 型別為 int 的變數可儲存的最大值是多少?
  • 一個程式能有多大的參數清單?
  • 路徑名稱的最大長度是多少?

我們通常會制定一個應用程式的限制與選項(limits or options), 但會減少可攜性 ,因為限制與選項會與 系統不同而隨之改變 ,像是說:

  • 跨 unix 系統:隨著不同的 unix 系統會造成 int 可儲存的最大值不同。
  • 在特地系統的執行期環境:應用程式可能是在 A 系統編譯,按對於 B 系統中有著不同的限制情形。
  • file system 的轉移:
    • SystemV:檔名長度最多 14 位元組
    • BSD file system:檔名程度最多 255 位元組

11.1 系統限制

SUSv3 要求全部的系統,對於 SUSv3 指定的限制都要提供一個最小值,這樣就可以移植到遵循此標準的系統,通常會在 <limit.h> 常數中定義,命名原則使用前綴 _POSIX_ 字串,而且通常包含 _MAX 字串,所以命名格式通常為 _POSIX_XXX_MAX

這邊其實很弔詭,其實命名 _MAX 但稱其名稱為最小值是一件很怪的事
當我們了解這個常數是用來定義某些資源或特性上限值的常數,此上限值必須有明確的最小值時,就可以清楚理解了。

By the way: 在編譯的過程中遇到了一個問題,macos high sierra 升級到 macos mojave 之後執行 gcc -o … 會跳出

1
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun

此時的處理方式是透過 這個處理方式 來解決,執行

1
xcode-select --install

在 mac 系統中

  • limits.h 放置於 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/limits.h
  • unistd.h 放置於 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/unistd.h

SUSv3 將其規範限制分成三類

  1. 執行期恆定值(runtime invariant value)
  2. 路徑名稱變動值(pathname variable value)
  3. 執行期可增值(runtime increasable value)

執行期恆定值(runtime invariant value)

路徑名稱變動值(pathname variable value)

執行期可增值(runtime increasable value)

  • 參數命名:於執行期時可用於 sysconf() 或是 pathconf() 以取得系統的限制值
    • _SC_ 開頭的常數可用於 sysconf()
    • _PC_ 開頭的常數可用於 pathconf() 或是 fpathconf()

從 shell 取得限制與選項:getconf

執行:

1
$ getconf variable-name [pathname]

11.2 在執行期取得系統限制與選項 sysconf()

1
2
3
4
5
6
#include <unistd.h>

/* Returns value of limit specified by name,
* or -1 if limit is indeterminate or an error occurred
*/
long sysconf(int name);
  • 參數 name 是定義於 <unistd.h> 的其中一個 _SC_* 常數
  • 回傳內容即為限制值
  • 若錯誤發生活是無法確定限制時則會回傳 -1,且 errno 非 0 ,表示發生錯誤

在 SUSv3 的規範之中,sysconf() 所傳回的限制值在呼叫的行程之生命週期內必須是個常數

11.3 在執行期取得檔案限制與選項 pathconf() / fpathconf()

1
2
3
4
5
6
7
#include <unistd.h>

/* Both return value of limit specified by name,
* or -1 if limit is indterminate or an error occurred
*/
long pathconf(const char *pathname, int name);
long fpathconf(int fd, int name);
  • pathconf()fpathconf() 不同之處就在於
    • pathconf() 輸入參數為路徑字串
    • fpathconf() 是使用 file descriptor
  • 參數 name 是定義於 <unistd.h> 的其中一個 _PC_* 系列常數
  • sysconf() 相同地,回傳的結果我即為限制值,且可區分回傳的是限制值還是錯誤,也可以用 errno 分辨錯誤
  • sysconf() 不同的是:SUSv3 並不要求 pathconf() / fpathconf() 的回傳值必須在形成的生命週期內保持不變。例如,行程執行時, 檔案系統可能會被卸載並以不同的性質重新裝載

延伸:autoconf + automake + aclocal

GNU Autoconf 是一個擴充工具,可以確定各種系統特性及限制的存在及設定,autoconf 可以基於所收集到的資訊而產生標頭檔,並將這些檔案 include 進 C 程式中。

透過 autoconf + automake + aclocal 自動產生 Makefile

  • 首先要先安裝相關套件
    brew install autoconf automake libtool
  • 安裝完後就找一個 .c 檔試試看

    1. 執行 autoscan
    2. 會產生 configure.scan
    3. 修改 configure.scan 後將其檔名修改成 configure.in

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      #Process this file with autoconf to produce a con figure script.

      AC_INIT(src.c)
      AM_INIT_AUTOMAKE(src, 1.0)
      # Checks for programs.
      AC_PROG_CC
      # Checks for libraries.

      # Checks for header files.

      # Checks for typedefs, structures, and compiler ch aracteristics.

      # Checks for library functions.

      AC_OUTPUT(Makefile)
    4. 執行 aclocal

    5. 執行 autoconf
    6. 應該會產生 aclocal.m4 configure configure.in src.c
    7. 編輯 Makefile.am

      1
      2
      3
      4
      5
      AUTOMAKE_OPTIONS= foreign

      bin_PROGRAMS= src

      hello_SOURCES= src.c
    8. 執行 automake --add-missing

    9. 執行 ./configure
    10. 應該會產生 Makefile 等檔案
    11. 執行 make / make install / make dist 等即可