標籤:style blog http color io os ar 使用 for
errno.h中的strerror(int errno)可以確定指定的errno的錯誤的提示資訊。在 Nginx 中,將所有錯誤提示資訊預先儲存在一個數組裡,而預先確定這個數組的大小,是在自動化指令碼中完成的,如下是auto/unix指令碼:(其中自動化指令碼auto/feature的作用參考《解剖 Nginx·自動指令碼篇(4)工具型指令碼系列》一文)
// auto/unixngx_feature="sys_nerr"ngx_feature_name="NGX_SYS_NERR"ngx_feature_run=valuengx_feature_incs=‘#include #include ‘ngx_feature_path=ngx_feature_libs=ngx_feature_test=‘printf("%d", sys_nerr);‘. auto/feature
但是對於某些平台是沒有sys_nerr的,此時引用auto/feature後得到的ngx_found變數的值為no,否則為yes。當為no時,則執行下面這段:
// auto/unixif [ $ngx_found = no ]; then ngx_feature="_sys_nerr" ngx_feature_name="NGX_SYS_NERR" ngx_feature_run=value ngx_feature_incs=‘#include #include ‘ ngx_feature_path= ngx_feature_libs= ngx_feature_test=‘printf("%d", _sys_nerr);‘ . auto/featurefi
上面這段會在 Cygwin 環境下起作用,因為 Cygwin 定義了_sys_nerr。如果此後ngx_found還是no,則運行:
if [ $ngx_found = no ]; then ngx_feature=‘maximum errno‘ ngx_feature_name=NGX_SYS_NERR ngx_feature_run=value ngx_feature_incs=‘#include #include #include ‘ ngx_feature_path= ngx_feature_libs= ngx_feature_test=‘int n; char *p; for (n = 1; n < 1000; n++) { errno = 0; p = strerror(n); if (errno == EINVAL || p == NULL || strncmp(p, "Unknown error", 13) == 0) { break; } } printf("%d", n);‘ . auto/featurefi
上面這段會在 Solaris 上生效,因為 Solaris 沒有sys_nerr和_sys_nerr。
這樣就會在objs/ngx_auto_config.h檔案中加入如下一句;
// Mac OS X 10.8#ifndef NGX_SYS_NERR#define NGX_SYS_NERR 107#endif
// Linux ubuntu 3.2.0-30-generic-pae#ifndef NGX_SYS_NERR#define NGX_SYS_NERR 135#endif
Igor 把所有 strerror 訊息都拷貝到一個數組裡,他是這樣解釋原因的:
- 1) strerror() and strerror_r() functions are not Async-Signal-Safe, therefore, they cannot be used in signal handlers;
2) a direct sys_errlist[] array may be used instead of these functions, but Linux linker warns about its usage:
warning: `sys_errlist‘ is deprecated; use `strerror‘ or `strerror_r‘ instead warning: `sys_nerr‘ is deprecated; use `strerror‘ or `strerror_r‘ instead causing false bug reports.
如下是src/os/unix/ngx_errno.c:
static ngx_str_t *ngx_sys_errlist;static ngx_str_t ngx_unknown_error = ngx_string("Unknown error");// 替代 strerror,傳入 err 錯誤碼、已指派記憶體的 errstr 指標以及其記憶體大小// 調用該函數後,errstr 和傳回值均為給定錯誤碼相應的錯誤訊息u_char *ngx_strerror(ngx_err_t err, u_char *errstr, size_t size){ ngx_str_t *msg; msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]: &ngx_unknown_error; size = ngx_min(size, msg->len); return ngx_cpymem(errstr, msg->data, size);}ngx_int_tngx_strerror_init(void){ char *msg; u_char *p; size_t len; ngx_err_t err; /* * ngx_strerror() is not ready to work at this stage, therefore, * malloc() is used and possible errors are logged using strerror(). */ // 所有 strerror 訊息的數量所需要的 ngx_str_t 的記憶體位元組數 //(注意不是訊息本身,因為小內容是存在 ngx_str_t 的 data 裡的) len = NGX_SYS_NERR * sizeof(ngx_str_t); // 分配記憶體,注意此時是直接使用 malloc 的 // TODO ngx_sys_errlist = malloc(len); if (ngx_sys_errlist == NULL) { goto failed; } // 初始化錯誤訊息的每一項 for (err = 0; err < NGX_SYS_NERR; err++) { // 擷取該訊息 msg = strerror(err); // 該條訊息的大小 len = ngx_strlen(msg); // 分配 len 大小的記憶體 p = malloc(len); if (p == NULL) { goto failed; } ngx_memcpy(p, msg, len); ngx_sys_errlist[err].len = len; ngx_sys_errlist[err].data = p; } return NGX_OK;failed: err = errno; ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err)); return NGX_ERROR;}
Nginx源碼完全注釋(8)ngx_errno.c