Linux系统的实现需要遵循很多个标准,比如ANSI C标准,POSIX标准,XSI标准,每个标准都有各自的限制和选项,标准中规定有一些内容是必须的,一些是可选的。当我们的应用程序设计遵循标准中的选项和限制,那么就可以达到最大化的可移植性。
静态定义
不管是限制还是选项,都是支持静态和动态获取的,也有一些只能在系统运行后才能确定其值的,那么就只有通过动态去获取了。对于静态定义的系统限制和选项,宏定义都会包含在如下头文件中:
#include <unistd.h>
#include <limit.h>
limit.h 头文件会包含限制相关的定义,unistd.h 头文件会包含选项相关的定义。
动态获取
Linux系统中基本上所有的限制和选项都可以通过sysconf函数在运行时获取:
#include <unistd.h>
long sysconf(int name);
long pathconf(const char *pathname, int name);
long fpathconf(int fd, int name);
系统定义了所有相关的name宏定义,格式为:_SC_XXX/_PC_XXX,其中 _SC_XXX 是给 sysconf 使用的;_PC_XXX 是给 pathconf 和 fpathconf 使用的。
比如:
_SC_ARG_MAX
......
_PC_FILESIZEBITS
返回值:
- 如果传入的name值该函数不支持,则返回 -1 ,并把errno设置为EINVAL。
- 返回 -1 ,errno为0,表示是不确定的或者无限制的
- 返回 >= 0 ,为设定的一个确定的值,在进程运行过程中是不改变的。
如上所说,系统限制和选项在进程运行过程中是不改变的,因此我们只有获取config的API,却没有修改的API。但有一点需要注意的是,rlimit中有两个值的修改会影响到对应的sysconf获取的值:
RLIMIT_NOFILE 会反映到sysconf的_SC_OPEN_MAX的返回值。
RLIMIT_NPROC 会反映到sysconf的_SC_CHILD_MAX的返回值。
所有能够使用的sysconf参数可以通过头文件 confname.h 中去查找:
/* Values for the NAME argument to `pathconf' and `fpathconf'. */
enum
{
_PC_LINK_MAX,
#define _PC_LINK_MAX _PC_LINK_MAX
_PC_MAX_CANON,
#define _PC_MAX_CANON _PC_MAX_CANON
_PC_MAX_INPUT,
#define _PC_MAX_INPUT _PC_MAX_INPUT
_PC_NAME_MAX,
#define _PC_NAME_MAX _PC_NAME_MAX
_PC_PATH_MAX,
#define _PC_PATH_MAX _PC_PATH_MAX
_PC_PIPE_BUF,
......
};
/* Values for the argument to `sysconf'. */
enum
{
_SC_ARG_MAX,
#define _SC_ARG_MAX _SC_ARG_MAX
_SC_CHILD_MAX,
#define _SC_CHILD_MAX _SC_CHILD_MAX
_SC_CLK_TCK,
#define _SC_CLK_TCK _SC_CLK_TCK
_SC_NGROUPS_MAX,
#define _SC_NGROUPS_MAX _SC_NGROUPS_MAX
_SC_OPEN_MAX,
#define _SC_OPEN_MAX _SC_OPEN_MAX
_SC_STREAM_MAX,
#define _SC_STREAM_MAX _SC_STREAM_MAX
_SC_TZNAME_MAX,
#define _SC_TZNAME_MAX _SC_TZNAME_MAX
_SC_JOB_CONTROL,
#define _SC_JOB_CONTROL _SC_JOB_CONTROL
_SC_SAVED_IDS,
#define _SC_SAVED_IDS _SC_SAVED_IDS
_SC_REALTIME_SIGNALS,
......
};
限制
对于系统限制来说,一般会定义一个对应的宏在 limit.h 头文件中,比如 _FOO ,同时也会定义 sysconf() 参数宏 _SC_FOO 用于给 sysconf 函数动态获取使用。
对于一个限制来说,POSIX标准定义了针对该限制的所能允许设置的最小值 _POSIX_FOO,实际系统对于限制 _FOO 的设定只要满足比该值更大,所以 _POSIX_FOO 只能作为 _FOO 的极限值。
测试示例:
#ifdef ARG_MAX
printf("ARG MAX is defined to %ld\n", (long) ARG_MAX);
#else
printf("no symbol for ARG_MAX\n");
#endif
#ifdef _SC_ARG_MAX
printf("ARG_MAX = %ld, errno:%d\n", sysconf(_SC_ARG_MAX), errno);
#else
printf("no symbol for _SC_ARG_MAX\n");
#endif
通过类似上述代码片段的实现,我们可以打印出当前系统都做了哪些限制,可以看到和 ARG_MAX 限制对应的 sysconf 参数宏被定义为 _SC_ARG_MAX。我的部分测试结果:
no symbol for ARG_MAX
ARG_MAX = 2097152, errno:0
no symbol for ATEXIT_MAX
ATEXIT_MAX = 2147483647, errno:0
从这份测试结果可以看出, ARG_MAX 和 ATEXIT_MAX 这两个限制都没有定义对应的静态值,而需要通过运行时确定。因此使用时需要特别注意:如果没有静态定义,也必须要使用动态获取接口尝试获取一下。
选项
对应选项的定义和limit限制还是稍有区别,一般是会在 unistd.h 头文件中定义 _POSIX_FOO ,同时定义 sysconf() 参数宏 _SC_FOO 用于给 sysconf 函数动态获取使用。和限制一样,对于一个特定的选项,如果没有静态定义,我们也必须要使用动态获取接口尝试。
#ifdef _POSIX_BARRIERS
printf("_POSIX_BARRIERS is defined (val is %ld)\n", (long)_POSIX_BARRIERS+0);
#else
printf("_POSIX_BARRIERS is undefined\n");
#endif
#ifdef _SC_BARRIERS
printf("_POSIX_BARRIERS = %ld, errno:%d\n", sysconf(_SC_BARRIERS), errno);
#else
printf("no symbol for _POSIX_BARRIERS\n");
#endif
测试结果:
_POSIX_BARRIERS is defined (val is 200809)
sysconf says _POSIX_BARRIERS = 200809