Mercurial > hg > nginx
view src/os/unix/ngx_errno.c @ 7985:ec2e6893caaa
Simplified sendfile(SF_NODISKIO) usage.
Starting with FreeBSD 11, there is no need to use AIO operations to preload
data into cache for sendfile(SF_NODISKIO) to work. Instead, sendfile()
handles non-blocking loading data from disk by itself. It still can, however,
return EBUSY if a page is already being loaded (for example, by a different
process). If this happens, we now post an event for the next event loop
iteration, so sendfile() is retried "after a short period", as manpage
recommends.
The limit of the number of EBUSY tolerated without any progress is preserved,
but now it does not result in an alert, since on an idle system event loop
iteration might be very short and EBUSY can happen many times in a row.
Instead, SF_NODISKIO is simply disabled for one call once the limit is
reached.
With this change, sendfile(SF_NODISKIO) is now used automatically as long as
sendfile() is enabled, and no longer requires "aio on;".
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 27 Dec 2021 19:48:33 +0300 |
parents | c43a2e8fdf7e |
children |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include <ngx_core.h> static ngx_str_t ngx_unknown_error = ngx_string("Unknown error"); #if (NGX_HAVE_STRERRORDESC_NP) /* * The strerrordesc_np() function, introduced in glibc 2.32, is * async-signal-safe. This makes it possible to use it directly, * without copying error messages. */ u_char * ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) { size_t len; const char *msg; msg = strerrordesc_np(err); if (msg == NULL) { msg = (char *) ngx_unknown_error.data; len = ngx_unknown_error.len; } else { len = ngx_strlen(msg); } size = ngx_min(size, len); return ngx_cpymem(errstr, msg, size); } ngx_int_t ngx_strerror_init(void) { return NGX_OK; } #else /* * The strerror() messages are copied because: * * 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. */ static ngx_str_t *ngx_sys_errlist; static ngx_err_t ngx_first_error; static ngx_err_t ngx_last_error; u_char * ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) { ngx_str_t *msg; if (err >= ngx_first_error && err < ngx_last_error) { msg = &ngx_sys_errlist[err - ngx_first_error]; } else { msg = &ngx_unknown_error; } size = ngx_min(size, msg->len); return ngx_cpymem(errstr, msg->data, size); } ngx_int_t ngx_strerror_init(void) { char *msg; u_char *p; size_t len; ngx_err_t err; #if (NGX_SYS_NERR) ngx_first_error = 0; ngx_last_error = NGX_SYS_NERR; #elif (EPERM > 1000 && EPERM < 0x7fffffff - 1000) /* * If number of errors is not known, and EPERM error code has large * but reasonable value, guess possible error codes based on the error * messages returned by strerror(), starting from EPERM. Notably, * this covers GNU/Hurd, where errors start at 0x40000001. */ for (err = EPERM; err > EPERM - 1000; err--) { ngx_set_errno(0); msg = strerror(err); if (errno == EINVAL || msg == NULL || strncmp(msg, "Unknown error", 13) == 0) { continue; } ngx_first_error = err; } for (err = EPERM; err < EPERM + 1000; err++) { ngx_set_errno(0); msg = strerror(err); if (errno == EINVAL || msg == NULL || strncmp(msg, "Unknown error", 13) == 0) { continue; } ngx_last_error = err + 1; } #else /* * If number of errors is not known, guess it based on the error * messages returned by strerror(). */ ngx_first_error = 0; for (err = 0; err < 1000; err++) { ngx_set_errno(0); msg = strerror(err); if (errno == EINVAL || msg == NULL || strncmp(msg, "Unknown error", 13) == 0) { continue; } ngx_last_error = err + 1; } #endif /* * ngx_strerror() is not ready to work at this stage, therefore, * malloc() is used and possible errors are logged using strerror(). */ len = (ngx_last_error - ngx_first_error) * sizeof(ngx_str_t); ngx_sys_errlist = malloc(len); if (ngx_sys_errlist == NULL) { goto failed; } for (err = ngx_first_error; err < ngx_last_error; err++) { msg = strerror(err); if (msg == NULL) { ngx_sys_errlist[err - ngx_first_error] = ngx_unknown_error; continue; } len = ngx_strlen(msg); p = malloc(len); if (p == NULL) { goto failed; } ngx_memcpy(p, msg, len); ngx_sys_errlist[err - ngx_first_error].len = len; ngx_sys_errlist[err - ngx_first_error].data = p; } return NGX_OK; failed: err = errno; ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err)); return NGX_ERROR; } #endif