summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornginx <nginx@nginx.org>2015-03-24 16:13:40 +0000
committerJon Kolb <kolbyjack@gmail.com>2015-03-24 16:13:40 +0000
commitae88e2338f6e27459ace8a23754afc5892c2c5be (patch)
tree94ab9dbb49d3a712d8f58ad3c442cfa375d646ef
parentaa248e453fd0df9623d5da0f13727049e69e503d (diff)
downloadnginx-1.7.11.tar.gz
Changes with nginx 1.7.11 24 Mar 2015v1.7.11
*) Change: the "sendfile" parameter of the "aio" directive is deprecated; now nginx automatically uses AIO to pre-load data for sendfile if both "aio" and "sendfile" directives are used. *) Feature: experimental thread pools support. *) Feature: the "proxy_request_buffering", "fastcgi_request_buffering", "scgi_request_buffering", and "uwsgi_request_buffering" directives. *) Feature: request body filters experimental API. *) Feature: client SSL certificates support in mail proxy. Thanks to Sven Peter, Franck Levionnois, and Filipe Da Silva. *) Feature: startup speedup when using the "hash ... consistent" directive in the upstream block. Thanks to Wai Keen Woon. *) Feature: debug logging into a cyclic memory buffer. *) Bugfix: in hash table handling. Thanks to Chris West. *) Bugfix: in the "proxy_cache_revalidate" directive. *) Bugfix: SSL connections might hang if deferred accept or the "proxy_protocol" parameter of the "listen" directive were used. Thanks to James Hamlin. *) Bugfix: the $upstream_response_time variable might contain a wrong value if the "image_filter" directive was used. *) Bugfix: in integer overflow handling. Thanks to Régis Leroy. *) Bugfix: it was not possible to enable SSLv3 with LibreSSL. *) Bugfix: the "ignoring stale global SSL error ... called a function you should not call" alerts appeared in logs when using LibreSSL. *) Bugfix: certificates specified by the "ssl_client_certificate" and "ssl_trusted_certificate" directives were inadvertently used to automatically construct certificate chains.
-rw-r--r--CHANGES47
-rw-r--r--CHANGES.ru51
-rw-r--r--auto/lib/openssl/make5
-rw-r--r--auto/modules6
-rw-r--r--auto/options5
-rw-r--r--auto/os/darwin1
-rw-r--r--auto/os/freebsd29
-rw-r--r--auto/sources20
-rw-r--r--auto/summary27
-rw-r--r--auto/threads20
-rw-r--r--auto/types/sizeof14
-rwxr-xr-xauto/unix24
-rwxr-xr-xconfigure1
-rw-r--r--src/core/nginx.c6
-rw-r--r--src/core/nginx.h4
-rw-r--r--src/core/ngx_buf.h13
-rw-r--r--src/core/ngx_config.h3
-rw-r--r--src/core/ngx_connection.c56
-rw-r--r--src/core/ngx_connection.h4
-rw-r--r--src/core/ngx_core.h4
-rw-r--r--src/core/ngx_cycle.c2
-rw-r--r--src/core/ngx_cycle.h8
-rw-r--r--src/core/ngx_file.h6
-rw-r--r--src/core/ngx_hash.c2
-rw-r--r--src/core/ngx_inet.c8
-rw-r--r--src/core/ngx_log.c129
-rw-r--r--src/core/ngx_output_chain.c113
-rw-r--r--src/core/ngx_parse.c80
-rw-r--r--src/core/ngx_regex.c6
-rw-r--r--src/core/ngx_spinlock.c2
-rw-r--r--src/core/ngx_string.c99
-rw-r--r--src/core/ngx_thread_pool.c630
-rw-r--r--src/core/ngx_thread_pool.h36
-rw-r--r--src/event/modules/ngx_aio_module.c2
-rw-r--r--src/event/modules/ngx_devpoll_module.c2
-rw-r--r--src/event/modules/ngx_epoll_module.c143
-rw-r--r--src/event/modules/ngx_eventport_module.c37
-rw-r--r--src/event/modules/ngx_kqueue_module.c210
-rw-r--r--src/event/modules/ngx_poll_module.c4
-rw-r--r--src/event/modules/ngx_rtsig_module.c2
-rw-r--r--src/event/modules/ngx_select_module.c4
-rw-r--r--src/event/modules/ngx_win32_select_module.c2
-rw-r--r--src/event/ngx_event.c6
-rw-r--r--src/event/ngx_event.h29
-rw-r--r--src/event/ngx_event_busy_lock.c286
-rw-r--r--src/event/ngx_event_busy_lock.h65
-rw-r--r--src/event/ngx_event_connect.h4
-rw-r--r--src/event/ngx_event_mutex.c70
-rw-r--r--src/event/ngx_event_openssl.c16
-rw-r--r--src/event/ngx_event_pipe.c8
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c360
-rw-r--r--src/http/modules/ngx_http_proxy_module.c245
-rw-r--r--src/http/modules/ngx_http_range_filter_module.c13
-rw-r--r--src/http/modules/ngx_http_scgi_module.c23
-rw-r--r--src/http/modules/ngx_http_ssl_module.c2
-rw-r--r--src/http/modules/ngx_http_upstream_hash_module.c52
-rw-r--r--src/http/modules/ngx_http_upstream_keepalive_module.c2
-rw-r--r--src/http/modules/ngx_http_uwsgi_module.c23
-rw-r--r--src/http/ngx_http.c5
-rw-r--r--src/http/ngx_http.h6
-rw-r--r--src/http/ngx_http_busy_lock.c307
-rw-r--r--src/http/ngx_http_busy_lock.h54
-rw-r--r--src/http/ngx_http_copy_filter_module.c177
-rw-r--r--src/http/ngx_http_core_module.c159
-rw-r--r--src/http/ngx_http_core_module.h17
-rw-r--r--src/http/ngx_http_file_cache.c14
-rw-r--r--src/http/ngx_http_parse.c12
-rw-r--r--src/http/ngx_http_request.c6
-rw-r--r--src/http/ngx_http_request.h8
-rw-r--r--src/http/ngx_http_request_body.c140
-rw-r--r--src/http/ngx_http_spdy.c2
-rw-r--r--src/http/ngx_http_upstream.c223
-rw-r--r--src/http/ngx_http_upstream.h1
-rw-r--r--src/http/ngx_http_upstream_round_robin.h2
-rw-r--r--src/http/ngx_http_variables.c4
-rw-r--r--src/http/ngx_http_write_filter_module.c4
-rw-r--r--src/mail/ngx_mail.c2
-rw-r--r--src/mail/ngx_mail.h2
-rw-r--r--src/mail/ngx_mail_auth_http_module.c151
-rw-r--r--src/mail/ngx_mail_core_module.c4
-rw-r--r--src/mail/ngx_mail_handler.c71
-rw-r--r--src/mail/ngx_mail_imap_module.c4
-rw-r--r--src/mail/ngx_mail_pop3_module.c4
-rw-r--r--src/mail/ngx_mail_smtp_module.c4
-rw-r--r--src/mail/ngx_mail_ssl_module.c89
-rw-r--r--src/mail/ngx_mail_ssl_module.h6
-rw-r--r--src/os/unix/ngx_file_aio_read.c42
-rw-r--r--src/os/unix/ngx_files.c109
-rw-r--r--src/os/unix/ngx_files.h6
-rw-r--r--src/os/unix/ngx_freebsd_config.h6
-rw-r--r--src/os/unix/ngx_freebsd_rfork_thread.c756
-rw-r--r--src/os/unix/ngx_freebsd_rfork_thread.h122
-rw-r--r--src/os/unix/ngx_freebsd_sendfile_chain.c77
-rw-r--r--src/os/unix/ngx_linux_aio_read.c39
-rw-r--r--src/os/unix/ngx_linux_config.h2
-rw-r--r--src/os/unix/ngx_linux_sendfile_chain.c265
-rw-r--r--src/os/unix/ngx_process_cycle.c189
-rw-r--r--src/os/unix/ngx_process_cycle.h1
-rw-r--r--src/os/unix/ngx_pthread_thread.c278
-rw-r--r--src/os/unix/ngx_thread.h109
-rw-r--r--src/os/unix/ngx_thread_cond.c87
-rw-r--r--src/os/unix/ngx_thread_id.c70
-rw-r--r--src/os/unix/ngx_thread_mutex.c174
-rw-r--r--src/os/unix/ngx_user.c20
-rw-r--r--src/os/unix/rfork_thread.S73
105 files changed, 3930 insertions, 3044 deletions
diff --git a/CHANGES b/CHANGES
index 1170db637..8c76b9580 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,51 @@
+Changes with nginx 1.7.11 24 Mar 2015
+
+ *) Change: the "sendfile" parameter of the "aio" directive is
+ deprecated; now nginx automatically uses AIO to pre-load data for
+ sendfile if both "aio" and "sendfile" directives are used.
+
+ *) Feature: experimental thread pools support.
+
+ *) Feature: the "proxy_request_buffering", "fastcgi_request_buffering",
+ "scgi_request_buffering", and "uwsgi_request_buffering" directives.
+
+ *) Feature: request body filters experimental API.
+
+ *) Feature: client SSL certificates support in mail proxy.
+ Thanks to Sven Peter, Franck Levionnois, and Filipe Da Silva.
+
+ *) Feature: startup speedup when using the "hash ... consistent"
+ directive in the upstream block.
+ Thanks to Wai Keen Woon.
+
+ *) Feature: debug logging into a cyclic memory buffer.
+
+ *) Bugfix: in hash table handling.
+ Thanks to Chris West.
+
+ *) Bugfix: in the "proxy_cache_revalidate" directive.
+
+ *) Bugfix: SSL connections might hang if deferred accept or the
+ "proxy_protocol" parameter of the "listen" directive were used.
+ Thanks to James Hamlin.
+
+ *) Bugfix: the $upstream_response_time variable might contain a wrong
+ value if the "image_filter" directive was used.
+
+ *) Bugfix: in integer overflow handling.
+ Thanks to Régis Leroy.
+
+ *) Bugfix: it was not possible to enable SSLv3 with LibreSSL.
+
+ *) Bugfix: the "ignoring stale global SSL error ... called a function
+ you should not call" alerts appeared in logs when using LibreSSL.
+
+ *) Bugfix: certificates specified by the "ssl_client_certificate" and
+ "ssl_trusted_certificate" directives were inadvertently used to
+ automatically construct certificate chains.
+
+
Changes with nginx 1.7.10 10 Feb 2015
*) Feature: the "use_temp_path" parameter of the "proxy_cache_path",
diff --git a/CHANGES.ru b/CHANGES.ru
index abb909b2e..7936c19cd 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,55 @@
+Изменения в nginx 1.7.11 24.03.2015
+
+ *) Изменение: параметр sendfile директивы aio более не нужен; теперь
+ nginx автоматически использует AIO для подгрузки данных для sendfile,
+ если одновременно используются директивы aio и sendfile.
+
+ *) Добавление: экспериментальная поддержка потоков.
+
+ *) Добавление: директивы proxy_request_buffering,
+ fastcgi_request_buffering, scgi_request_buffering и
+ uwsgi_request_buffering.
+
+ *) Добавление: экспериментальное API для обработки тела запроса.
+
+ *) Добавление: проверка клиентских SSL-сертификатов в почтовом
+ прокси-сервере.
+ Спасибо Sven Peter, Franck Levionnois и Filipe Da Silva.
+
+ *) Добавление: уменьшение времени запуска при использовании дирекивы
+ "hash ... consistent" в блоке upstream.
+ Спасибо Wai Keen Woon.
+
+ *) Добавление: отладочное логгирование в кольцевой буфер в памяти.
+
+ *) Исправление: в обработке хэш-таблиц.
+ Спасибо Chris West.
+
+ *) Исправление: в директиве proxy_cache_revalidate.
+
+ *) Исправление: SSL-соединения могли зависать, если использовался
+ отложенный accept или параметр proxy_protocol директивы listen.
+ Спасибо James Hamlin.
+
+ *) Исправление: переменная $upstream_response_time могла содержать
+ неверное значение при использовании директивы image_filter.
+
+ *) Исправление: в обработке целочисленных переполнений.
+ Спасибо Régis Leroy.
+
+ *) Исправление: при использовании LibreSSL было невозможно включить
+ поддержку SSLv3.
+
+ *) Исправление: при использовании LibreSSL в логах появлялись сообщения
+ "ignoring stale global SSL error ... called a function you should not
+ call".
+
+ *) Исправление: сертификаты, указанные в директивах
+ ssl_client_certificate и ssl_trusted_certificate, использовались для
+ автоматического построения цепочек сертификатов.
+
+
Изменения в nginx 1.7.10 10.02.2015
*) Добавление: параметр use_temp_path директив proxy_cache_path,
diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make
index e64acd973..765cd0653 100644
--- a/auto/lib/openssl/make
+++ b/auto/lib/openssl/make
@@ -41,11 +41,6 @@ END
;;
*)
- case $USE_THREADS in
- NO) OPENSSL_OPT="$OPENSSL_OPT no-threads" ;;
- *) OPENSSL_OPT="$OPENSSL_OPT threads" ;;
- esac
-
case $OPENSSL in
/*) ngx_prefix="$OPENSSL/.openssl" ;;
*) ngx_prefix="$PWD/$OPENSSL/.openssl" ;;
diff --git a/auto/modules b/auto/modules
index 788596763..5a56957b8 100644
--- a/auto/modules
+++ b/auto/modules
@@ -432,6 +432,12 @@ fi
modules="$CORE_MODULES $EVENT_MODULES"
+# thread pool module should be initialized after events
+if [ $USE_THREADS = YES ]; then
+ modules="$modules $THREAD_POOL_MODULE"
+fi
+
+
if [ $USE_OPENSSL = YES ]; then
modules="$modules $OPENSSL_MODULE"
CORE_DEPS="$CORE_DEPS $OPENSSL_DEPS"
diff --git a/auto/options b/auto/options
index 0d296ac60..763871f7b 100644
--- a/auto/options
+++ b/auto/options
@@ -190,8 +190,7 @@ do
--without-poll_module) EVENT_POLL=NONE ;;
--with-aio_module) EVENT_AIO=YES ;;
- #--with-threads=*) USE_THREADS="$value" ;;
- #--with-threads) USE_THREADS="pthreads" ;;
+ --with-threads) USE_THREADS=YES ;;
--with-file-aio) NGX_FILE_AIO=YES ;;
--with-ipv6) NGX_IPV6=YES ;;
@@ -354,6 +353,8 @@ cat << END
--with-poll_module enable poll module
--without-poll_module disable poll module
+ --with-threads enable thread pool support
+
--with-file-aio enable file AIO support
--with-ipv6 enable IPv6 support
diff --git a/auto/os/darwin b/auto/os/darwin
index b97518a6e..1d3e3d393 100644
--- a/auto/os/darwin
+++ b/auto/os/darwin
@@ -100,7 +100,6 @@ ngx_feature_test="int s = 0, fd = 1;
. auto/feature
if [ $ngx_found = yes ]; then
- have=NGX_HAVE_SENDFILE . auto/have
CORE_SRCS="$CORE_SRCS $DARWIN_SENDFILE_SRCS"
fi
diff --git a/auto/os/freebsd b/auto/os/freebsd
index 6aa823f92..6c696326b 100644
--- a/auto/os/freebsd
+++ b/auto/os/freebsd
@@ -44,10 +44,12 @@ if [ $osreldate -gt 300007 ]; then
CORE_SRCS="$CORE_SRCS $FREEBSD_SENDFILE_SRCS"
fi
-if [ $osreldate -gt 502103 ]; then
- echo " + sendfile()'s SF_NODISKIO found"
+if [ $NGX_FILE_AIO = YES ]; then
+ if [ $osreldate -gt 502103 ]; then
+ echo " + sendfile()'s SF_NODISKIO found"
- have=NGX_HAVE_AIO_SENDFILE . auto/have
+ have=NGX_HAVE_AIO_SENDFILE . auto/have
+ fi
fi
# POSIX semaphores
@@ -78,7 +80,7 @@ fi
NGX_KQUEUE_CHECKED=YES
-# kqueue's NOTE_LAWAT
+# kqueue's NOTE_LOWAT
if [ \( $version -lt 500000 -a $version -ge 430000 \) \
-o $version -ge 500018 ]
@@ -97,25 +99,6 @@ then
fi
-if [ $USE_THREADS = "rfork" ]; then
-
- echo " + using rfork()"
-
-# # kqueue's EVFILT_SIGNAL is safe
-#
-# if [ $version -gt 460101 ]; then
-# echo " + kqueue's EVFILT_SIGNAL is safe"
-# have=NGX_HAVE_SAFE_EVFILT_SIGNAL . auto/have
-# else
-# echo "$0: error: the kqueue's EVFILT_SIGNAL is unsafe on this"
-# echo "FreeBSD version, so --with-threads=rfork could not be used"
-# echo
-#
-# exit 1
-# fi
-fi
-
-
if [ $EVENT_AIO = YES ]; then
if [ \( $version -lt 500000 -a $version -ge 430000 \) \
-o $version -ge 500014 ]
diff --git a/auto/sources b/auto/sources
index 1287782ea..90037894f 100644
--- a/auto/sources
+++ b/auto/sources
@@ -92,14 +92,12 @@ EVENT_INCS="src/event src/event/modules"
EVENT_DEPS="src/event/ngx_event.h \
src/event/ngx_event_timer.h \
src/event/ngx_event_posted.h \
- src/event/ngx_event_busy_lock.h \
src/event/ngx_event_connect.h \
src/event/ngx_event_pipe.h"
EVENT_SRCS="src/event/ngx_event.c \
src/event/ngx_event_timer.c \
src/event/ngx_event_posted.c \
- src/event/ngx_event_busy_lock.c \
src/event/ngx_event_accept.c \
src/event/ngx_event_connect.c \
src/event/ngx_event_pipe.c"
@@ -193,14 +191,16 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \
POSIX_DEPS=src/os/unix/ngx_posix_config.h
+THREAD_POOL_MODULE=ngx_thread_pool_module
+THREAD_POOL_DEPS=src/core/ngx_thread_pool.h
+THREAD_POOL_SRCS="src/core/ngx_thread_pool.c
+ src/os/unix/ngx_thread_cond.c
+ src/os/unix/ngx_thread_mutex.c
+ src/os/unix/ngx_thread_id.c"
+
FREEBSD_DEPS="src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_freebsd.h"
FREEBSD_SRCS=src/os/unix/ngx_freebsd_init.c
FREEBSD_SENDFILE_SRCS=src/os/unix/ngx_freebsd_sendfile_chain.c
-FREEBSD_RFORK_DEPS="src/os/unix/ngx_freebsd_rfork_thread.h"
-FREEBSD_RFORK_SRCS="src/os/unix/ngx_freebsd_rfork_thread.c"
-FREEBSD_RFORK_THREAD_SRCS="src/os/unix/rfork_thread.S"
-
-PTHREAD_SRCS="src/os/unix/ngx_pthread_thread.c"
LINUX_DEPS="src/os/unix/ngx_linux_config.h src/os/unix/ngx_linux.h"
LINUX_SRCS=src/os/unix/ngx_linux_init.c
@@ -295,8 +295,7 @@ HTTP_DEPS="src/http/ngx_http.h \
src/http/ngx_http_variables.h \
src/http/ngx_http_script.h \
src/http/ngx_http_upstream.h \
- src/http/ngx_http_upstream_round_robin.h \
- src/http/ngx_http_busy_lock.h"
+ src/http/ngx_http_upstream_round_robin.h"
HTTP_SRCS="src/http/ngx_http.c \
src/http/ngx_http_core_module.c \
@@ -320,9 +319,6 @@ HTTP_SRCS="src/http/ngx_http.c \
src/http/modules/ngx_http_headers_filter_module.c \
src/http/modules/ngx_http_not_modified_filter_module.c"
-# STUB
-HTTP_SRCS="$HTTP_SRCS src/http/ngx_http_busy_lock.c"
-
HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c
HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c
diff --git a/auto/summary b/auto/summary
index dcebec9f0..1be975d82 100644
--- a/auto/summary
+++ b/auto/summary
@@ -3,34 +3,13 @@
# Copyright (C) Nginx, Inc.
-### STUB
-
-if [ $USE_THREADS != NO ]; then
-
-cat << END
-
-$0: error: the threads support is broken now.
-
-END
- exit 1
- fi
-
-###
-
-
echo
echo "Configuration summary"
-#case $USE_THREADS in
-# rfork) echo " + using rfork()ed threads" ;;
-# pthreads) echo " + using libpthread threads library" ;;
-# libthr) echo " + using FreeBSD libthr threads library" ;;
-# libc_r) echo " + using FreeBSD libc_r threads library" ;;
-# linuxthreads) echo " + using FreeBSD LinuxThreads port library" ;;
-# NO) echo " + threads are not used" ;;
-# *) echo " + using lib$USE_THREADS threads library" ;;
-#esac
+if [ $USE_THREADS = YES ]; then
+ echo " + using threads"
+fi
if [ $USE_PCRE = DISABLED ]; then
echo " + PCRE library is disabled"
diff --git a/auto/threads b/auto/threads
new file mode 100644
index 000000000..381f07ac3
--- /dev/null
+++ b/auto/threads
@@ -0,0 +1,20 @@
+
+# Copyright (C) Nginx, Inc.
+
+
+if [ $USE_THREADS = YES ]; then
+
+ if [ "$NGX_PLATFORM" = win32 ]; then
+ cat << END
+
+$0: --with-threads is not supported on Windows
+
+END
+ exit 1
+ fi
+
+ have=NGX_THREADS . auto/have
+ CORE_DEPS="$CORE_DEPS $THREAD_POOL_DEPS"
+ CORE_SRCS="$CORE_SRCS $THREAD_POOL_SRCS"
+ CORE_LIBS="$CORE_LIBS -lpthread"
+fi
diff --git a/auto/types/sizeof b/auto/types/sizeof
index 9215a545f..a5f66bbd9 100644
--- a/auto/types/sizeof
+++ b/auto/types/sizeof
@@ -50,22 +50,12 @@ rm -rf $NGX_AUTOTEST*
case $ngx_size in
4)
- if [ "$ngx_type"="long" ]; then
- ngx_max_value=2147483647L
- else
- ngx_max_value=2147483647
- fi
-
+ ngx_max_value=2147483647
ngx_max_len='(sizeof("-2147483648") - 1)'
;;
8)
- if [ "$ngx_type"="long long" ]; then
- ngx_max_value=9223372036854775807LL
- else
- ngx_max_value=9223372036854775807L
- fi
-
+ ngx_max_value=9223372036854775807LL
ngx_max_len='(sizeof("-9223372036854775808") - 1)'
;;
diff --git a/auto/unix b/auto/unix
index 9b4764c6d..6e54531c9 100755
--- a/auto/unix
+++ b/auto/unix
@@ -450,6 +450,29 @@ Currently file AIO is supported on FreeBSD 4.3+ and Linux 2.6.22+ only
END
exit 1
fi
+
+else
+
+ ngx_feature="eventfd()"
+ ngx_feature_name="NGX_HAVE_EVENTFD"
+ ngx_feature_run=no
+ ngx_feature_incs="#include <sys/eventfd.h>"
+ ngx_feature_path=
+ ngx_feature_libs=
+ ngx_feature_test="(void) eventfd(0, 0)"
+ . auto/feature
+
+ if [ $ngx_found = yes ]; then
+ have=NGX_HAVE_SYS_EVENTFD_H . auto/have
+ fi
+
+ if [ $ngx_found = no ]; then
+
+ ngx_feature="eventfd() (SYS_eventfd)"
+ ngx_feature_incs="#include <sys/syscall.h>"
+ ngx_feature_test="int n = SYS_eventfd"
+ . auto/feature
+ fi
fi
@@ -510,6 +533,7 @@ ngx_param=NGX_OFF_T_LEN; ngx_value=$ngx_max_len; . auto/types/value
ngx_type="time_t"; . auto/types/sizeof
ngx_param=NGX_TIME_T_SIZE; ngx_value=$ngx_size; . auto/types/value
ngx_param=NGX_TIME_T_LEN; ngx_value=$ngx_max_len; . auto/types/value
+ngx_param=NGX_MAX_TIME_T_VALUE; ngx_value=$ngx_max_value; . auto/types/value
# syscalls, libc calls and some features
diff --git a/configure b/configure
index e8929b8f0..617d992b8 100755
--- a/configure
+++ b/configure
@@ -58,6 +58,7 @@ if [ "$NGX_PLATFORM" != win32 ]; then
. auto/unix
fi
+. auto/threads
. auto/modules
. auto/lib/conf
diff --git a/src/core/nginx.c b/src/core/nginx.c
index c75ee4fd7..feb861a11 100644
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -139,7 +139,7 @@ static ngx_command_t ngx_core_commands[] = {
0,
NULL },
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
{ ngx_string("worker_threads"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
@@ -959,7 +959,7 @@ ngx_core_module_create_conf(ngx_cycle_t *cycle)
ccf->user = (ngx_uid_t) NGX_CONF_UNSET_UINT;
ccf->group = (ngx_gid_t) NGX_CONF_UNSET_UINT;
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
ccf->worker_threads = NGX_CONF_UNSET;
ccf->thread_stack_size = NGX_CONF_UNSET_SIZE;
#endif
@@ -1000,7 +1000,7 @@ ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf)
#endif
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
ngx_conf_init_value(ccf->worker_threads, 0);
ngx_threads_n = ccf->worker_threads;
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 93dc82d64..2e84845d2 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
-#define nginx_version 1007010
-#define NGINX_VERSION "1.7.10"
+#define nginx_version 1007011
+#define NGINX_VERSION "1.7.11"
#define NGINX_VER "nginx/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h
index 13536a69a..f652b20ef 100644
--- a/src/core/ngx_buf.h
+++ b/src/core/ngx_buf.h
@@ -90,10 +90,21 @@ struct ngx_output_chain_ctx_s {
#endif
unsigned need_in_memory:1;
unsigned need_in_temp:1;
-#if (NGX_HAVE_FILE_AIO)
+#if (NGX_HAVE_FILE_AIO || NGX_THREADS)
unsigned aio:1;
+#endif
+#if (NGX_HAVE_FILE_AIO)
ngx_output_chain_aio_pt aio_handler;
+#if (NGX_HAVE_AIO_SENDFILE)
+ ssize_t (*aio_preload)(ngx_buf_t *file);
+#endif
+#endif
+
+#if (NGX_THREADS)
+ ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
+ ngx_file_t *file);
+ ngx_thread_task_t *thread_task;
#endif
off_t alignment;
diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h
index 1da71f8d1..145e43a44 100644
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -85,8 +85,11 @@ typedef intptr_t ngx_flag_t;
#if (NGX_PTR_SIZE == 4)
#define NGX_INT_T_LEN NGX_INT32_LEN
+#define NGX_MAX_INT_T_VALUE 2147483647
+
#else
#define NGX_INT_T_LEN NGX_INT64_LEN
+#define NGX_MAX_INT_T_VALUE 9223372036854775807
#endif
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index b687d76b2..9f8fbc363 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -835,8 +835,6 @@ ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
return NULL;
}
- /* ngx_mutex_lock */
-
c = ngx_cycle->free_connections;
if (c == NULL) {
@@ -849,16 +847,12 @@ ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
"%ui worker_connections are not enough",
ngx_cycle->connection_n);
- /* ngx_mutex_unlock */
-
return NULL;
}
ngx_cycle->free_connections = c->data;
ngx_cycle->free_connection_n--;
- /* ngx_mutex_unlock */
-
if (ngx_cycle->files) {
ngx_cycle->files[s] = c;
}
@@ -896,14 +890,10 @@ ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
void
ngx_free_connection(ngx_connection_t *c)
{
- /* ngx_mutex_lock */
-
c->data = ngx_cycle->free_connections;
ngx_cycle->free_connections = c;
ngx_cycle->free_connection_n++;
- /* ngx_mutex_unlock */
-
if (ngx_cycle->files) {
ngx_cycle->files[c->fd] = NULL;
}
@@ -943,18 +933,6 @@ ngx_close_connection(ngx_connection_t *c)
}
}
-#if (NGX_THREADS)
-
- /*
- * we have to clean the connection information before the closing
- * because another thread may reopen the same file descriptor
- * before we clean the connection
- */
-
- ngx_unlock(&c->lock);
-
-#endif
-
if (c->read->posted) {
ngx_delete_posted_event(c->read);
}
@@ -1073,33 +1051,33 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
struct sockaddr_in6 *sin6;
#endif
- if (c->local_socklen == 0) {
- return NGX_ERROR;
- }
+ addr = 0;
- switch (c->local_sockaddr->sa_family) {
+ if (c->local_socklen) {
+ switch (c->local_sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
- for (addr = 0, i = 0; addr == 0 && i < 16; i++) {
- addr |= sin6->sin6_addr.s6_addr[i];
- }
+ for (i = 0; addr == 0 && i < 16; i++) {
+ addr |= sin6->sin6_addr.s6_addr[i];
+ }
- break;
+ break;
#endif
#if (NGX_HAVE_UNIX_DOMAIN)
- case AF_UNIX:
- addr = 1;
- break;
+ case AF_UNIX:
+ addr = 1;
+ break;
#endif
- default: /* AF_INET */
- sin = (struct sockaddr_in *) c->local_sockaddr;
- addr = sin->sin_addr.s_addr;
- break;
+ default: /* AF_INET */
+ sin = (struct sockaddr_in *) c->local_sockaddr;
+ addr = sin->sin_addr.s_addr;
+ break;
+ }
}
if (addr == 0) {
diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h
index ed14e6023..f1ca9619b 100644
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -181,13 +181,11 @@ struct ngx_connection_s {
#endif
#if (NGX_HAVE_AIO_SENDFILE)
- unsigned aio_sendfile:1;
unsigned busy_count:2;
- ngx_buf_t *busy_sendfile;
#endif
#if (NGX_THREADS)
- ngx_atomic_t lock;
+ ngx_thread_task_t *sendfile_task;
#endif
};
diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h
index aeea0c68b..bc1d43f98 100644
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -22,6 +22,10 @@ typedef struct ngx_event_s ngx_event_t;
typedef struct ngx_event_aio_s ngx_event_aio_t;
typedef struct ngx_connection_s ngx_connection_t;
+#if (NGX_THREADS)
+typedef struct ngx_thread_task_s ngx_thread_task_t;
+#endif
+
typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
index d69783fec..11e413f4e 100644
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -26,7 +26,7 @@ static ngx_event_t ngx_cleaner_event;
ngx_uint_t ngx_test_config;
ngx_uint_t ngx_quiet_mode;
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
ngx_tls_key_t ngx_core_tls_key;
#endif
diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h
index 21bf5ca3f..be90a7281 100644
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -103,7 +103,7 @@ typedef struct {
ngx_array_t env;
char **environment;
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
ngx_int_t worker_threads;
size_t thread_stack_size;
#endif
@@ -111,10 +111,14 @@ typedef struct {
} ngx_core_conf_t;
+#if (NGX_OLD_THREADS)
+
typedef struct {
ngx_pool_t *pool; /* pcre's malloc() pool */
} ngx_core_tls_t;
+#endif
+
#define ngx_is_init_cycle(cycle) (cycle->conf_ctx == NULL)
@@ -136,7 +140,7 @@ extern ngx_array_t ngx_old_cycles;
extern ngx_module_t ngx_core_module;
extern ngx_uint_t ngx_test_config;
extern ngx_uint_t ngx_quiet_mode;
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
extern ngx_tls_key_t ngx_core_tls_key;
#endif
diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h
index 3ea6c28c8..301b1918b 100644
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -23,6 +23,12 @@ struct ngx_file_s {
ngx_log_t *log;
+#if (NGX_THREADS)
+ ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
+ ngx_file_t *file);
+ void *thread_ctx;
+#endif
+
#if (NGX_HAVE_FILE_AIO)
ngx_event_aio_t *aio;
#endif
diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c
index 65ad83947..e707c0998 100644
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -312,7 +312,7 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
continue;
}
- size--;
+ size = hinit->max_size;
ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0,
"could not build optimal %s, you should increase "
diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c
index 26c5bc4b0..2c84daf6e 100644
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -27,6 +27,10 @@ ngx_inet_addr(u_char *text, size_t len)
for (p = text; p < text + len; p++) {
+ if (octet > 255) {
+ return INADDR_NONE;
+ }
+
c = *p;
if (c >= '0' && c <= '9') {
@@ -34,7 +38,7 @@ ngx_inet_addr(u_char *text, size_t len)
continue;
}
- if (c == '.' && octet < 256) {
+ if (c == '.') {
addr = (addr << 8) + octet;
octet = 0;
n++;
@@ -44,7 +48,7 @@ ngx_inet_addr(u_char *text, size_t len)
return INADDR_NONE;
}
- if (n == 3 && octet < 256) {
+ if (n == 3) {
addr = (addr << 8) + octet;
return htonl(addr);
}
diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c
index 0cf235998..bf0050885 100644
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -14,6 +14,23 @@ static char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log);
static void ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log);
+#if (NGX_DEBUG)
+
+static void ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level,
+ u_char *buf, size_t len);
+static void ngx_log_memory_cleanup(void *data);
+
+
+typedef struct {
+ u_char *start;
+ u_char *end;
+ u_char *pos;
+ ngx_atomic_t written;
+} ngx_log_memory_buf_t;
+
+#endif
+
+
static ngx_command_t ngx_errlog_commands[] = {
{ngx_string("error_log"),
@@ -97,10 +114,8 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
last = errstr + NGX_MAX_ERROR_STR;
- ngx_memcpy(errstr, ngx_cached_err_log_time.data,
- ngx_cached_err_log_time.len);
-
- p = errstr + ngx_cached_err_log_time.len;
+ p = ngx_cpymem(errstr, ngx_cached_err_log_time.data,
+ ngx_cached_err_log_time.len);
p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]);
@@ -248,9 +263,8 @@ ngx_log_stderr(ngx_err_t err, const char *fmt, ...)
u_char errstr[NGX_MAX_ERROR_STR];
last = errstr + NGX_MAX_ERROR_STR;
- p = errstr + 7;
- ngx_memcpy(errstr, "nginx: ", 7);
+ p = ngx_cpymem(errstr, "nginx: ", 7);
va_start(args, fmt);
p = ngx_vslprintf(p, last, fmt, args);
@@ -571,6 +585,64 @@ ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head)
return NGX_CONF_ERROR;
}
+ } else if (ngx_strncmp(value[1].data, "memory:", 7) == 0) {
+
+#if (NGX_DEBUG)
+ size_t size, needed;
+ ngx_pool_cleanup_t *cln;
+ ngx_log_memory_buf_t *buf;
+
+ value[1].len -= 7;
+ value[1].data += 7;
+
+ needed = sizeof("MEMLOG :" NGX_LINEFEED)
+ + cf->conf_file->file.name.len
+ + NGX_SIZE_T_LEN
+ + NGX_INT_T_LEN
+ + NGX_MAX_ERROR_STR;
+
+ size = ngx_parse_size(&value[1]);
+
+ if (size == (size_t) NGX_ERROR || size < needed) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid buffer size \"%V\"", &value[1]);
+ return NGX_CONF_ERROR;
+ }
+
+ buf = ngx_palloc(cf->pool, sizeof(ngx_log_memory_buf_t));
+ if (buf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ buf->start = ngx_pnalloc(cf->pool, size);
+ if (buf->start == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ buf->end = buf->start + size;
+
+ buf->pos = ngx_slprintf(buf->start, buf->end, "MEMLOG %uz %V:%ui%N",
+ size, &cf->conf_file->file.name,
+ cf->conf_file->line);
+
+ ngx_memset(buf->pos, ' ', buf->end - buf->pos);
+
+ cln = ngx_pool_cleanup_add(cf->pool, 0);
+ if (cln == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ cln->data = new_log;
+ cln->handler = ngx_log_memory_cleanup;
+
+ new_log->writer = ngx_log_memory_writer;
+ new_log->wdata = buf;
+
+#else
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "nginx was built without debug support");
+ return NGX_CONF_ERROR;
+#endif
} else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
@@ -636,3 +708,48 @@ ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log)
log->next = new_log;
}
+
+
+#if (NGX_DEBUG)
+
+static void
+ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
+ size_t len)
+{
+ u_char *p;
+ size_t avail, written;
+ ngx_log_memory_buf_t *mem;
+
+ mem = log->wdata;
+
+ if (mem == NULL) {
+ return;
+ }
+
+ written = ngx_atomic_fetch_add(&mem->written, len);
+
+ p = mem->pos + written % (mem->end - mem->pos);
+
+ avail = mem->end - p;
+
+ if (avail >= len) {
+ ngx_memcpy(p, buf, len);
+
+ } else {
+ ngx_memcpy(p, buf, avail);
+ ngx_memcpy(mem->pos, buf + avail, len - avail);
+ }
+}
+
+
+static void
+ngx_log_memory_cleanup(void *data)
+{
+ ngx_log_t *log = data;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "destroy memory log buffer");
+
+ log->wdata = NULL;
+}
+
+#endif
diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c
index 9d7a8460f..252359af6 100644
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -29,6 +29,10 @@
static ngx_inline ngx_int_t
ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf);
+#if (NGX_HAVE_AIO_SENDFILE)
+static ngx_int_t ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx,
+ ngx_file_t *file);
+#endif
static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool,
ngx_chain_t **chain, ngx_chain_t *in);
static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx,
@@ -46,7 +50,7 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
ngx_chain_t *cl, *out, **last_out;
if (ctx->in == NULL && ctx->busy == NULL
-#if (NGX_HAVE_FILE_AIO)
+#if (NGX_HAVE_FILE_AIO || NGX_THREADS)
&& !ctx->aio
#endif
)
@@ -85,7 +89,7 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
for ( ;; ) {
-#if (NGX_HAVE_FILE_AIO)
+#if (NGX_HAVE_FILE_AIO || NGX_THREADS)
if (ctx->aio) {
return NGX_AGAIN;
}
@@ -229,6 +233,13 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
return 1;
}
+#if (NGX_THREADS)
+ if (buf->in_file) {
+ buf->file->thread_handler = ctx->thread_handler;
+ buf->file->thread_ctx = ctx->filter_ctx;
+ }
+#endif
+
if (buf->in_file && buf->file->directio) {
return 0;
}
@@ -252,6 +263,12 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
buf->in_file = 0;
}
+#if (NGX_HAVE_AIO_SENDFILE)
+ if (ctx->aio_preload && buf->in_file) {
+ (void) ngx_output_chain_aio_setup(ctx, buf->file);
+ }
+#endif
+
if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
return 0;
}
@@ -264,6 +281,28 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
}
+#if (NGX_HAVE_AIO_SENDFILE)
+
+static ngx_int_t
+ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, ngx_file_t *file)
+{
+ ngx_event_aio_t *aio;
+
+ if (file->aio == NULL && ngx_file_aio_init(file, ctx->pool) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ aio = file->aio;
+
+ aio->data = ctx->filter_ctx;
+ aio->preload_handler = ctx->aio_preload;
+
+ return NGX_OK;
+}
+
+#endif
+
+
static ngx_int_t
ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
ngx_chain_t *in)
@@ -527,7 +566,6 @@ ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx)
#endif
#if (NGX_HAVE_FILE_AIO)
-
if (ctx->aio_handler) {
n = ngx_file_aio_read(src->file, dst->pos, (size_t) size,
src->file_pos, ctx->pool);
@@ -536,15 +574,23 @@ ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx)
return NGX_AGAIN;
}
- } else {
+ } else
+#endif
+#if (NGX_THREADS)
+ if (src->file->thread_handler) {
+ n = ngx_thread_read(&ctx->thread_task, src->file, dst->pos,
+ (size_t) size, src->file_pos, ctx->pool);
+ if (n == NGX_AGAIN) {
+ ctx->aio = 1;
+ return NGX_AGAIN;
+ }
+
+ } else
+#endif
+ {
n = ngx_read_file(src->file, dst->pos, (size_t) size,
src->file_pos);
}
-#else
-
- n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos);
-
-#endif
#if (NGX_HAVE_ALIGNED_DIRECTIO)
@@ -608,7 +654,7 @@ ngx_chain_writer(void *data, ngx_chain_t *in)
ngx_chain_writer_ctx_t *ctx = data;
off_t size;
- ngx_chain_t *cl;
+ ngx_chain_t *cl, *ln, *chain;
ngx_connection_t *c;
c = ctx->connection;
@@ -617,7 +663,23 @@ ngx_chain_writer(void *data, ngx_chain_t *in)
#if 1
if (ngx_buf_size(in->buf) == 0 && !ngx_buf_special(in->buf)) {
+
+ ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
+ "zero size buf in chain writer "
+ "t:%d r:%d f:%d %p %p-%p %p %O-%O",
+ in->buf->temporary,
+ in->buf->recycled,
+ in->buf->in_file,
+ in->buf->start,
+ in->buf->pos,
+ in->buf->last,
+ in->buf->file,
+ in->buf->file_pos,
+ in->buf->file_last);
+
ngx_debug_point();
+
+ continue;
}
#endif
@@ -645,9 +707,24 @@ ngx_chain_writer(void *data, ngx_chain_t *in)
#if 1
if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
+
+ ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
+ "zero size buf in chain writer "
+ "t:%d r:%d f:%d %p %p-%p %p %O-%O",
+ cl->buf->temporary,
+ cl->buf->recycled,
+ cl->buf->in_file,
+ cl->buf->start,
+ cl->buf->pos,
+ cl->buf->last,
+ cl->buf->file,
+ cl->buf->file_pos,
+ cl->buf->file_last);
+
ngx_debug_point();
- }
+ continue;
+ }
#endif
size += ngx_buf_size(cl->buf);
@@ -657,15 +734,23 @@ ngx_chain_writer(void *data, ngx_chain_t *in)
return NGX_OK;
}
- ctx->out = c->send_chain(c, ctx->out, ctx->limit);
+ chain = c->send_chain(c, ctx->out, ctx->limit);
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
- "chain writer out: %p", ctx->out);
+ "chain writer out: %p", chain);
- if (ctx->out == NGX_CHAIN_ERROR) {
+ if (chain == NGX_CHAIN_ERROR) {
return NGX_ERROR;
}
+ for (cl = ctx->out; cl && cl != chain; /* void */) {
+ ln = cl;
+ cl = cl->next;
+ ngx_free_chain(ctx->pool, ln);
+ }
+
+ ctx->out = chain;
+
if (ctx->out == NULL) {
ctx->last = &ctx->out;
diff --git a/src/core/ngx_parse.c b/src/core/ngx_parse.c
index da24f4c75..d7350d423 100644
--- a/src/core/ngx_parse.c
+++ b/src/core/ngx_parse.c
@@ -12,10 +12,9 @@
ssize_t
ngx_parse_size(ngx_str_t *line)
{
- u_char unit;
- size_t len;
- ssize_t size;
- ngx_int_t scale;
+ u_char unit;
+ size_t len;
+ ssize_t size, scale, max;
len = line->len;
unit = line->data[len - 1];
@@ -24,21 +23,24 @@ ngx_parse_size(ngx_str_t *line)
case 'K':
case 'k':
len--;
+ max = NGX_MAX_SIZE_T_VALUE / 1024;
scale = 1024;
break;
case 'M':
case 'm':
len--;
+ max = NGX_MAX_SIZE_T_VALUE / (1024 * 1024);
scale = 1024 * 1024;
break;
default:
+ max = NGX_MAX_SIZE_T_VALUE;
scale = 1;
}
size = ngx_atosz(line->data, len);
- if (size == NGX_ERROR) {
+ if (size == NGX_ERROR || size > max) {
return NGX_ERROR;
}
@@ -51,10 +53,9 @@ ngx_parse_size(ngx_str_t *line)
off_t
ngx_parse_offset(ngx_str_t *line)
{
- u_char unit;
- off_t offset;
- size_t len;
- ngx_int_t scale;
+ u_char unit;
+ off_t offset, scale, max;
+ size_t len;
len = line->len;
unit = line->data[len - 1];
@@ -63,27 +64,31 @@ ngx_parse_offset(ngx_str_t *line)
case 'K':
case 'k':
len--;
+ max = NGX_MAX_OFF_T_VALUE / 1024;
scale = 1024;
break;
case 'M':
case 'm':
len--;
+ max = NGX_MAX_OFF_T_VALUE / (1024 * 1024);
scale = 1024 * 1024;
break;
case 'G':
case 'g':
len--;
+ max = NGX_MAX_OFF_T_VALUE / (1024 * 1024 * 1024);
scale = 1024 * 1024 * 1024;
break;
default:
+ max = NGX_MAX_OFF_T_VALUE;
scale = 1;
}
offset = ngx_atoof(line->data, len);
- if (offset == NGX_ERROR) {
+ if (offset == NGX_ERROR || offset > max) {
return NGX_ERROR;
}
@@ -98,7 +103,8 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
{
u_char *p, *last;
ngx_int_t value, total, scale;
- ngx_uint_t max, valid;
+ ngx_int_t max, cutoff, cutlim;
+ ngx_uint_t valid;
enum {
st_start = 0,
st_year,
@@ -115,8 +121,9 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
valid = 0;
value = 0;
total = 0;
+ cutoff = NGX_MAX_INT_T_VALUE / 10;
+ cutlim = NGX_MAX_INT_T_VALUE % 10;
step = is_sec ? st_start : st_month;
- scale = is_sec ? 1 : 1000;
p = line->data;
last = p + line->len;
@@ -124,6 +131,10 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
while (p < last) {
if (*p >= '0' && *p <= '9') {
+ if (value >= cutoff && (value > cutoff || *p - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
value = value * 10 + (*p++ - '0');
valid = 1;
continue;
@@ -136,7 +147,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
return NGX_ERROR;
}
step = st_year;
- max = NGX_MAX_INT32_VALUE / (60 * 60 * 24 * 365);
+ max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 365);
scale = 60 * 60 * 24 * 365;
break;
@@ -145,7 +156,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
return NGX_ERROR;
}
step = st_month;
- max = NGX_MAX_INT32_VALUE / (60 * 60 * 24 * 30);
+ max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 30);
scale = 60 * 60 * 24 * 30;
break;
@@ -154,7 +165,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
return NGX_ERROR;
}
step = st_week;
- max = NGX_MAX_INT32_VALUE / (60 * 60 * 24 * 7);
+ max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 7);
scale = 60 * 60 * 24 * 7;
break;
@@ -163,7 +174,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
return NGX_ERROR;
}
step = st_day;
- max = NGX_MAX_INT32_VALUE / (60 * 60 * 24);
+ max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24);
scale = 60 * 60 * 24;
break;
@@ -172,7 +183,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
return NGX_ERROR;
}
step = st_hour;
- max = NGX_MAX_INT32_VALUE / (60 * 60);
+ max = NGX_MAX_INT_T_VALUE / (60 * 60);
scale = 60 * 60;
break;
@@ -183,7 +194,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
}
p++;
step = st_msec;
- max = NGX_MAX_INT32_VALUE;
+ max = NGX_MAX_INT_T_VALUE;
scale = 1;
break;
}
@@ -192,7 +203,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
return NGX_ERROR;
}
step = st_min;
- max = NGX_MAX_INT32_VALUE / 60;
+ max = NGX_MAX_INT_T_VALUE / 60;
scale = 60;
break;
@@ -201,7 +212,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
return NGX_ERROR;
}
step = st_sec;
- max = NGX_MAX_INT32_VALUE;
+ max = NGX_MAX_INT_T_VALUE;
scale = 1;
break;
@@ -210,7 +221,7 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
return NGX_ERROR;
}
step = st_last;
- max = NGX_MAX_INT32_VALUE;
+ max = NGX_MAX_INT_T_VALUE;
scale = 1;
break;
@@ -223,27 +234,40 @@ ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
max /= 1000;
}
- if ((ngx_uint_t) value > max) {
+ if (value > max) {
return NGX_ERROR;
}
- total += value * scale;
+ value *= scale;
- if ((ngx_uint_t) total > NGX_MAX_INT32_VALUE) {
+ if (total > NGX_MAX_INT_T_VALUE - value) {
return NGX_ERROR;
}
+ total += value;
+
value = 0;
- scale = is_sec ? 1 : 1000;
while (p < last && *p == ' ') {
p++;
}
}
- if (valid) {
- return total + value * scale;
+ if (!valid) {
+ return NGX_ERROR;
+ }
+
+ if (!is_sec) {
+ if (value > NGX_MAX_INT_T_VALUE / 1000) {
+ return NGX_ERROR;
+ }
+
+ value *= 1000;
+ }
+
+ if (total > NGX_MAX_INT_T_VALUE - value) {
+ return NGX_ERROR;
}
- return NGX_ERROR;
+ return total + value;
}
diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c
index 30acca5fc..77c5947de 100644
--- a/src/core/ngx_regex.c
+++ b/src/core/ngx_regex.c
@@ -80,7 +80,7 @@ ngx_regex_init(void)
static ngx_inline void
ngx_regex_malloc_init(ngx_pool_t *pool)
{
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
ngx_core_tls_t *tls;
if (ngx_threaded) {
@@ -98,7 +98,7 @@ ngx_regex_malloc_init(ngx_pool_t *pool)
static ngx_inline void
ngx_regex_malloc_done(void)
{
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
ngx_core_tls_t *tls;
if (ngx_threaded) {
@@ -253,7 +253,7 @@ static void * ngx_libc_cdecl
ngx_regex_malloc(size_t size)
{
ngx_pool_t *pool;
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
ngx_core_tls_t *tls;
if (ngx_threaded) {
diff --git a/src/core/ngx_spinlock.c b/src/core/ngx_spinlock.c
index 9c93afaf1..33477e2ee 100644
--- a/src/core/ngx_spinlock.c
+++ b/src/core/ngx_spinlock.c
@@ -42,7 +42,7 @@ ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin)
#else
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
#error ngx_spinlock() or ngx_atomic_cmp_set() are not defined !
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
index f8641b7ab..d2a8d0117 100644
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -901,26 +901,28 @@ ngx_filename_cmp(u_char *s1, u_char *s2, size_t n)
ngx_int_t
ngx_atoi(u_char *line, size_t n)
{
- ngx_int_t value;
+ ngx_int_t value, cutoff, cutlim;
if (n == 0) {
return NGX_ERROR;
}
+ cutoff = NGX_MAX_INT_T_VALUE / 10;
+ cutlim = NGX_MAX_INT_T_VALUE % 10;
+
for (value = 0; n--; line++) {
if (*line < '0' || *line > '9') {
return NGX_ERROR;
}
+ if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
value = value * 10 + (*line - '0');
}
- if (value < 0) {
- return NGX_ERROR;
-
- } else {
- return value;
- }
+ return value;
}
@@ -929,13 +931,16 @@ ngx_atoi(u_char *line, size_t n)
ngx_int_t
ngx_atofp(u_char *line, size_t n, size_t point)
{
- ngx_int_t value;
+ ngx_int_t value, cutoff, cutlim;
ngx_uint_t dot;
if (n == 0) {
return NGX_ERROR;
}
+ cutoff = NGX_MAX_INT_T_VALUE / 10;
+ cutlim = NGX_MAX_INT_T_VALUE % 10;
+
dot = 0;
for (value = 0; n--; line++) {
@@ -957,98 +962,107 @@ ngx_atofp(u_char *line, size_t n, size_t point)
return NGX_ERROR;
}
+ if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
value = value * 10 + (*line - '0');
point -= dot;
}
while (point--) {
+ if (value > cutoff) {
+ return NGX_ERROR;
+ }
+
value = value * 10;
}
- if (value < 0) {
- return NGX_ERROR;
-
- } else {
- return value;
- }
+ return value;
}
ssize_t
ngx_atosz(u_char *line, size_t n)
{
- ssize_t value;
+ ssize_t value, cutoff, cutlim;
if (n == 0) {
return NGX_ERROR;
}
+ cutoff = NGX_MAX_SIZE_T_VALUE / 10;
+ cutlim = NGX_MAX_SIZE_T_VALUE % 10;
+
for (value = 0; n--; line++) {
if (*line < '0' || *line > '9') {
return NGX_ERROR;
}
+ if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
value = value * 10 + (*line - '0');
}
- if (value < 0) {
- return NGX_ERROR;
-
- } else {
- return value;
- }
+ return value;
}
off_t
ngx_atoof(u_char *line, size_t n)
{
- off_t value;
+ off_t value, cutoff, cutlim;
if (n == 0) {
return NGX_ERROR;
}
+ cutoff = NGX_MAX_OFF_T_VALUE / 10;
+ cutlim = NGX_MAX_OFF_T_VALUE % 10;
+
for (value = 0; n--; line++) {
if (*line < '0' || *line > '9') {
return NGX_ERROR;
}
+ if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
value = value * 10 + (*line - '0');
}
- if (value < 0) {
- return NGX_ERROR;
-
- } else {
- return value;
- }
+ return value;
}
time_t
ngx_atotm(u_char *line, size_t n)
{
- time_t value;
+ time_t value, cutoff, cutlim;
if (n == 0) {
return NGX_ERROR;
}
+ cutoff = NGX_MAX_TIME_T_VALUE / 10;
+ cutlim = NGX_MAX_TIME_T_VALUE % 10;
+
for (value = 0; n--; line++) {
if (*line < '0' || *line > '9') {
return NGX_ERROR;
}
+ if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
value = value * 10 + (*line - '0');
}
- if (value < 0) {
- return NGX_ERROR;
-
- } else {
- return value;
- }
+ return value;
}
@@ -1056,13 +1070,19 @@ ngx_int_t
ngx_hextoi(u_char *line, size_t n)
{
u_char c, ch;
- ngx_int_t value;
+ ngx_int_t value, cutoff;
if (n == 0) {
return NGX_ERROR;
}
+ cutoff = NGX_MAX_INT_T_VALUE / 16;
+
for (value = 0; n--; line++) {
+ if (value > cutoff) {
+ return NGX_ERROR;
+ }
+
ch = *line;
if (ch >= '0' && ch <= '9') {
@@ -1080,12 +1100,7 @@ ngx_hextoi(u_char *line, size_t n)
return NGX_ERROR;
}
- if (value < 0) {
- return NGX_ERROR;
-
- } else {
- return value;
- }
+ return value;
}
diff --git a/src/core/ngx_thread_pool.c b/src/core/ngx_thread_pool.c
new file mode 100644
index 000000000..03530851a
--- /dev/null
+++ b/src/core/ngx_thread_pool.c
@@ -0,0 +1,630 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ * Copyright (C) Valentin V. Bartenev
+ * Copyright (C) Ruslan Ermilov
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_thread_pool.h>
+
+
+typedef struct {
+ ngx_array_t pools;
+} ngx_thread_pool_conf_t;
+
+
+typedef struct {
+ ngx_thread_task_t *first;
+ ngx_thread_task_t **last;
+} ngx_thread_pool_queue_t;
+
+#define ngx_thread_pool_queue_init(q) \
+ (q)->first = NULL; \
+ (q)->last = &(q)->first
+
+
+struct ngx_thread_pool_s {
+ ngx_thread_mutex_t mtx;
+ ngx_thread_pool_queue_t queue;
+ ngx_int_t waiting;
+ ngx_thread_cond_t cond;
+
+ ngx_log_t *log;
+
+ ngx_str_t name;
+ ngx_uint_t threads;
+ ngx_int_t max_queue;
+
+ u_char *file;
+ ngx_uint_t line;
+};
+
+
+static ngx_int_t ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log,
+ ngx_pool_t *pool);
+static void ngx_thread_pool_destroy(ngx_thread_pool_t *tp);
+static void ngx_thread_pool_exit_handler(void *data, ngx_log_t *log);
+
+static void *ngx_thread_pool_cycle(void *data);
+static void ngx_thread_pool_handler(ngx_event_t *ev);
+
+static char *ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+
+static void *ngx_thread_pool_create_conf(ngx_cycle_t *cycle);
+static char *ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf);
+
+static ngx_int_t ngx_thread_pool_init_worker(ngx_cycle_t *cycle);
+static void ngx_thread_pool_exit_worker(ngx_cycle_t *cycle);
+
+
+static ngx_command_t ngx_thread_pool_commands[] = {
+
+ { ngx_string("thread_pool"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE23,
+ ngx_thread_pool,
+ 0,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_core_module_t ngx_thread_pool_module_ctx = {
+ ngx_string("thread_pool"),
+ ngx_thread_pool_create_conf,
+ ngx_thread_pool_init_conf
+};
+
+
+ngx_module_t ngx_thread_pool_module = {
+ NGX_MODULE_V1,
+ &ngx_thread_pool_module_ctx, /* module context */
+ ngx_thread_pool_commands, /* module directives */
+ NGX_CORE_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ ngx_thread_pool_init_worker, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ ngx_thread_pool_exit_worker, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_str_t ngx_thread_pool_default = ngx_string("default");
+
+static ngx_uint_t ngx_thread_pool_task_id;
+static ngx_atomic_t ngx_thread_pool_done_lock;
+static ngx_thread_pool_queue_t ngx_thread_pool_done;
+
+
+static ngx_int_t
+ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log, ngx_pool_t *pool)
+{
+ int err;
+ pthread_t tid;
+ ngx_uint_t n;
+ pthread_attr_t attr;
+
+ if (ngx_notify == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "the configured event method cannot be used with thread pools");
+ return NGX_ERROR;
+ }
+
+ ngx_thread_pool_queue_init(&tp->queue);
+
+ if (ngx_thread_mutex_create(&tp->mtx, log) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_thread_cond_create(&tp->cond, log) != NGX_OK) {
+ (void) ngx_thread_mutex_destroy(&tp->mtx, log);
+ return NGX_ERROR;
+ }
+
+ tp->log = log;
+
+ err = pthread_attr_init(&attr);
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "pthread_attr_init() failed");
+ return NGX_ERROR;
+ }
+
+#if 0
+ err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "pthread_attr_setstacksize() failed");
+ return NGX_ERROR;
+ }
+#endif
+
+ for (n = 0; n < tp->threads; n++) {
+ err = pthread_create(&tid, &attr, ngx_thread_pool_cycle, tp);
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "pthread_create() failed");
+ return NGX_ERROR;
+ }
+ }
+
+ (void) pthread_attr_destroy(&attr);
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_thread_pool_destroy(ngx_thread_pool_t *tp)
+{
+ ngx_uint_t n;
+ ngx_thread_task_t task;
+ volatile ngx_uint_t lock;
+
+ ngx_memzero(&task, sizeof(ngx_thread_task_t));
+
+ task.handler = ngx_thread_pool_exit_handler;
+ task.ctx = (void *) &lock;
+
+ for (n = 0; n < tp->threads; n++) {
+ lock = 1;
+
+ if (ngx_thread_task_post(tp, &task) != NGX_OK) {
+ return;
+ }
+
+ while (lock) {
+ ngx_sched_yield();
+ }
+
+ task.event.active = 0;
+ }
+
+ (void) ngx_thread_cond_destroy(&tp->cond, tp->log);
+
+ (void) ngx_thread_mutex_destroy(&tp->mtx, tp->log);
+}
+
+
+static void
+ngx_thread_pool_exit_handler(void *data, ngx_log_t *log)
+{
+ ngx_uint_t *lock = data;
+
+ *lock = 0;
+
+ pthread_exit(0);
+}
+
+
+ngx_thread_task_t *
+ngx_thread_task_alloc(ngx_pool_t *pool, size_t size)
+{
+ ngx_thread_task_t *task;
+
+ task = ngx_pcalloc(pool, sizeof(ngx_thread_task_t) + size);
+ if (task == NULL) {
+ return NULL;
+ }
+
+ task->ctx = task + 1;
+
+ return task;
+}
+
+
+ngx_int_t
+ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task)
+{
+ if (task->event.active) {
+ ngx_log_error(NGX_LOG_ALERT, tp->log, 0,
+ "task #%ui already active", task->id);
+ return NGX_ERROR;
+ }
+
+ if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (tp->waiting >= tp->max_queue) {
+ (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
+
+ ngx_log_error(NGX_LOG_ERR, tp->log, 0,
+ "thread pool \"%V\" queue overflow: %i tasks waiting",
+ &tp->name, tp->waiting);
+ return NGX_ERROR;
+ }
+
+ task->event.active = 1;
+
+ task->id = ngx_thread_pool_task_id++;
+ task->next = NULL;
+
+ if (ngx_thread_cond_signal(&tp->cond, tp->log) != NGX_OK) {
+ (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
+ return NGX_ERROR;
+ }
+
+ *tp->queue.last = task;
+ tp->queue.last = &task->next;
+
+ tp->waiting++;
+
+ (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
+ "task #%ui added to thread pool \"%V\"",
+ task->id, &tp->name);
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_thread_pool_cycle(void *data)
+{
+ ngx_thread_pool_t *tp = data;
+
+ int err;
+ sigset_t set;
+ ngx_thread_task_t *task;
+
+#if 0
+ ngx_time_update();
+#endif
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, tp->log, 0,
+ "thread in pool \"%V\" started", &tp->name);
+
+ sigfillset(&set);
+
+ sigdelset(&set, SIGILL);
+ sigdelset(&set, SIGFPE);
+ sigdelset(&set, SIGSEGV);
+ sigdelset(&set, SIGBUS);
+
+ err = pthread_sigmask(SIG_BLOCK, &set, NULL);
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, tp->log, err, "pthread_sigmask() failed");
+ return NULL;
+ }
+
+ for ( ;; ) {
+ if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {
+ return NULL;
+ }
+
+ /* the number may become negative */
+ tp->waiting--;
+
+ while (tp->queue.first == NULL) {
+ if (ngx_thread_cond_wait(&tp->cond, &tp->mtx, tp->log)
+ != NGX_OK)
+ {
+ (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
+ return NULL;
+ }
+ }
+
+ task = tp->queue.first;
+ tp->queue.first = task->next;
+
+ if (tp->queue.first == NULL) {
+ tp->queue.last = &tp->queue.first;
+ }
+
+ if (ngx_thread_mutex_unlock(&tp->mtx, tp->log) != NGX_OK) {
+ return NULL;
+ }
+
+#if 0
+ ngx_time_update();
+#endif
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
+ "run task #%ui in thread pool \"%V\"",
+ task->id, &tp->name);
+
+ task->handler(task->ctx, tp->log);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
+ "complete task #%ui in thread pool \"%V\"",
+ task->id, &tp->name);
+
+ task->next = NULL;
+
+ ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);
+
+ *ngx_thread_pool_done.last = task;
+ ngx_thread_pool_done.last = &task->next;
+
+ ngx_unlock(&ngx_thread_pool_done_lock);
+
+ (void) ngx_notify(ngx_thread_pool_handler);
+ }
+}
+
+
+static void
+ngx_thread_pool_handler(ngx_event_t *ev)
+{
+ ngx_event_t *event;
+ ngx_thread_task_t *task;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "thread pool handler");
+
+ ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);
+
+ task = ngx_thread_pool_done.first;
+ ngx_thread_pool_done.first = NULL;
+ ngx_thread_pool_done.last = &ngx_thread_pool_done.first;
+
+ ngx_unlock(&ngx_thread_pool_done_lock);
+
+ while (task) {
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
+ "run completion handler for task #%ui", task->id);
+
+ event = &task->event;
+ task = task->next;
+
+ event->complete = 1;
+ event->active = 0;
+
+ event->handler(event);
+ }
+}
+
+
+static void *
+ngx_thread_pool_create_conf(ngx_cycle_t *cycle)
+{
+ ngx_thread_pool_conf_t *tcf;
+
+ tcf = ngx_pcalloc(cycle->pool, sizeof(ngx_thread_pool_conf_t));
+ if (tcf == NULL) {
+ return NULL;
+ }
+
+ if (ngx_array_init(&tcf->pools, cycle->pool, 4,
+ sizeof(ngx_thread_pool_t *))
+ != NGX_OK)
+ {
+ return NULL;
+ }
+
+ return tcf;
+}
+
+
+static char *
+ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_thread_pool_conf_t *tcf = conf;
+
+ ngx_uint_t i;
+ ngx_thread_pool_t **tpp;
+
+ tpp = tcf->pools.elts;
+
+ for (i = 0; i < tcf->pools.nelts; i++) {
+
+ if (tpp[i]->threads) {
+ continue;
+ }
+
+ if (tpp[i]->name.len == ngx_thread_pool_default.len
+ && ngx_strncmp(tpp[i]->name.data, ngx_thread_pool_default.data,
+ ngx_thread_pool_default.len)
+ == 0)
+ {
+ tpp[i]->threads = 32;
+ tpp[i]->max_queue = 65536;
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+ "unknown thread pool \"%V\" in %s:%ui",
+ &tpp[i]->name, tpp[i]->file, tpp[i]->line);
+
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_str_t *value;
+ ngx_uint_t i;
+ ngx_thread_pool_t *tp;
+
+ value = cf->args->elts;
+
+ tp = ngx_thread_pool_add(cf, &value[1]);
+
+ if (tp == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (tp->threads) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate thread pool \"%V\"", &tp->name);
+ return NGX_CONF_ERROR;
+ }
+
+ tp->max_queue = 65536;
+
+ for (i = 2; i < cf->args->nelts; i++) {
+
+ if (ngx_strncmp(value[i].data, "threads=", 8) == 0) {
+
+ tp->threads = ngx_atoi(value[i].data + 8, value[i].len - 8);
+
+ if (tp->threads == (ngx_uint_t) NGX_ERROR || tp->threads == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid threads value \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ if (ngx_strncmp(value[i].data, "max_queue=", 10) == 0) {
+
+ tp->max_queue = ngx_atoi(value[i].data + 10, value[i].len - 10);
+
+ if (tp->max_queue == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid max_queue value \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+ }
+
+ if (tp->threads == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%V\" must have \"threads\" parameter",
+ &cmd->name);
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+ngx_thread_pool_t *
+ngx_thread_pool_add(ngx_conf_t *cf, ngx_str_t *name)
+{
+ ngx_thread_pool_t *tp, **tpp;
+ ngx_thread_pool_conf_t *tcf;
+
+ if (name == NULL) {
+ name = &ngx_thread_pool_default;
+ }
+
+ tp = ngx_thread_pool_get(cf->cycle, name);
+
+ if (tp) {
+ return tp;
+ }
+
+ tp = ngx_pcalloc(cf->pool, sizeof(ngx_thread_pool_t));
+ if (tp == NULL) {
+ return NULL;
+ }
+
+ tp->name = *name;
+ tp->file = cf->conf_file->file.name.data;
+ tp->line = cf->conf_file->line;
+
+ tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cf->cycle->conf_ctx,
+ ngx_thread_pool_module);
+
+ tpp = ngx_array_push(&tcf->pools);
+ if (tpp == NULL) {
+ return NULL;
+ }
+
+ *tpp = tp;
+
+ return tp;
+}
+
+
+ngx_thread_pool_t *
+ngx_thread_pool_get(ngx_cycle_t *cycle, ngx_str_t *name)
+{
+ ngx_uint_t i;
+ ngx_thread_pool_t **tpp;
+ ngx_thread_pool_conf_t *tcf;
+
+ tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
+ ngx_thread_pool_module);
+
+ tpp = tcf->pools.elts;
+
+ for (i = 0; i < tcf->pools.nelts; i++) {
+
+ if (tpp[i]->name.len == name->len
+ && ngx_strncmp(tpp[i]->name.data, name->data, name->len) == 0)
+ {
+ return tpp[i];
+ }
+ }
+
+ return NULL;
+}
+
+
+static ngx_int_t
+ngx_thread_pool_init_worker(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+ ngx_thread_pool_t **tpp;
+ ngx_thread_pool_conf_t *tcf;
+
+ if (ngx_process != NGX_PROCESS_WORKER
+ && ngx_process != NGX_PROCESS_SINGLE)
+ {
+ return NGX_OK;
+ }
+
+ tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
+ ngx_thread_pool_module);
+
+ if (tcf == NULL) {
+ return NGX_OK;
+ }
+
+ ngx_thread_pool_queue_init(&ngx_thread_pool_done);
+
+ tpp = tcf->pools.elts;
+
+ for (i = 0; i < tcf->pools.nelts; i++) {
+ if (ngx_thread_pool_init(tpp[i], cycle->log, cycle->pool) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_thread_pool_exit_worker(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+ ngx_thread_pool_t **tpp;
+ ngx_thread_pool_conf_t *tcf;
+
+ if (ngx_process != NGX_PROCESS_WORKER
+ && ngx_process != NGX_PROCESS_SINGLE)
+ {
+ return;
+ }
+
+ tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
+ ngx_thread_pool_module);
+
+ if (tcf == NULL) {
+ return;
+ }
+
+ tpp = tcf->pools.elts;
+
+ for (i = 0; i < tcf->pools.nelts; i++) {
+ ngx_thread_pool_destroy(tpp[i]);
+ }
+}
diff --git a/src/core/ngx_thread_pool.h b/src/core/ngx_thread_pool.h
new file mode 100644
index 000000000..5e5adf624
--- /dev/null
+++ b/src/core/ngx_thread_pool.h
@@ -0,0 +1,36 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ * Copyright (C) Valentin V. Bartenev
+ */
+
+
+#ifndef _NGX_THREAD_POOL_H_INCLUDED_
+#define _NGX_THREAD_POOL_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+struct ngx_thread_task_s {
+ ngx_thread_task_t *next;
+ ngx_uint_t id;
+ void *ctx;
+ void (*handler)(void *data, ngx_log_t *log);
+ ngx_event_t event;
+};
+
+
+typedef struct ngx_thread_pool_s ngx_thread_pool_t;
+
+
+ngx_thread_pool_t *ngx_thread_pool_add(ngx_conf_t *cf, ngx_str_t *name);
+ngx_thread_pool_t *ngx_thread_pool_get(ngx_cycle_t *cycle, ngx_str_t *name);
+
+ngx_thread_task_t *ngx_thread_task_alloc(ngx_pool_t *pool, size_t size);
+ngx_int_t ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task);
+
+
+#endif /* _NGX_THREAD_POOL_H_INCLUDED_ */
diff --git a/src/event/modules/ngx_aio_module.c b/src/event/modules/ngx_aio_module.c
index c881319d1..fd03fecb4 100644
--- a/src/event/modules/ngx_aio_module.c
+++ b/src/event/modules/ngx_aio_module.c
@@ -48,7 +48,7 @@ ngx_event_module_t ngx_aio_module_ctx = {
NULL, /* disable an event */
NULL, /* add an connection */
ngx_aio_del_connection, /* delete an connection */
- NULL, /* process the changes */
+ NULL, /* trigger a notify */
ngx_aio_process_events, /* process the events */
ngx_aio_init, /* init the events */
ngx_aio_done /* done the events */
diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c
index 5658e8620..fa8aebdf4 100644
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -88,7 +88,7 @@ ngx_event_module_t ngx_devpoll_module_ctx = {
ngx_devpoll_del_event, /* disable an event */
NULL, /* add an connection */
NULL, /* delete an connection */
- NULL, /* process the changes */
+ NULL, /* trigger a notify */
ngx_devpoll_process_events, /* process the events */
ngx_devpoll_init, /* init the events */
ngx_devpoll_done, /* done the events */
diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c
index 2674d382b..5f7f67859 100644
--- a/src/event/modules/ngx_epoll_module.c
+++ b/src/event/modules/ngx_epoll_module.c
@@ -70,12 +70,15 @@ int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout)
return -1;
}
+#if (NGX_HAVE_EVENTFD)
+#define SYS_eventfd 323
+#endif
+
#if (NGX_HAVE_FILE_AIO)
#define SYS_io_setup 245
#define SYS_io_destroy 246
#define SYS_io_getevents 247
-#define SYS_eventfd 323
typedef u_int aio_context_t;
@@ -88,7 +91,7 @@ struct io_event {
#endif
-#endif
+#endif /* NGX_TEST_BUILD_EPOLL */
typedef struct {
@@ -98,6 +101,10 @@ typedef struct {
static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+#if (NGX_HAVE_EVENTFD)
+static ngx_int_t ngx_epoll_notify_init(ngx_log_t *log);
+static void ngx_epoll_notify_handler(ngx_event_t *ev);
+#endif
static void ngx_epoll_done(ngx_cycle_t *cycle);
static ngx_int_t ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event,
ngx_uint_t flags);
@@ -106,6 +113,9 @@ static ngx_int_t ngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event,
static ngx_int_t ngx_epoll_add_connection(ngx_connection_t *c);
static ngx_int_t ngx_epoll_del_connection(ngx_connection_t *c,
ngx_uint_t flags);
+#if (NGX_HAVE_EVENTFD)
+static ngx_int_t ngx_epoll_notify(ngx_event_handler_pt handler);
+#endif
static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags);
@@ -120,6 +130,12 @@ static int ep = -1;
static struct epoll_event *event_list;
static ngx_uint_t nevents;
+#if (NGX_HAVE_EVENTFD)
+static int notify_fd = -1;
+static ngx_event_t notify_event;
+static ngx_connection_t notify_conn;
+#endif
+
#if (NGX_HAVE_FILE_AIO)
int ngx_eventfd = -1;
@@ -164,7 +180,11 @@ ngx_event_module_t ngx_epoll_module_ctx = {
ngx_epoll_del_event, /* disable an event */
ngx_epoll_add_connection, /* add an connection */
ngx_epoll_del_connection, /* delete an connection */
- NULL, /* process the changes */
+#if (NGX_HAVE_EVENTFD)
+ ngx_epoll_notify, /* trigger a notify */
+#else
+ NULL, /* trigger a notify */
+#endif
ngx_epoll_process_events, /* process the events */
ngx_epoll_init, /* init the events */
ngx_epoll_done, /* done the events */
@@ -307,6 +327,12 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
return NGX_ERROR;
}
+#if (NGX_HAVE_EVENTFD)
+ if (ngx_epoll_notify_init(cycle->log) != NGX_OK) {
+ return NGX_ERROR;
+ }
+#endif
+
#if (NGX_HAVE_FILE_AIO)
ngx_epoll_aio_init(cycle, epcf);
@@ -344,6 +370,85 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
}
+#if (NGX_HAVE_EVENTFD)
+
+static ngx_int_t
+ngx_epoll_notify_init(ngx_log_t *log)
+{
+ struct epoll_event ee;
+
+#if (NGX_HAVE_SYS_EVENTFD_H)
+ notify_fd = eventfd(0, 0);
+#else
+ notify_fd = syscall(SYS_eventfd, 0);
+#endif
+
+ if (notify_fd == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "eventfd() failed");
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+ "notify eventfd: %d", notify_fd);
+
+ notify_event.handler = ngx_epoll_notify_handler;
+ notify_event.log = log;
+ notify_event.active = 1;
+
+ notify_conn.fd = notify_fd;
+ notify_conn.read = &notify_event;
+ notify_conn.log = log;
+
+ ee.events = EPOLLIN|EPOLLET;
+ ee.data.ptr = &notify_conn;
+
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, notify_fd, &ee) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "epoll_ctl(EPOLL_CTL_ADD, eventfd) failed");
+
+ if (close(notify_fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "eventfd close() failed");
+ }
+
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_epoll_notify_handler(ngx_event_t *ev)
+{
+ ssize_t n;
+ uint64_t count;
+ ngx_err_t err;
+ ngx_event_handler_pt handler;
+
+ if (++ev->index == NGX_MAX_UINT32_VALUE) {
+ ev->index = 0;
+
+ n = read(notify_fd, &count, sizeof(uint64_t));
+
+ err = ngx_errno;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "read() eventfd %d: %z count:%uL", notify_fd, n, count);
+
+ if ((size_t) n != sizeof(uint64_t)) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, err,
+ "read() eventfd %d failed", notify_fd);
+ }
+ }
+
+ handler = ev->data;
+ handler(ev);
+}
+
+#endif
+
+
static void
ngx_epoll_done(ngx_cycle_t *cycle)
{
@@ -354,6 +459,17 @@ ngx_epoll_done(ngx_cycle_t *cycle)
ep = -1;
+#if (NGX_HAVE_EVENTFD)
+
+ if (close(notify_fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "eventfd close() failed");
+ }
+
+ notify_fd = -1;
+
+#endif
+
#if (NGX_HAVE_FILE_AIO)
if (ngx_eventfd != -1) {
@@ -560,6 +676,27 @@ ngx_epoll_del_connection(ngx_connection_t *c, ngx_uint_t flags)
}
+#if (NGX_HAVE_EVENTFD)
+
+static ngx_int_t
+ngx_epoll_notify(ngx_event_handler_pt handler)
+{
+ static uint64_t inc = 1;
+
+ if ((size_t) write(notify_fd, &inc, sizeof(uint64_t)) != sizeof(uint64_t)) {
+ ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
+ "write() to eventfd %d failed", notify_fd);
+ return NGX_ERROR;
+ }
+
+ notify_event.data = handler;
+
+ return NGX_OK;
+}
+
+#endif
+
+
static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c
index a9d8a6246..bacbb0507 100644
--- a/src/event/modules/ngx_eventport_module.c
+++ b/src/event/modules/ngx_eventport_module.c
@@ -93,6 +93,13 @@ int port_getn(int port, port_event_t list[], uint_t max, uint_t *nget,
return -1;
}
+int port_send(int port, int events, void *user);
+
+int port_send(int port, int events, void *user)
+{
+ return -1;
+}
+
int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid);
@@ -133,6 +140,7 @@ static ngx_int_t ngx_eventport_add_event(ngx_event_t *ev, ngx_int_t event,
ngx_uint_t flags);
static ngx_int_t ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event,
ngx_uint_t flags);
+static ngx_int_t ngx_eventport_notify(ngx_event_handler_pt handler);
static ngx_int_t ngx_eventport_process_events(ngx_cycle_t *cycle,
ngx_msec_t timer, ngx_uint_t flags);
@@ -143,6 +151,7 @@ static int ep = -1;
static port_event_t *event_list;
static ngx_uint_t nevents;
static timer_t event_timer = (timer_t) -1;
+static ngx_event_t notify_event;
static ngx_str_t eventport_name = ngx_string("eventport");
@@ -172,7 +181,7 @@ ngx_event_module_t ngx_eventport_module_ctx = {
ngx_eventport_del_event, /* disable an event */
NULL, /* add an connection */
NULL, /* delete an connection */
- NULL, /* process the changes */
+ ngx_eventport_notify, /* trigger a notify */
ngx_eventport_process_events, /* process the events */
ngx_eventport_init, /* init the events */
ngx_eventport_done, /* done the events */
@@ -214,6 +223,9 @@ ngx_eventport_init(ngx_cycle_t *cycle, ngx_msec_t timer)
"port_create() failed");
return NGX_ERROR;
}
+
+ notify_event.active = 1;
+ notify_event.log = cycle->log;
}
if (nevents < epcf->events) {
@@ -405,6 +417,21 @@ ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
}
+static ngx_int_t
+ngx_eventport_notify(ngx_event_handler_pt handler)
+{
+ notify_event.handler = handler;
+
+ if (port_send(ep, 0, &notify_event) != 0) {
+ ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
+ "port_send() failed");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
ngx_int_t
ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags)
@@ -579,9 +606,15 @@ ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
continue;
+ case PORT_SOURCE_USER:
+
+ ev->handler(ev);
+
+ continue;
+
default:
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
- "unexpected even_port object %d",
+ "unexpected eventport object %d",
event_list[i].portev_object);
continue;
}
diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c
index 9e7a1bdb6..5573cb211 100644
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -17,6 +17,9 @@ typedef struct {
static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+#ifdef EVFILT_USER
+static ngx_int_t ngx_kqueue_notify_init(ngx_log_t *log);
+#endif
static void ngx_kqueue_done(ngx_cycle_t *cycle);
static ngx_int_t ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event,
ngx_uint_t flags);
@@ -24,7 +27,9 @@ static ngx_int_t ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event,
ngx_uint_t flags);
static ngx_int_t ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter,
ngx_uint_t flags);
-static ngx_int_t ngx_kqueue_process_changes(ngx_cycle_t *cycle, ngx_uint_t try);
+#ifdef EVFILT_USER
+static ngx_int_t ngx_kqueue_notify(ngx_event_handler_pt handler);
+#endif
static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags);
static ngx_inline void ngx_kqueue_dump_event(ngx_log_t *log,
@@ -36,25 +41,16 @@ static char *ngx_kqueue_init_conf(ngx_cycle_t *cycle, void *conf);
int ngx_kqueue = -1;
-/*
- * The "change_list" should be declared as ngx_thread_volatile.
- * However, the use of the change_list is localized in kqueue functions and
- * is protected by the mutex so even the "icc -ipo" should not build the code
- * with the race condition. Thus we avoid the declaration to make a more
- * readable code.
- */
-
-static struct kevent *change_list, *change_list0, *change_list1;
+static struct kevent *change_list;
static struct kevent *event_list;
static ngx_uint_t max_changes, nchanges, nevents;
-#if (NGX_THREADS)
-static ngx_mutex_t *list_mutex;
-static ngx_mutex_t *kevent_mutex;
+#ifdef EVFILT_USER
+static ngx_event_t notify_event;
+static struct kevent notify_kev;
#endif
-
static ngx_str_t kqueue_name = ngx_string("kqueue");
static ngx_command_t ngx_kqueue_commands[] = {
@@ -89,7 +85,11 @@ ngx_event_module_t ngx_kqueue_module_ctx = {
ngx_kqueue_del_event, /* disable an event */
NULL, /* add an connection */
NULL, /* delete an connection */
- ngx_kqueue_process_changes, /* process the changes */
+#ifdef EVFILT_USER
+ ngx_kqueue_notify, /* trigger a notify */
+#else
+ NULL, /* trigger a notify */
+#endif
ngx_kqueue_process_events, /* process the events */
ngx_kqueue_init, /* init the events */
ngx_kqueue_done /* done the events */
@@ -133,18 +133,10 @@ ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
return NGX_ERROR;
}
-#if (NGX_THREADS)
-
- list_mutex = ngx_mutex_init(cycle->log, 0);
- if (list_mutex == NULL) {
- return NGX_ERROR;
- }
-
- kevent_mutex = ngx_mutex_init(cycle->log, 0);
- if (kevent_mutex == NULL) {
+#ifdef EVFILT_USER
+ if (ngx_kqueue_notify_init(cycle->log) != NGX_OK) {
return NGX_ERROR;
}
-
#endif
}
@@ -163,27 +155,15 @@ ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
nchanges = 0;
}
- if (change_list0) {
- ngx_free(change_list0);
- }
-
- change_list0 = ngx_alloc(kcf->changes * sizeof(struct kevent),
- cycle->log);
- if (change_list0 == NULL) {
- return NGX_ERROR;
- }
-
- if (change_list1) {
- ngx_free(change_list1);
+ if (change_list) {
+ ngx_free(change_list);
}
- change_list1 = ngx_alloc(kcf->changes * sizeof(struct kevent),
- cycle->log);
- if (change_list1 == NULL) {
+ change_list = ngx_alloc(kcf->changes * sizeof(struct kevent),
+ cycle->log);
+ if (change_list == NULL) {
return NGX_ERROR;
}
-
- change_list = change_list0;
}
max_changes = kcf->changes;
@@ -247,6 +227,37 @@ ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
}
+#ifdef EVFILT_USER
+
+static ngx_int_t
+ngx_kqueue_notify_init(ngx_log_t *log)
+{
+ notify_kev.ident = 0;
+ notify_kev.filter = EVFILT_USER;
+ notify_kev.data = 0;
+ notify_kev.flags = EV_ADD|EV_CLEAR;
+ notify_kev.fflags = 0;
+ notify_kev.udata = 0;
+
+ if (kevent(ngx_kqueue, &notify_kev, 1, NULL, 0, NULL) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ "kevent(EVFILT_USER, EV_ADD) failed");
+ return NGX_ERROR;
+ }
+
+ notify_event.active = 1;
+ notify_event.log = log;
+
+ notify_kev.flags = 0;
+ notify_kev.fflags = NOTE_TRIGGER;
+ notify_kev.udata = NGX_KQUEUE_UDATA_T ((uintptr_t) &notify_event);
+
+ return NGX_OK;
+}
+
+#endif
+
+
static void
ngx_kqueue_done(ngx_cycle_t *cycle)
{
@@ -257,17 +268,9 @@ ngx_kqueue_done(ngx_cycle_t *cycle)
ngx_kqueue = -1;
-#if (NGX_THREADS)
- ngx_mutex_destroy(kevent_mutex);
- ngx_mutex_destroy(list_mutex);
-#endif
-
- ngx_free(change_list1);
- ngx_free(change_list0);
+ ngx_free(change_list);
ngx_free(event_list);
- change_list1 = NULL;
- change_list0 = NULL;
change_list = NULL;
event_list = NULL;
max_changes = 0;
@@ -289,8 +292,6 @@ ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
ev->disabled = 0;
ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
- ngx_mutex_lock(list_mutex);
-
#if 0
if (ev->index < nchanges
@@ -315,8 +316,6 @@ ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
e->index = ev->index;
}
- ngx_mutex_unlock(list_mutex);
-
return NGX_OK;
}
@@ -325,8 +324,6 @@ ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
"previous event on #%d were not passed in kernel", c->fd);
- ngx_mutex_unlock(list_mutex);
-
return NGX_ERROR;
}
@@ -334,8 +331,6 @@ ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
rc = ngx_kqueue_set_event(ev, event, EV_ADD|EV_ENABLE|flags);
- ngx_mutex_unlock(list_mutex);
-
return rc;
}
@@ -349,8 +344,6 @@ ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
ev->active = 0;
ev->disabled = 0;
- ngx_mutex_lock(list_mutex);
-
if (ev->index < nchanges
&& ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
== (uintptr_t) ev)
@@ -370,8 +363,6 @@ ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
e->index = ev->index;
}
- ngx_mutex_unlock(list_mutex);
-
return NGX_OK;
}
@@ -382,7 +373,6 @@ ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
*/
if (flags & NGX_CLOSE_EVENT) {
- ngx_mutex_unlock(list_mutex);
return NGX_OK;
}
@@ -395,8 +385,6 @@ ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
rc = ngx_kqueue_set_event(ev, event, flags);
- ngx_mutex_unlock(list_mutex);
-
return rc;
}
@@ -487,6 +475,25 @@ ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)
}
+#ifdef EVFILT_USER
+
+static ngx_int_t
+ngx_kqueue_notify(ngx_event_handler_pt handler)
+{
+ notify_event.handler = handler;
+
+ if (kevent(ngx_kqueue, &notify_kev, 1, NULL, 0, NULL) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno,
+ "kevent(EVFILT_USER, NOTE_TRIGGER) failed");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+#endif
+
+
static ngx_int_t
ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags)
@@ -499,17 +506,8 @@ ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_queue_t *queue;
struct timespec ts, *tp;
- if (ngx_threaded) {
- if (ngx_kqueue_process_changes(cycle, 0) == NGX_ERROR) {
- return NGX_ERROR;
- }
-
- n = 0;
-
- } else {
- n = (int) nchanges;
- nchanges = 0;
- }
+ n = (int) nchanges;
+ nchanges = 0;
if (timer == NGX_TIMER_INFINITE) {
tp = NULL;
@@ -647,6 +645,11 @@ ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
break;
+#ifdef EVFILT_USER
+ case EVFILT_USER:
+ break;
+#endif
+
default:
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
"unexpected kevent() filter %d",
@@ -670,59 +673,6 @@ ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
}
-static ngx_int_t
-ngx_kqueue_process_changes(ngx_cycle_t *cycle, ngx_uint_t try)
-{
- int n;
- ngx_int_t rc;
- ngx_err_t err;
- struct timespec ts;
- struct kevent *changes;
-
- ngx_mutex_lock(kevent_mutex);
-
- ngx_mutex_lock(list_mutex);
-
- if (nchanges == 0) {
- ngx_mutex_unlock(list_mutex);
- ngx_mutex_unlock(kevent_mutex);
- return NGX_OK;
- }
-
- changes = change_list;
- if (change_list == change_list0) {
- change_list = change_list1;
- } else {
- change_list = change_list0;
- }
-
- n = (int) nchanges;
- nchanges = 0;
-
- ngx_mutex_unlock(list_mutex);
-
- ts.tv_sec = 0;
- ts.tv_nsec = 0;
-
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
- "kevent changes: %d", n);
-
- if (kevent(ngx_kqueue, changes, n, NULL, 0, &ts) == -1) {
- err = ngx_errno;
- ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
- cycle->log, err, "kevent() failed");
- rc = NGX_ERROR;
-
- } else {
- rc = NGX_OK;
- }
-
- ngx_mutex_unlock(kevent_mutex);
-
- return rc;
-}
-
-
static ngx_inline void
ngx_kqueue_dump_event(ngx_log_t *log, struct kevent *kev)
{
diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c
index bad1a7d2a..e48a8227a 100644
--- a/src/event/modules/ngx_poll_module.c
+++ b/src/event/modules/ngx_poll_module.c
@@ -39,7 +39,7 @@ ngx_event_module_t ngx_poll_module_ctx = {
ngx_poll_del_event, /* disable an event */
NULL, /* add an connection */
NULL, /* delete an connection */
- NULL, /* process the changes */
+ NULL, /* trigger a notify */
ngx_poll_process_events, /* process the events */
ngx_poll_init, /* init the events */
ngx_poll_done /* done the events */
@@ -413,7 +413,7 @@ ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf)
return NGX_CONF_OK;
}
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
"poll() is not supported in the threaded mode");
diff --git a/src/event/modules/ngx_rtsig_module.c b/src/event/modules/ngx_rtsig_module.c
index 9e31afa1c..b120fecde 100644
--- a/src/event/modules/ngx_rtsig_module.c
+++ b/src/event/modules/ngx_rtsig_module.c
@@ -130,7 +130,7 @@ ngx_event_module_t ngx_rtsig_module_ctx = {
NULL, /* disable an event */
ngx_rtsig_add_connection, /* add an connection */
ngx_rtsig_del_connection, /* delete an connection */
- NULL, /* process the changes */
+ NULL, /* trigger a notify */
ngx_rtsig_process_events, /* process the events */
ngx_rtsig_init, /* init the events */
ngx_rtsig_done, /* done the events */
diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c
index fa2d55ae2..46004e5fd 100644
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -47,7 +47,7 @@ ngx_event_module_t ngx_select_module_ctx = {
ngx_select_del_event, /* disable an event */
NULL, /* add an connection */
NULL, /* delete an connection */
- NULL, /* process the changes */
+ NULL, /* trigger a notify */
ngx_select_process_events, /* process the events */
ngx_select_init, /* init the events */
ngx_select_done /* done the events */
@@ -419,7 +419,7 @@ ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
return NGX_CONF_ERROR;
}
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
"select() is not supported in the threaded mode");
diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c
index be87ded24..c671f836b 100644
--- a/src/event/modules/ngx_win32_select_module.c
+++ b/src/event/modules/ngx_win32_select_module.c
@@ -48,7 +48,7 @@ ngx_event_module_t ngx_select_module_ctx = {
ngx_select_del_event, /* disable an event */
NULL, /* add an connection */
NULL, /* delete an connection */
- NULL, /* process the changes */
+ NULL, /* trigger a notify */
ngx_select_process_events, /* process the events */
ngx_select_init, /* init the events */
ngx_select_done /* done the events */
diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c
index 26c3b9716..31514c44b 100644
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -212,7 +212,7 @@ ngx_process_events_and_timers(ngx_cycle_t *cycle)
timer = ngx_event_find_timer();
flags = NGX_UPDATE_TIME;
-#if (NGX_THREADS)
+#if (NGX_OLD_THREADS)
if (timer == NGX_TIMER_INFINITE || timer > 500) {
timer = 500;
@@ -721,10 +721,6 @@ ngx_event_process_init(ngx_cycle_t *cycle)
c[i].fd = (ngx_socket_t) -1;
next = &c[i];
-
-#if (NGX_THREADS)
- c[i].lock = 0;
-#endif
} while (i);
cycle->free_connections = next;
diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h
index a1643a134..b7009a3d3 100644
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -27,14 +27,6 @@ typedef struct {
#endif
-typedef struct {
- ngx_uint_t lock;
-
- ngx_event_t *events;
- ngx_event_t *last;
-} ngx_event_mutex_t;
-
-
struct ngx_event_s {
void *data;
@@ -168,23 +160,21 @@ struct ngx_event_aio_s {
ngx_event_handler_pt handler;
ngx_file_t *file;
+#if (NGX_HAVE_AIO_SENDFILE)
+ ssize_t (*preload_handler)(ngx_buf_t *file);
+#endif
+
ngx_fd_t fd;
#if (NGX_HAVE_EVENTFD)
int64_t res;
-#if (NGX_TEST_BUILD_EPOLL)
- ngx_err_t err;
- size_t nbytes;
#endif
-#else
+
+#if !(NGX_HAVE_EVENTFD) || (NGX_TEST_BUILD_EPOLL)
ngx_err_t err;
size_t nbytes;
#endif
-#if (NGX_HAVE_AIO_SENDFILE)
- off_t last_offset;
-#endif
-
ngx_aiocb_t aiocb;
ngx_event_t event;
};
@@ -202,7 +192,8 @@ typedef struct {
ngx_int_t (*add_conn)(ngx_connection_t *c);
ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);
- ngx_int_t (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait);
+ ngx_int_t (*notify)(ngx_event_handler_pt handler);
+
ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags);
@@ -415,7 +406,6 @@ extern ngx_event_actions_t ngx_event_actions;
#endif
-#define ngx_process_changes ngx_event_actions.process_changes
#define ngx_process_events ngx_event_actions.process_events
#define ngx_done_events ngx_event_actions.done
@@ -424,6 +414,8 @@ extern ngx_event_actions_t ngx_event_actions;
#define ngx_add_conn ngx_event_actions.add_conn
#define ngx_del_conn ngx_event_actions.del_conn
+#define ngx_notify ngx_event_actions.notify
+
#define ngx_add_timer ngx_event_add_timer
#define ngx_del_timer ngx_event_del_timer
@@ -533,7 +525,6 @@ ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat);
#include <ngx_event_timer.h>
#include <ngx_event_posted.h>
-#include <ngx_event_busy_lock.h>
#if (NGX_WIN32)
#include <ngx_iocp_module.h>
diff --git a/src/event/ngx_event_busy_lock.c b/src/event/ngx_event_busy_lock.c
deleted file mode 100644
index fdac0da8f..000000000
--- a/src/event/ngx_event_busy_lock.c
+++ /dev/null
@@ -1,286 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_event.h>
-
-
-static ngx_int_t ngx_event_busy_lock_look_cacheable(ngx_event_busy_lock_t *bl,
- ngx_event_busy_lock_ctx_t *ctx);
-static void ngx_event_busy_lock_handler(ngx_event_t *ev);
-static void ngx_event_busy_lock_posted_handler(ngx_event_t *ev);
-
-
-/*
- * NGX_OK: the busy lock is held
- * NGX_AGAIN: the all busy locks are held but we will wait the specified time
- * NGX_BUSY: ctx->timer == 0: there are many the busy locks
- * ctx->timer != 0: there are many the waiting locks
- */
-
-ngx_int_t
-ngx_event_busy_lock(ngx_event_busy_lock_t *bl, ngx_event_busy_lock_ctx_t *ctx)
-{
- ngx_int_t rc;
-
- ngx_mutex_lock(bl->mutex);
-
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->event->log, 0,
- "event busy lock: b:%d mb:%d",
- bl->busy, bl->max_busy);
-
- if (bl->busy < bl->max_busy) {
- bl->busy++;
-
- rc = NGX_OK;
-
- } else if (ctx->timer && bl->waiting < bl->max_waiting) {
- bl->waiting++;
- ngx_add_timer(ctx->event, ctx->timer);
- ctx->event->handler = ngx_event_busy_lock_handler;
-
- if (bl->events) {
- bl->last->next = ctx;
-
- } else {
- bl->events = ctx;
- }
-
- bl->last = ctx;
-
- rc = NGX_AGAIN;
-
- } else {
- rc = NGX_BUSY;
- }
-
- ngx_mutex_unlock(bl->mutex);
-
- return rc;
-}
-
-
-ngx_int_t
-ngx_event_busy_lock_cacheable(ngx_event_busy_lock_t *bl,
- ngx_event_busy_lock_ctx_t *ctx)
-{
- ngx_int_t rc;
-
- ngx_mutex_lock(bl->mutex);
-
- rc = ngx_event_busy_lock_look_cacheable(bl, ctx);
-
- ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ctx->event->log, 0,
- "event busy lock: %d w:%d mw:%d",
- rc, bl->waiting, bl->max_waiting);
-
- /*
- * NGX_OK: no the same request, there is free slot and we locked it
- * NGX_BUSY: no the same request and there is no free slot
- * NGX_AGAIN: the same request is processing
- */
-
- if (rc == NGX_AGAIN) {
-
- if (ctx->timer && bl->waiting < bl->max_waiting) {
- bl->waiting++;
- ngx_add_timer(ctx->event, ctx->timer);
- ctx->event->handler = ngx_event_busy_lock_handler;
-
- if (bl->events == NULL) {
- bl->events = ctx;
- } else {
- bl->last->next = ctx;
- }
- bl->last = ctx;
-
- } else {
- rc = NGX_BUSY;
- }
- }
-
- ngx_mutex_unlock(bl->mutex);
-
- return rc;
-}
-
-
-void
-ngx_event_busy_unlock(ngx_event_busy_lock_t *bl,
- ngx_event_busy_lock_ctx_t *ctx)
-{
- ngx_event_t *ev;
- ngx_event_busy_lock_ctx_t *wakeup;
-
- ngx_mutex_lock(bl->mutex);
-
- if (bl->events) {
- wakeup = bl->events;
- bl->events = bl->events->next;
-
- } else {
- wakeup = NULL;
- bl->busy--;
- }
-
- /*
- * MP: all ctx's and their queue must be in shared memory,
- * each ctx has pid to wake up
- */
-
- if (wakeup == NULL) {
- ngx_mutex_unlock(bl->mutex);
- return;
- }
-
- if (ctx->md5) {
- for (wakeup = bl->events; wakeup; wakeup = wakeup->next) {
- if (wakeup->md5 == NULL || wakeup->slot != ctx->slot) {
- continue;
- }
-
- wakeup->handler = ngx_event_busy_lock_posted_handler;
- wakeup->cache_updated = 1;
-
- ev = wakeup->event;
-
- ngx_post_event(ev, &ngx_posted_events);
- }
-
- ngx_mutex_unlock(bl->mutex);
-
- } else {
- bl->waiting--;
-
- ngx_mutex_unlock(bl->mutex);
-
- wakeup->handler = ngx_event_busy_lock_posted_handler;
- wakeup->locked = 1;
-
- ev = wakeup->event;
-
- if (ev->timer_set) {
- ngx_del_timer(ev);
- }
-
- ngx_post_event(ev, &ngx_posted_events);
- }
-}
-
-
-void
-ngx_event_busy_lock_cancel(ngx_event_busy_lock_t *bl,
- ngx_event_busy_lock_ctx_t *ctx)
-{
- ngx_event_busy_lock_ctx_t *c, *p;
-
- ngx_mutex_lock(bl->mutex);
-
- bl->waiting--;
-
- if (ctx == bl->events) {
- bl->events = ctx->next;
-
- } else {
- p = bl->events;
- for (c = bl->events->next; c; c = c->next) {
- if (c == ctx) {
- p->next = ctx->next;
- break;
- }
- p = c;
- }
- }
-
- ngx_mutex_unlock(bl->mutex);
-}
-
-
-static ngx_int_t
-ngx_event_busy_lock_look_cacheable(ngx_event_busy_lock_t *bl,
- ngx_event_busy_lock_ctx_t *ctx)
-{
- ngx_int_t free;
- ngx_uint_t i, bit, cacheable, mask;
-
- bit = 0;
- cacheable = 0;
- free = -1;
-
-#if (NGX_SUPPRESS_WARN)
- mask = 0;
-#endif
-
- for (i = 0; i < bl->max_busy; i++) {
-
- if ((bit & 7) == 0) {
- mask = bl->md5_mask[i / 8];
- }
-
- if (mask & 1) {
- if (ngx_memcmp(&bl->md5[i * 16], ctx->md5, 16) == 0) {
- ctx->waiting = 1;
- ctx->slot = i;
- return NGX_AGAIN;
- }
- cacheable++;
-
- } else if (free == -1) {
- free = i;
- }
-
- if (cacheable == bl->cacheable) {
- if (free == -1 && cacheable < bl->max_busy) {
- free = i + 1;
- }
-
- break;
- }
-
- mask >>= 1;
- bit++;
- }
-
- if (free == -1) {
- return NGX_BUSY;
- }
-
-#if 0
- if (bl->busy == bl->max_busy) {
- return NGX_BUSY;
- }
-#endif
-
- ngx_memcpy(&bl->md5[free * 16], ctx->md5, 16);
- bl->md5_mask[free / 8] |= 1 << (free & 7);
- ctx->slot = free;
-
- bl->cacheable++;
- bl->busy++;
-
- return NGX_OK;
-}
-
-
-static void
-ngx_event_busy_lock_handler(ngx_event_t *ev)
-{
- ev->handler = ngx_event_busy_lock_posted_handler;
-
- ngx_post_event(ev, &ngx_posted_events);
-}
-
-
-static void
-ngx_event_busy_lock_posted_handler(ngx_event_t *ev)
-{
- ngx_event_busy_lock_ctx_t *ctx;
-
- ctx = ev->data;
- ctx->handler(ev);
-}
diff --git a/src/event/ngx_event_busy_lock.h b/src/event/ngx_event_busy_lock.h
deleted file mode 100644
index 254c233e7..000000000
--- a/src/event/ngx_event_busy_lock.h
+++ /dev/null
@@ -1,65 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
- */
-
-
-#ifndef _NGX_EVENT_BUSY_LOCK_H_INCLUDED_
-#define _NGX_EVENT_BUSY_LOCK_H_INCLUDED_
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_event.h>
-
-typedef struct ngx_event_busy_lock_ctx_s ngx_event_busy_lock_ctx_t;
-
-struct ngx_event_busy_lock_ctx_s {
- ngx_event_t *event;
- ngx_event_handler_pt handler;
- void *data;
- ngx_msec_t timer;
-
- unsigned locked:1;
- unsigned waiting:1;
- unsigned cache_updated:1;
-
- char *md5;
- ngx_int_t slot;
-
- ngx_event_busy_lock_ctx_t *next;
-};
-
-
-typedef struct {
- u_char *md5_mask;
- char *md5;
- ngx_uint_t cacheable;
-
- ngx_uint_t busy;
- ngx_uint_t max_busy;
-
- ngx_uint_t waiting;
- ngx_uint_t max_waiting;
-
- ngx_event_busy_lock_ctx_t *events;
- ngx_event_busy_lock_ctx_t *last;
-
-#if (NGX_THREADS)
- ngx_mutex_t *mutex;
-#endif
-} ngx_event_busy_lock_t;
-
-
-ngx_int_t ngx_event_busy_lock(ngx_event_busy_lock_t *bl,
- ngx_event_busy_lock_ctx_t *ctx);
-ngx_int_t ngx_event_busy_lock_cacheable(ngx_event_busy_lock_t *bl,
- ngx_event_busy_lock_ctx_t *ctx);
-void ngx_event_busy_unlock(ngx_event_busy_lock_t *bl,
- ngx_event_busy_lock_ctx_t *ctx);
-void ngx_event_busy_lock_cancel(ngx_event_busy_lock_t *bl,
- ngx_event_busy_lock_ctx_t *ctx);
-
-
-#endif /* _NGX_EVENT_BUSY_LOCK_H_INCLUDED_ */
diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h
index e73825885..ed18db7c3 100644
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -53,10 +53,6 @@ struct ngx_peer_connection_s {
ngx_event_save_peer_session_pt save_session;
#endif
-#if (NGX_THREADS)
- ngx_atomic_t *lock;
-#endif
-
ngx_addr_t *local;
int rcvbuf;
diff --git a/src/event/ngx_event_mutex.c b/src/event/ngx_event_mutex.c
deleted file mode 100644
index 98efbb0d8..000000000
--- a/src/event/ngx_event_mutex.c
+++ /dev/null
@@ -1,70 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_event.h>
-
-
-ngx_int_t ngx_event_mutex_timedlock(ngx_event_mutex_t *m, ngx_msec_t timer,
- ngx_event_t *ev)
-{
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
- "lock event mutex %p lock:%XD", m, m->lock);
-
- if (m->lock) {
-
- if (m->events == NULL) {
- m->events = ev;
-
- } else {
- m->last->next = ev;
- }
-
- m->last = ev;
- ev->next = NULL;
-
-#if (NGX_THREADS0)
- ev->light = 1;
-#endif
-
- ngx_add_timer(ev, timer);
-
- return NGX_AGAIN;
- }
-
- m->lock = 1;
-
- return NGX_OK;
-}
-
-
-ngx_int_t ngx_event_mutex_unlock(ngx_event_mutex_t *m, ngx_log_t *log)
-{
- ngx_event_t *ev;
-
- if (m->lock == 0) {
- ngx_log_error(NGX_LOG_ALERT, log, 0,
- "tring to unlock the free event mutex %p", m);
- return NGX_ERROR;
- }
-
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
- "unlock event mutex %p, next event: %p", m, m->events);
-
- m->lock = 0;
-
- if (m->events) {
- ev = m->events;
- m->events = ev->next;
-
- ev->next = ngx_posted_events;
- ngx_posted_events = ev;
- }
-
- return NGX_OK;
-}
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index d5d4a1ac9..1b789e687 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -249,6 +249,12 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
+#ifdef SSL_CTRL_CLEAR_OPTIONS
+ /* only in 0.9.8m+ */
+ SSL_CTX_clear_options(ssl->ctx,
+ SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1);
+#endif
+
if (!(protocols & NGX_SSL_SSLv2)) {
SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2);
}
@@ -259,11 +265,13 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1);
}
#ifdef SSL_OP_NO_TLSv1_1
+ SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TLSv1_1);
if (!(protocols & NGX_SSL_TLSv1_1)) {
SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_1);
}
#endif
#ifdef SSL_OP_NO_TLSv1_2
+ SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
if (!(protocols & NGX_SSL_TLSv1_2)) {
SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
}
@@ -277,6 +285,10 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
SSL_CTX_set_mode(ssl->ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
+#ifdef SSL_MODE_NO_AUTO_CHAIN
+ SSL_CTX_set_mode(ssl->ctx, SSL_MODE_NO_AUTO_CHAIN);
+#endif
+
SSL_CTX_set_read_ahead(ssl->ctx, 1);
SSL_CTX_set_info_callback(ssl->ctx, ngx_ssl_info_callback);
@@ -1516,7 +1528,6 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
}
in->buf->pos += n;
- c->sent += n;
if (in->buf->pos == in->buf->last) {
in = in->next;
@@ -1617,7 +1628,6 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
}
buf->pos += n;
- c->sent += n;
if (n < size) {
break;
@@ -1675,6 +1685,8 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size)
ngx_post_event(c->read, &ngx_posted_events);
}
+ c->sent += n;
+
return n;
}
diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c
index 62663d5a4..8ba247f4a 100644
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -376,7 +376,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe buf busy s:%d t:%d f:%d "
"%p, pos %p, size: %z "
- "file: %O, size: %z",
+ "file: %O, size: %O",
(cl->buf->shadow ? 1 : 0),
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
@@ -389,7 +389,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe buf out s:%d t:%d f:%d "
"%p, pos %p, size: %z "
- "file: %O, size: %z",
+ "file: %O, size: %O",
(cl->buf->shadow ? 1 : 0),
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
@@ -402,7 +402,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe buf in s:%d t:%d f:%d "
"%p, pos %p, size: %z "
- "file: %O, size: %z",
+ "file: %O, size: %O",
(cl->buf->shadow ? 1 : 0),
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
@@ -415,7 +415,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe buf free s:%d t:%d f:%d "
"%p, pos %p, size: %z "
- "file: %O, size: %z",
+ "file: %O, size: %O",
(cl->buf->shadow ? 1 : 0),
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index 1bf4ac332..f3f78e804 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -81,8 +81,12 @@ typedef struct {
size_t length;
size_t padding;
+ ngx_chain_t *free;
+ ngx_chain_t *busy;
+
unsigned fastcgi_stdout:1;
unsigned large_stderr:1;
+ unsigned header_sent:1;
ngx_array_t *split_parts;
@@ -147,6 +151,8 @@ static ngx_int_t ngx_http_fastcgi_create_key(ngx_http_request_t *r);
#endif
static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_fastcgi_body_output_filter(void *data,
+ ngx_chain_t *in);
static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r);
static ngx_int_t ngx_http_fastcgi_input_filter_init(void *data);
static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p,
@@ -257,6 +263,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffering),
NULL },
+ { ngx_string("fastcgi_request_buffering"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_fastcgi_loc_conf_t, upstream.request_buffering),
+ NULL },
+
{ ngx_string("fastcgi_ignore_client_abort"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -703,6 +716,12 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r)
u->input_filter = ngx_http_fastcgi_non_buffered_filter;
u->input_filter_ctx = r;
+ if (!flcf->upstream.request_buffering
+ && flcf->upstream.pass_request_body)
+ {
+ r->request_body_no_buffering = 1;
+ }
+
rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
@@ -799,6 +818,7 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
ngx_chain_t *cl, *body;
ngx_list_part_t *part;
ngx_table_elt_t *header, **ignored;
+ ngx_http_upstream_t *u;
ngx_http_script_code_pt code;
ngx_http_script_engine_t e, le;
ngx_http_fastcgi_header_t *h;
@@ -810,10 +830,12 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
header_params = 0;
ignored = NULL;
+ u = r->upstream;
+
flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
#if (NGX_HTTP_CACHE)
- params = r->upstream->cacheable ? &flcf->params_cache : &flcf->params;
+ params = u->cacheable ? &flcf->params_cache : &flcf->params;
#else
params = &flcf->params;
#endif
@@ -1134,12 +1156,17 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
h->padding_length = 0;
h->reserved = 0;
- h = (ngx_http_fastcgi_header_t *) b->last;
- b->last += sizeof(ngx_http_fastcgi_header_t);
+ if (r->request_body_no_buffering) {
+
+ u->request_bufs = cl;
+
+ u->output.output_filter = ngx_http_fastcgi_body_output_filter;
+ u->output.filter_ctx = r;
- if (flcf->upstream.pass_request_body) {
- body = r->upstream->request_bufs;
- r->upstream->request_bufs = cl;
+ } else if (flcf->upstream.pass_request_body) {
+
+ body = u->request_bufs;
+ u->request_bufs = cl;
#if (NGX_SUPPRESS_WARN)
file_pos = 0;
@@ -1194,6 +1221,9 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
padding = 8 - len % 8;
padding = (padding == 8) ? 0 : padding;
+ h = (ngx_http_fastcgi_header_t *) cl->buf->last;
+ cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
+
h->version = 1;
h->type = NGX_HTTP_FASTCGI_STDIN;
h->request_id_hi = 0;
@@ -1223,9 +1253,6 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
b->last += padding;
}
- h = (ngx_http_fastcgi_header_t *) b->last;
- b->last += sizeof(ngx_http_fastcgi_header_t);
-
cl->next = ngx_alloc_chain_link(r->pool);
if (cl->next == NULL) {
return NGX_ERROR;
@@ -1240,17 +1267,22 @@ ngx_http_fastcgi_create_request(ngx_http_request_t *r)
}
} else {
- r->upstream->request_bufs = cl;
+ u->request_bufs = cl;
}
- h->version = 1;
- h->type = NGX_HTTP_FASTCGI_STDIN;
- h->request_id_hi = 0;
- h->request_id_lo = 1;
- h->content_length_hi = 0;
- h->content_length_lo = 0;
- h->padding_length = 0;
- h->reserved = 0;
+ if (!r->request_body_no_buffering) {
+ h = (ngx_http_fastcgi_header_t *) cl->buf->last;
+ cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
+
+ h->version = 1;
+ h->type = NGX_HTTP_FASTCGI_STDIN;
+ h->request_id_hi = 0;
+ h->request_id_lo = 1;
+ h->content_length_hi = 0;
+ h->content_length_lo = 0;
+ h->padding_length = 0;
+ h->reserved = 0;
+ }
cl->next = NULL;
@@ -1284,6 +1316,294 @@ ngx_http_fastcgi_reinit_request(ngx_http_request_t *r)
static ngx_int_t
+ngx_http_fastcgi_body_output_filter(void *data, ngx_chain_t *in)
+{
+ ngx_http_request_t *r = data;
+
+ off_t file_pos;
+ u_char *pos, *start;
+ size_t len, padding;
+ ngx_buf_t *b;
+ ngx_int_t rc;
+ ngx_uint_t next, last;
+ ngx_chain_t *cl, *tl, *out, **ll;
+ ngx_http_fastcgi_ctx_t *f;
+ ngx_http_fastcgi_header_t *h;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "fastcgi output filter");
+
+ f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
+
+ if (in == NULL) {
+ out = in;
+ goto out;
+ }
+
+ out = NULL;
+ ll = &out;
+
+ if (!f->header_sent) {
+ /* first buffer contains headers, pass it unmodified */
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "fastcgi output header");
+
+ f->header_sent = 1;
+
+ tl = ngx_alloc_chain_link(r->pool);
+ if (tl == NULL) {
+ return NGX_ERROR;
+ }
+
+ tl->buf = in->buf;
+ *ll = tl;
+ ll = &tl->next;
+
+ in = in->next;
+
+ if (in == NULL) {
+ tl->next = NULL;
+ goto out;
+ }
+ }
+
+ cl = ngx_chain_get_free_buf(r->pool, &f->free);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ b = cl->buf;
+
+ b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
+ b->temporary = 1;
+
+ if (b->start == NULL) {
+ /* reserve space for maximum possible padding, 7 bytes */
+
+ b->start = ngx_palloc(r->pool,
+ sizeof(ngx_http_fastcgi_header_t) + 7);
+ if (b->start == NULL) {
+ return NGX_ERROR;
+ }
+
+ b->pos = b->start;
+ b->last = b->start;
+
+ b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
+ }
+
+ *ll = cl;
+
+ last = 0;
+ padding = 0;
+
+#if (NGX_SUPPRESS_WARN)
+ file_pos = 0;
+ pos = NULL;
+#endif
+
+ while (in) {
+
+ ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
+ "fastcgi output in l:%d f:%d %p, pos %p, size: %z "
+ "file: %O, size: %O",
+ in->buf->last_buf,
+ in->buf->in_file,
+ in->buf->start, in->buf->pos,
+ in->buf->last - in->buf->pos,
+ in->buf->file_pos,
+ in->buf->file_last - in->buf->file_pos);
+
+ if (in->buf->last_buf) {
+ last = 1;
+ }
+
+ if (ngx_buf_special(in->buf)) {
+ in = in->next;
+ continue;
+ }
+
+ if (in->buf->in_file) {
+ file_pos = in->buf->file_pos;
+
+ } else {
+ pos = in->buf->pos;
+ }
+
+ next = 0;
+
+ do {
+ tl = ngx_chain_get_free_buf(r->pool, &f->free);
+ if (tl == NULL) {
+ return NGX_ERROR;
+ }
+
+ b = tl->buf;
+ start = b->start;
+
+ ngx_memcpy(b, in->buf, sizeof(ngx_buf_t));
+
+ /*
+ * restore b->start to preserve memory allocated in the buffer,
+ * to reuse it later for headers and padding
+ */
+
+ b->start = start;
+
+ if (in->buf->in_file) {
+ b->file_pos = file_pos;
+ file_pos += 32 * 1024;
+
+ if (file_pos >= in->buf->file_last) {
+ file_pos = in->buf->file_last;
+ next = 1;
+ }
+
+ b->file_last = file_pos;
+ len = (ngx_uint_t) (file_pos - b->file_pos);
+
+ } else {
+ b->pos = pos;
+ pos += 32 * 1024;
+
+ if (pos >= in->buf->last) {
+ pos = in->buf->last;
+ next = 1;
+ }
+
+ b->last = pos;
+ len = (ngx_uint_t) (pos - b->pos);
+ }
+
+ b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
+ b->shadow = in->buf;
+ b->last_shadow = next;
+
+ b->last_buf = 0;
+ b->last_in_chain = 0;
+
+ padding = 8 - len % 8;
+ padding = (padding == 8) ? 0 : padding;
+
+ h = (ngx_http_fastcgi_header_t *) cl->buf->last;
+ cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
+
+ h->version = 1;
+ h->type = NGX_HTTP_FASTCGI_STDIN;
+ h->request_id_hi = 0;
+ h->request_id_lo = 1;
+ h->content_length_hi = (u_char) ((len >> 8) & 0xff);
+ h->content_length_lo = (u_char) (len & 0xff);
+ h->padding_length = (u_char) padding;
+ h->reserved = 0;
+
+ cl->next = tl;
+ cl = tl;
+
+ tl = ngx_chain_get_free_buf(r->pool, &f->free);
+ if (tl == NULL) {
+ return NGX_ERROR;
+ }
+
+ b = tl->buf;
+
+ b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
+ b->temporary = 1;
+
+ if (b->start == NULL) {
+ /* reserve space for maximum possible padding, 7 bytes */
+
+ b->start = ngx_palloc(r->pool,
+ sizeof(ngx_http_fastcgi_header_t) + 7);
+ if (b->start == NULL) {
+ return NGX_ERROR;
+ }
+
+ b->pos = b->start;
+ b->last = b->start;
+
+ b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
+ }
+
+ if (padding) {
+ ngx_memzero(b->last, padding);
+ b->last += padding;
+ }
+
+ cl->next = tl;
+ cl = tl;
+
+ } while (!next);
+
+ in = in->next;
+ }
+
+ if (last) {
+ h = (ngx_http_fastcgi_header_t *) cl->buf->last;
+ cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
+
+ h->version = 1;
+ h->type = NGX_HTTP_FASTCGI_STDIN;
+ h->request_id_hi = 0;
+ h->request_id_lo = 1;
+ h->content_length_hi = 0;
+ h->content_length_lo = 0;
+ h->padding_length = 0;
+ h->reserved = 0;
+
+ cl->buf->last_buf = 1;
+
+ } else if (padding == 0) {
+ /* TODO: do not allocate buffers instead */
+ cl->buf->temporary = 0;
+ cl->buf->sync = 1;
+ }
+
+ cl->next = NULL;
+
+out:
+
+#if (NGX_DEBUG)
+
+ for (cl = out; cl; cl = cl->next) {
+ ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
+ "fastcgi output out l:%d f:%d %p, pos %p, size: %z "
+ "file: %O, size: %O",
+ cl->buf->last_buf,
+ cl->buf->in_file,
+ cl->buf->start, cl->buf->pos,
+ cl->buf->last - cl->buf->pos,
+ cl->buf->file_pos,
+ cl->buf->file_last - cl->buf->file_pos);
+ }
+
+#endif
+
+ rc = ngx_chain_writer(&r->upstream->writer, out);
+
+ ngx_chain_update_chains(r->pool, &f->free, &f->busy, &out,
+ (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter);
+
+ for (cl = f->free; cl; cl = cl->next) {
+
+ /* mark original buffers as sent */
+
+ if (cl->buf->shadow) {
+ if (cl->buf->last_shadow) {
+ b = cl->buf->shadow;
+ b->pos = b->last;
+ }
+
+ cl->buf->shadow = NULL;
+ }
+ }
+
+ return rc;
+}
+
+
+static ngx_int_t
ngx_http_fastcgi_process_header(ngx_http_request_t *r)
{
u_char *p, *msg, *start, *last,
@@ -2405,6 +2725,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.store_access = NGX_CONF_UNSET_UINT;
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
+ conf->upstream.request_buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
conf->upstream.force_ranges = NGX_CONF_UNSET;
@@ -2498,6 +2819,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
+ ngx_conf_merge_value(conf->upstream.request_buffering,
+ prev->upstream.request_buffering, 1);
+
ngx_conf_merge_value(conf->upstream.ignore_client_abort,
prev->upstream.ignore_client_abort, 0);
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index d7675d468..d0b1c885d 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -110,7 +110,12 @@ typedef struct {
ngx_http_proxy_vars_t vars;
off_t internal_body_length;
- ngx_uint_t head; /* unsigned head:1 */
+ ngx_chain_t *free;
+ ngx_chain_t *busy;
+
+ unsigned head:1;
+ unsigned internal_chunked:1;
+ unsigned header_sent:1;
} ngx_http_proxy_ctx_t;
@@ -121,6 +126,7 @@ static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
#endif
static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in);
static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
@@ -146,6 +152,8 @@ static ngx_int_t
static ngx_int_t
ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
ngx_table_elt_t *h, size_t prefix);
static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
@@ -292,6 +300,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
NULL },
+ { ngx_string("proxy_request_buffering"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.request_buffering),
+ NULL },
+
{ ngx_string("proxy_ignore_client_abort"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -721,8 +736,8 @@ static ngx_keyval_t ngx_http_proxy_headers[] = {
{ ngx_string("Host"), ngx_string("$proxy_host") },
{ ngx_string("Connection"), ngx_string("close") },
{ ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
+ { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
{ ngx_string("TE"), ngx_string("") },
- { ngx_string("Transfer-Encoding"), ngx_string("") },
{ ngx_string("Keep-Alive"), ngx_string("") },
{ ngx_string("Expect"), ngx_string("") },
{ ngx_string("Upgrade"), ngx_string("") },
@@ -749,8 +764,8 @@ static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
{ ngx_string("Host"), ngx_string("$proxy_host") },
{ ngx_string("Connection"), ngx_string("close") },
{ ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
+ { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
{ ngx_string("TE"), ngx_string("") },
- { ngx_string("Transfer-Encoding"), ngx_string("") },
{ ngx_string("Keep-Alive"), ngx_string("") },
{ ngx_string("Expect"), ngx_string("") },
{ ngx_string("Upgrade"), ngx_string("") },
@@ -786,6 +801,10 @@ static ngx_http_variable_t ngx_http_proxy_vars[] = {
ngx_http_proxy_internal_body_length_variable, 0,
NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
+ { ngx_string("proxy_internal_chunked"), NULL,
+ ngx_http_proxy_internal_chunked_variable, 0,
+ NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
+
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
@@ -812,7 +831,7 @@ ngx_http_proxy_handler(ngx_http_request_t *r)
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
if (ctx == NULL) {
- return NGX_ERROR;
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
@@ -876,6 +895,14 @@ ngx_http_proxy_handler(ngx_http_request_t *r)
u->accel = 1;
+ if (!plcf->upstream.request_buffering
+ && plcf->body_values == NULL && plcf->upstream.pass_request_body
+ && (!r->headers_in.chunked
+ || plcf->http_version == NGX_HTTP_VERSION_11))
+ {
+ r->request_body_no_buffering = 1;
+ }
+
rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
@@ -1194,6 +1221,10 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
ctx->internal_body_length = body_len;
len += body_len;
+ } else if (r->headers_in.chunked && r->reading_body) {
+ ctx->internal_body_length = -1;
+ ctx->internal_chunked = 1;
+
} else {
ctx->internal_body_length = r->headers_in.content_length_n;
}
@@ -1379,6 +1410,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
if (plcf->body_values) {
e.ip = plcf->body_values->elts;
e.pos = b->last;
+ e.skip = 0;
while (*(uintptr_t *) e.ip) {
code = *(ngx_http_script_code_pt *) e.ip;
@@ -1392,7 +1424,16 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
"http proxy header:%N\"%*s\"",
(size_t) (b->last - b->pos), b->pos);
- if (plcf->body_values == NULL && plcf->upstream.pass_request_body) {
+ if (r->request_body_no_buffering) {
+
+ u->request_bufs = cl;
+
+ if (ctx->internal_chunked) {
+ u->output.output_filter = ngx_http_proxy_body_output_filter;
+ u->output.filter_ctx = r;
+ }
+
+ } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) {
body = u->request_bufs;
u->request_bufs = cl;
@@ -1454,6 +1495,172 @@ ngx_http_proxy_reinit_request(ngx_http_request_t *r)
static ngx_int_t
+ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in)
+{
+ ngx_http_request_t *r = data;
+
+ off_t size;
+ u_char *chunk;
+ ngx_int_t rc;
+ ngx_buf_t *b;
+ ngx_chain_t *out, *cl, *tl, **ll;
+ ngx_http_proxy_ctx_t *ctx;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "proxy output filter");
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (in == NULL) {
+ out = in;
+ goto out;
+ }
+
+ out = NULL;
+ ll = &out;
+
+ if (!ctx->header_sent) {
+ /* first buffer contains headers, pass it unmodified */
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "proxy output header");
+
+ ctx->header_sent = 1;
+
+ tl = ngx_alloc_chain_link(r->pool);
+ if (tl == NULL) {
+ return NGX_ERROR;
+ }
+
+ tl->buf = in->buf;
+ *ll = tl;
+ ll = &tl->next;
+
+ in = in->next;
+
+ if (in == NULL) {
+ tl->next = NULL;
+ goto out;
+ }
+ }
+
+ size = 0;
+ cl = in;
+
+ for ( ;; ) {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "proxy output chunk: %d", ngx_buf_size(cl->buf));
+
+ size += ngx_buf_size(cl->buf);
+
+ if (cl->buf->flush
+ || cl->buf->sync
+ || ngx_buf_in_memory(cl->buf)
+ || cl->buf->in_file)
+ {
+ tl = ngx_alloc_chain_link(r->pool);
+ if (tl == NULL) {
+ return NGX_ERROR;
+ }
+
+ tl->buf = cl->buf;
+ *ll = tl;
+ ll = &tl->next;
+ }
+
+ if (cl->next == NULL) {
+ break;
+ }
+
+ cl = cl->next;
+ }
+
+ if (size) {
+ tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+ if (tl == NULL) {
+ return NGX_ERROR;
+ }
+
+ b = tl->buf;
+ chunk = b->start;
+
+ if (chunk == NULL) {
+ /* the "0000000000000000" is 64-bit hexadecimal string */
+
+ chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
+ if (chunk == NULL) {
+ return NGX_ERROR;
+ }
+
+ b->start = chunk;
+ b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
+ }
+
+ b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
+ b->memory = 0;
+ b->temporary = 1;
+ b->pos = chunk;
+ b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
+
+ tl->next = out;
+ out = tl;
+ }
+
+ if (cl->buf->last_buf) {
+ tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+ if (tl == NULL) {
+ return NGX_ERROR;
+ }
+
+ b = tl->buf;
+
+ b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
+ b->temporary = 0;
+ b->memory = 1;
+ b->last_buf = 1;
+ b->pos = (u_char *) CRLF "0" CRLF CRLF;
+ b->last = b->pos + 7;
+
+ cl->buf->last_buf = 0;
+
+ *ll = tl;
+
+ if (size == 0) {
+ b->pos += 2;
+ }
+
+ } else if (size > 0) {
+ tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
+ if (tl == NULL) {
+ return NGX_ERROR;
+ }
+
+ b = tl->buf;
+
+ b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
+ b->temporary = 0;
+ b->memory = 1;
+ b->pos = (u_char *) CRLF;
+ b->last = b->pos + 2;
+
+ *ll = tl;
+
+ } else {
+ *ll = NULL;
+ }
+
+out:
+
+ rc = ngx_chain_writer(&r->upstream->writer, out);
+
+ ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
+ (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter);
+
+ return rc;
+}
+
+
+static ngx_int_t
ngx_http_proxy_process_status_line(ngx_http_request_t *r)
{
size_t len;
@@ -2247,6 +2454,30 @@ ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
static ngx_int_t
+ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ ngx_http_proxy_ctx_t *ctx;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (ctx == NULL || !ctx->internal_chunked) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+
+ v->data = (u_char *) "chunked";
+ v->len = sizeof("chunked") - 1;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
size_t prefix)
{
@@ -2581,6 +2812,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.store_access = NGX_CONF_UNSET_UINT;
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
+ conf->upstream.request_buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
conf->upstream.force_ranges = NGX_CONF_UNSET;
@@ -2690,6 +2922,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
+ ngx_conf_merge_value(conf->upstream.request_buffering,
+ prev->upstream.request_buffering, 1);
+
ngx_conf_merge_value(conf->upstream.ignore_client_abort,
prev->upstream.ignore_client_abort, 0);
diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c
index 6a65e4849..bb9a42c54 100644
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -274,7 +274,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx,
ngx_uint_t ranges)
{
u_char *p;
- off_t start, end, size, content_length;
+ off_t start, end, size, content_length, cutoff, cutlim;
ngx_uint_t suffix;
ngx_http_range_t *range;
@@ -282,6 +282,9 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx,
size = 0;
content_length = r->headers_out.content_length_n;
+ cutoff = NGX_MAX_OFF_T_VALUE / 10;
+ cutlim = NGX_MAX_OFF_T_VALUE % 10;
+
for ( ;; ) {
start = 0;
end = 0;
@@ -295,6 +298,10 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx,
}
while (*p >= '0' && *p <= '9') {
+ if (start >= cutoff && (start > cutoff || *p - '0' > cutlim)) {
+ return NGX_HTTP_RANGE_NOT_SATISFIABLE;
+ }
+
start = start * 10 + *p++ - '0';
}
@@ -321,6 +328,10 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx,
}
while (*p >= '0' && *p <= '9') {
+ if (end >= cutoff && (end > cutoff || *p - '0' > cutlim)) {
+ return NGX_HTTP_RANGE_NOT_SATISFIABLE;
+ }
+
end = end * 10 + *p++ - '0';
}
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index 33c23a5a1..6e5b0770c 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -120,6 +120,13 @@ static ngx_command_t ngx_http_scgi_commands[] = {
offsetof(ngx_http_scgi_loc_conf_t, upstream.buffering),
NULL },
+ { ngx_string("scgi_request_buffering"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_scgi_loc_conf_t, upstream.request_buffering),
+ NULL },
+
{ ngx_string("scgi_ignore_client_abort"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -504,6 +511,13 @@ ngx_http_scgi_handler(ngx_http_request_t *r)
u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
u->pipe->input_ctx = r;
+ if (!scf->upstream.request_buffering
+ && scf->upstream.pass_request_body
+ && !r->headers_in.chunked)
+ {
+ r->request_body_no_buffering = 1;
+ }
+
rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
@@ -865,7 +879,10 @@ ngx_http_scgi_create_request(ngx_http_request_t *r)
*b->last++ = (u_char) ',';
- if (scf->upstream.pass_request_body) {
+ if (r->request_body_no_buffering) {
+ r->upstream->request_bufs = cl;
+
+ } else if (scf->upstream.pass_request_body) {
body = r->upstream->request_bufs;
r->upstream->request_bufs = cl;
@@ -1162,6 +1179,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.store_access = NGX_CONF_UNSET_UINT;
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
+ conf->upstream.request_buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
conf->upstream.force_ranges = NGX_CONF_UNSET;
@@ -1250,6 +1268,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
+ ngx_conf_merge_value(conf->upstream.request_buffering,
+ prev->upstream.request_buffering, 1);
+
ngx_conf_merge_value(conf->upstream.ignore_client_abort,
prev->upstream.ignore_client_abort, 0);
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index 4c69091d6..275febe65 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -715,8 +715,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
}
+#ifndef LIBRESSL_VERSION_NUMBER
/* a temporary 512-bit RSA key is required for export versions of MSIE */
SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback);
+#endif
if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) {
return NGX_CONF_ERROR;
diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c
index 777e180a5..a1f0ff3c9 100644
--- a/src/http/modules/ngx_http_upstream_hash_module.c
+++ b/src/http/modules/ngx_http_upstream_hash_module.c
@@ -49,8 +49,8 @@ static ngx_int_t ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc,
static ngx_int_t ngx_http_upstream_init_chash(ngx_conf_t *cf,
ngx_http_upstream_srv_conf_t *us);
-static void ngx_http_upstream_add_chash_point(
- ngx_http_upstream_chash_points_t *points, uint32_t hash, ngx_str_t *server);
+static int ngx_libc_cdecl
+ ngx_http_upstream_chash_cmp_points(const void *one, const void *two);
static ngx_uint_t ngx_http_upstream_find_chash_point(
ngx_http_upstream_chash_points_t *points, uint32_t hash);
static ngx_int_t ngx_http_upstream_init_chash_peer(ngx_http_request_t *r,
@@ -360,12 +360,27 @@ ngx_http_upstream_init_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
ngx_crc32_update(&hash, (u_char *) &prev_hash, sizeof(uint32_t));
ngx_crc32_final(hash);
- ngx_http_upstream_add_chash_point(points, hash, &peer->server);
+ points->point[points->number].hash = hash;
+ points->point[points->number].server = server;
+ points->number++;
prev_hash = hash;
}
}
+ ngx_qsort(points->point,
+ points->number,
+ sizeof(ngx_http_upstream_chash_point_t),
+ ngx_http_upstream_chash_cmp_points);
+
+ for (i = 0, j = 1; j < points->number; j++) {
+ if (points->point[i].hash != points->point[j].hash) {
+ points->point[++i] = points->point[j];
+ }
+ }
+
+ points->number = i + 1;
+
hcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_hash_module);
hcf->points = points;
@@ -373,28 +388,23 @@ ngx_http_upstream_init_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
}
-static void
-ngx_http_upstream_add_chash_point(ngx_http_upstream_chash_points_t *points,
- uint32_t hash, ngx_str_t *server)
+static int ngx_libc_cdecl
+ngx_http_upstream_chash_cmp_points(const void *one, const void *two)
{
- size_t size;
- ngx_uint_t i;
- ngx_http_upstream_chash_point_t *point;
+ ngx_http_upstream_chash_point_t *first =
+ (ngx_http_upstream_chash_point_t *) one;
+ ngx_http_upstream_chash_point_t *second =
+ (ngx_http_upstream_chash_point_t *) two;
- i = ngx_http_upstream_find_chash_point(points, hash);
- point = &points->point[i];
+ if (first->hash < second->hash) {
+ return -1;
- if (point->hash == hash) {
- return;
- }
-
- size = (points->number - i) * sizeof(ngx_http_upstream_chash_point_t);
-
- ngx_memmove(point + 1, point, size);
+ } else if (first->hash > second->hash) {
+ return 1;
- points->number++;
- point->hash = hash;
- point->server = server;
+ } else {
+ return 0;
+ }
}
diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c
index f738f0cc1..4e005fc0e 100644
--- a/src/http/modules/ngx_http_upstream_keepalive_module.c
+++ b/src/http/modules/ngx_http_upstream_keepalive_module.c
@@ -387,7 +387,7 @@ ngx_http_upstream_keepalive_close_handler(ngx_event_t *ev)
n = recv(c->fd, buf, 1, MSG_PEEK);
if (n == -1 && ngx_socket_errno == NGX_EAGAIN) {
- /* stale event */
+ ev->ready = 0;
if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
goto close;
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index f833d675c..0d0bc5857 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -180,6 +180,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.buffering),
NULL },
+ { ngx_string("uwsgi_request_buffering"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_uwsgi_loc_conf_t, upstream.request_buffering),
+ NULL },
+
{ ngx_string("uwsgi_ignore_client_abort"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -672,6 +679,13 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r)
u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
u->pipe->input_ctx = r;
+ if (!uwcf->upstream.request_buffering
+ && uwcf->upstream.pass_request_body
+ && !r->headers_in.chunked)
+ {
+ r->request_body_no_buffering = 1;
+ }
+
rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
@@ -1068,7 +1082,10 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r)
b->last = ngx_copy(b->last, uwcf->uwsgi_string.data,
uwcf->uwsgi_string.len);
- if (uwcf->upstream.pass_request_body) {
+ if (r->request_body_no_buffering) {
+ r->upstream->request_bufs = cl;
+
+ } else if (uwcf->upstream.pass_request_body) {
body = r->upstream->request_bufs;
r->upstream->request_bufs = cl;
@@ -1368,6 +1385,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.store_access = NGX_CONF_UNSET_UINT;
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
+ conf->upstream.request_buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
conf->upstream.force_ranges = NGX_CONF_UNSET;
@@ -1464,6 +1482,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
+ ngx_conf_merge_value(conf->upstream.request_buffering,
+ prev->upstream.request_buffering, 1);
+
ngx_conf_merge_value(conf->upstream.ignore_client_abort,
prev->upstream.ignore_client_abort, 0);
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c
index 9c8d6cba4..72981c17b 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -69,8 +69,9 @@ static ngx_int_t ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport,
ngx_uint_t ngx_http_max_module;
-ngx_int_t (*ngx_http_top_header_filter) (ngx_http_request_t *r);
-ngx_int_t (*ngx_http_top_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
+ngx_http_output_header_filter_pt ngx_http_top_header_filter;
+ngx_http_output_body_filter_pt ngx_http_top_body_filter;
+ngx_http_request_body_filter_pt ngx_http_top_request_body_filter;
ngx_str_t ngx_http_html_default_types[] = {
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index 0acc23494..b1e5fae6a 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -36,7 +36,6 @@ typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r,
#include <ngx_http_script.h>
#include <ngx_http_upstream.h>
#include <ngx_http_upstream_round_robin.h>
-#include <ngx_http_busy_lock.h>
#include <ngx_http_core_module.h>
#if (NGX_HTTP_SPDY)
@@ -131,9 +130,6 @@ void ngx_http_empty_handler(ngx_event_t *wev);
void ngx_http_request_empty_handler(ngx_http_request_t *r);
-#define ngx_http_ephemeral(r) (void *) (&r->uri_start)
-
-
#define NGX_HTTP_LAST 1
#define NGX_HTTP_FLUSH 2
@@ -142,6 +138,7 @@ ngx_int_t ngx_http_send_special(ngx_http_request_t *r, ngx_uint_t flags);
ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r,
ngx_http_client_body_handler_pt post_handler);
+ngx_int_t ngx_http_read_unbuffered_request_body(ngx_http_request_t *r);
ngx_int_t ngx_http_send_header(ngx_http_request_t *r);
ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r,
@@ -181,6 +178,7 @@ extern ngx_str_t ngx_http_html_default_types[];
extern ngx_http_output_header_filter_pt ngx_http_top_header_filter;
extern ngx_http_output_body_filter_pt ngx_http_top_body_filter;
+extern ngx_http_request_body_filter_pt ngx_http_top_request_body_filter;
#endif /* _NGX_HTTP_H_INCLUDED_ */
diff --git a/src/http/ngx_http_busy_lock.c b/src/http/ngx_http_busy_lock.c
deleted file mode 100644
index 3b4b28c8b..000000000
--- a/src/http/ngx_http_busy_lock.c
+++ /dev/null
@@ -1,307 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-
-
-
-static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl,
- ngx_http_busy_lock_ctx_t *bc,
- int lock);
-
-
-int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc)
-{
- if (bl->busy < bl->max_busy) {
- bl->busy++;
-
- if (bc->time) {
- bc->time = 0;
- bl->waiting--;
- }
-
- return NGX_OK;
- }
-
- if (bc->time) {
- if (bc->time < bl->timeout) {
- ngx_add_timer(bc->event, 1000);
- return NGX_AGAIN;
- }
-
- bl->waiting--;
- return NGX_DONE;
-
- }
-
- if (bl->timeout == 0) {
- return NGX_DONE;
- }
-
- if (bl->waiting < bl->max_waiting) {
- bl->waiting++;
-
-#if 0
- ngx_add_timer(bc->event, 1000);
- bc->event->event_handler = bc->event_handler;
-#endif
-
- /* TODO: ngx_handle_level_read_event() */
-
- return NGX_AGAIN;
- }
-
- return NGX_ERROR;
-}
-
-
-int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl,
- ngx_http_busy_lock_ctx_t *bc, int lock)
-{
- int rc;
-
- rc = ngx_http_busy_lock_look_cacheable(bl, bc, lock);
-
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, bc->event->log, 0,
- "http busylock: %d w:%d mw::%d",
- rc, bl->waiting, bl->max_waiting);
-
- if (rc == NGX_OK) { /* no the same request, there's free slot */
- return NGX_OK;
- }
-
- if (rc == NGX_ERROR && !lock) { /* no the same request, no free slot */
- return NGX_OK;
- }
-
- /* rc == NGX_AGAIN: the same request */
-
- if (bc->time) {
- if (bc->time < bl->timeout) {
- ngx_add_timer(bc->event, 1000);
- return NGX_AGAIN;
- }
-
- bl->waiting--;
- return NGX_DONE;
-
- }
-
- if (bl->timeout == 0) {
- return NGX_DONE;
- }
-
- if (bl->waiting < bl->max_waiting) {
-#if 0
- bl->waiting++;
- ngx_add_timer(bc->event, 1000);
- bc->event->event_handler = bc->event_handler;
-#endif
-
- /* TODO: ngx_handle_level_read_event() */
-
- return NGX_AGAIN;
- }
-
- return NGX_ERROR;
-}
-
-
-void ngx_http_busy_unlock(ngx_http_busy_lock_t *bl,
- ngx_http_busy_lock_ctx_t *bc)
-{
- if (bl == NULL) {
- return;
- }
-
- if (bl->md5) {
- bl->md5_mask[bc->slot / 8] &= ~(1 << (bc->slot & 7));
- bl->cacheable--;
- }
-
- bl->busy--;
-}
-
-
-static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl,
- ngx_http_busy_lock_ctx_t *bc,
- int lock)
-{
- int i, b, cacheable, free;
- u_int mask;
-
- b = 0;
- cacheable = 0;
- free = -1;
-
-#if (NGX_SUPPRESS_WARN)
- mask = 0;
-#endif
-
- for (i = 0; i < bl->max_busy; i++) {
-
- if ((b & 7) == 0) {
- mask = bl->md5_mask[i / 8];
- }
-
- if (mask & 1) {
- if (ngx_memcmp(&bl->md5[i * 16], bc->md5, 16) == 0) {
- return NGX_AGAIN;
- }
- cacheable++;
-
- } else if (free == -1) {
- free = i;
- }
-
-#if 1
- if (cacheable == bl->cacheable) {
- if (free == -1 && cacheable < bl->max_busy) {
- free = i + 1;
- }
-
- break;
- }
-#endif
-
- mask >>= 1;
- b++;
- }
-
- if (free == -1) {
- return NGX_ERROR;
- }
-
- if (lock) {
- if (bl->busy == bl->max_busy) {
- return NGX_ERROR;
- }
-
- ngx_memcpy(&bl->md5[free * 16], bc->md5, 16);
- bl->md5_mask[free / 8] |= 1 << (free & 7);
- bc->slot = free;
-
- bl->cacheable++;
- bl->busy++;
- }
-
- return NGX_OK;
-}
-
-
-char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
- void *conf)
-{
- char *p = conf;
-
- ngx_uint_t i, dup, invalid;
- ngx_str_t *value, line;
- ngx_http_busy_lock_t *bl, **blp;
-
- blp = (ngx_http_busy_lock_t **) (p + cmd->offset);
- if (*blp) {
- return "is duplicate";
- }
-
- /* ngx_calloc_shared() */
- bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t));
- if (bl == NULL) {
- return NGX_CONF_ERROR;
- }
- *blp = bl;
-
- /* ngx_calloc_shared() */
- bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t));
- if (bl->mutex == NULL) {
- return NGX_CONF_ERROR;
- }
-
- dup = 0;
- invalid = 0;
- value = cf->args->elts;
-
- for (i = 1; i < cf->args->nelts; i++) {
-
- if (value[i].data[1] != '=') {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid value \"%s\"", value[i].data);
- return NGX_CONF_ERROR;
- }
-
- switch (value[i].data[0]) {
-
- case 'b':
- if (bl->max_busy) {
- dup = 1;
- break;
- }
-
- bl->max_busy = ngx_atoi(value[i].data + 2, value[i].len - 2);
- if (bl->max_busy == NGX_ERROR) {
- invalid = 1;
- break;
- }
-
- continue;
-
- case 'w':
- if (bl->max_waiting) {
- dup = 1;
- break;
- }
-
- bl->max_waiting = ngx_atoi(value[i].data + 2, value[i].len - 2);
- if (bl->max_waiting == NGX_ERROR) {
- invalid = 1;
- break;
- }
-
- continue;
-
- case 't':
- if (bl->timeout) {
- dup = 1;
- break;
- }
-
- line.len = value[i].len - 2;
- line.data = value[i].data + 2;
-
- bl->timeout = ngx_parse_time(&line, 1);
- if (bl->timeout == (time_t) NGX_ERROR) {
- invalid = 1;
- break;
- }
-
- continue;
-
- default:
- invalid = 1;
- }
-
- if (dup) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "duplicate value \"%s\"", value[i].data);
- return NGX_CONF_ERROR;
- }
-
- if (invalid) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid value \"%s\"", value[i].data);
- return NGX_CONF_ERROR;
- }
- }
-
- if (bl->timeout == 0 && bl->max_waiting) {
- ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "busy lock waiting is useless with zero timeout, ignoring");
- }
-
- return NGX_CONF_OK;
-}
diff --git a/src/http/ngx_http_busy_lock.h b/src/http/ngx_http_busy_lock.h
deleted file mode 100644
index c676382f2..000000000
--- a/src/http/ngx_http_busy_lock.h
+++ /dev/null
@@ -1,54 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
- */
-
-
-#ifndef _NGX_HTTP_BUSY_LOCK_H_INCLUDED_
-#define _NGX_HTTP_BUSY_LOCK_H_INCLUDED_
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_event.h>
-#include <ngx_http.h>
-
-
-typedef struct {
- u_char *md5_mask;
- char *md5;
- int cacheable;
-
- int busy;
- int max_busy;
-
- int waiting;
- int max_waiting;
-
- time_t timeout;
-
- ngx_event_mutex_t *mutex;
-} ngx_http_busy_lock_t;
-
-
-typedef struct {
- time_t time;
- ngx_event_t *event;
- void (*event_handler)(ngx_event_t *ev);
- u_char *md5;
- int slot;
-} ngx_http_busy_lock_ctx_t;
-
-
-int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc);
-int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl,
- ngx_http_busy_lock_ctx_t *bc, int lock);
-void ngx_http_busy_unlock(ngx_http_busy_lock_t *bl,
- ngx_http_busy_lock_ctx_t *bc);
-
-char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
- void *conf);
-
-
-#endif /* _NGX_HTTP_BUSY_LOCK_H_INCLUDED_ */
diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c
index 3ad27b042..0f908add7 100644
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -20,9 +20,15 @@ static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx,
ngx_file_t *file);
static void ngx_http_copy_aio_event_handler(ngx_event_t *ev);
#if (NGX_HAVE_AIO_SENDFILE)
+static ssize_t ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file);
static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev);
#endif
#endif
+#if (NGX_THREADS)
+static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task,
+ ngx_file_t *file);
+static void ngx_http_copy_thread_event_handler(ngx_event_t *ev);
+#endif
static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf);
static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf,
@@ -120,91 +126,42 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
ctx->filter_ctx = r;
#if (NGX_HAVE_FILE_AIO)
- if (ngx_file_aio) {
- if (clcf->aio) {
- ctx->aio_handler = ngx_http_copy_aio_handler;
- }
+ if (ngx_file_aio && clcf->aio == NGX_HTTP_AIO_ON) {
+ ctx->aio_handler = ngx_http_copy_aio_handler;
#if (NGX_HAVE_AIO_SENDFILE)
- c->aio_sendfile = (clcf->aio == NGX_HTTP_AIO_SENDFILE);
+ ctx->aio_preload = ngx_http_copy_aio_sendfile_preload;
#endif
}
#endif
+#if (NGX_THREADS)
+ if (clcf->aio == NGX_HTTP_AIO_THREADS) {
+ ctx->thread_handler = ngx_http_copy_thread_handler;
+ }
+#endif
+
if (in && in->buf && ngx_buf_size(in->buf)) {
r->request_output = 1;
}
}
-#if (NGX_HAVE_FILE_AIO)
+#if (NGX_HAVE_FILE_AIO || NGX_THREADS)
ctx->aio = r->aio;
#endif
- for ( ;; ) {
- rc = ngx_output_chain(ctx, in);
-
- if (ctx->in == NULL) {
- r->buffered &= ~NGX_HTTP_COPY_BUFFERED;
-
- } else {
- r->buffered |= NGX_HTTP_COPY_BUFFERED;
- }
-
- ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
- "http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);
-
-#if (NGX_HAVE_FILE_AIO && NGX_HAVE_AIO_SENDFILE)
-
- if (c->busy_sendfile) {
- ssize_t n;
- off_t offset;
- ngx_file_t *file;
- ngx_http_ephemeral_t *e;
-
- if (r->aio) {
- c->busy_sendfile = NULL;
- return rc;
- }
-
- file = c->busy_sendfile->file;
- offset = c->busy_sendfile->file_pos;
-
- if (file->aio) {
- c->busy_count = (offset == file->aio->last_offset) ?
- c->busy_count + 1 : 0;
- file->aio->last_offset = offset;
-
- if (c->busy_count > 2) {
- ngx_log_error(NGX_LOG_ALERT, c->log, 0,
- "sendfile(%V) returned busy again",
- &file->name);
- c->aio_sendfile = 0;
- }
- }
-
- c->busy_sendfile = NULL;
- e = (ngx_http_ephemeral_t *) &r->uri_start;
-
- n = ngx_file_aio_read(file, &e->aio_preload, 1, offset, r->pool);
+ rc = ngx_output_chain(ctx, in);
- if (n > 0) {
- in = NULL;
- continue;
- }
+ if (ctx->in == NULL) {
+ r->buffered &= ~NGX_HTTP_COPY_BUFFERED;
- rc = n;
+ } else {
+ r->buffered |= NGX_HTTP_COPY_BUFFERED;
+ }
- if (rc == NGX_AGAIN) {
- file->aio->data = r;
- file->aio->handler = ngx_http_copy_aio_sendfile_event_handler;
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);
- r->main->blocked++;
- r->aio = 1;
- }
- }
-#endif
-
- return rc;
- }
+ return rc;
}
@@ -244,6 +201,29 @@ ngx_http_copy_aio_event_handler(ngx_event_t *ev)
#if (NGX_HAVE_AIO_SENDFILE)
+static ssize_t
+ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file)
+{
+ ssize_t n;
+ static u_char buf[1];
+ ngx_event_aio_t *aio;
+ ngx_http_request_t *r;
+
+ n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL);
+
+ if (n == NGX_AGAIN) {
+ aio = file->file->aio;
+ aio->handler = ngx_http_copy_aio_sendfile_event_handler;
+
+ r = aio->data;
+ r->main->blocked++;
+ r->aio = 1;
+ }
+
+ return n;
+}
+
+
static void
ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev)
{
@@ -264,6 +244,67 @@ ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev)
#endif
+#if (NGX_THREADS)
+
+static ngx_int_t
+ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file)
+{
+ ngx_str_t name;
+ ngx_thread_pool_t *tp;
+ ngx_http_request_t *r;
+ ngx_http_core_loc_conf_t *clcf;
+
+ r = file->thread_ctx;
+
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+ tp = clcf->thread_pool;
+
+ if (tp == NULL) {
+ if (ngx_http_complex_value(r, clcf->thread_pool_value, &name)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ tp = ngx_thread_pool_get((ngx_cycle_t *) ngx_cycle, &name);
+
+ if (tp == NULL) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "thread pool \"%V\" not found", &name);
+ return NGX_ERROR;
+ }
+ }
+
+ task->event.data = r;
+ task->event.handler = ngx_http_copy_thread_event_handler;
+
+ if (ngx_thread_task_post(tp, task) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ r->main->blocked++;
+ r->aio = 1;
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_http_copy_thread_event_handler(ngx_event_t *ev)
+{
+ ngx_http_request_t *r;
+
+ r = ev->data;
+
+ r->main->blocked--;
+ r->aio = 0;
+
+ r->connection->write->handler(r->connection->write);
+}
+
+#endif
+
+
static void *
ngx_http_copy_filter_create_conf(ngx_conf_t *cf)
{
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 0542b2871..096a561c4 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -26,6 +26,7 @@ static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r,
ngx_http_location_tree_node_t *node);
static ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf);
+static ngx_int_t ngx_http_core_postconfiguration(ngx_conf_t *cf);
static void *ngx_http_core_create_main_conf(ngx_conf_t *cf);
static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf);
static void *ngx_http_core_create_srv_conf(ngx_conf_t *cf);
@@ -54,6 +55,8 @@ static char *ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd,
static char *ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_core_set_aio(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static char *ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -114,20 +117,6 @@ static ngx_conf_enum_t ngx_http_core_request_body_in_file[] = {
};
-#if (NGX_HAVE_FILE_AIO)
-
-static ngx_conf_enum_t ngx_http_core_aio[] = {
- { ngx_string("off"), NGX_HTTP_AIO_OFF },
- { ngx_string("on"), NGX_HTTP_AIO_ON },
-#if (NGX_HAVE_AIO_SENDFILE)
- { ngx_string("sendfile"), NGX_HTTP_AIO_SENDFILE },
-#endif
- { ngx_null_string, 0 }
-};
-
-#endif
-
-
static ngx_conf_enum_t ngx_http_core_satisfy[] = {
{ ngx_string("all"), NGX_HTTP_SATISFY_ALL },
{ ngx_string("any"), NGX_HTTP_SATISFY_ANY },
@@ -423,16 +412,12 @@ static ngx_command_t ngx_http_core_commands[] = {
offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk),
NULL },
-#if (NGX_HAVE_FILE_AIO)
-
{ ngx_string("aio"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_enum_slot,
+ ngx_http_core_set_aio,
NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_core_loc_conf_t, aio),
- &ngx_http_core_aio },
-
-#endif
+ 0,
+ NULL },
{ ngx_string("read_ahead"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
@@ -795,7 +780,7 @@ static ngx_command_t ngx_http_core_commands[] = {
static ngx_http_module_t ngx_http_core_module_ctx = {
ngx_http_core_preconfiguration, /* preconfiguration */
- NULL, /* postconfiguration */
+ ngx_http_core_postconfiguration, /* postconfiguration */
ngx_http_core_create_main_conf, /* create main configuration */
ngx_http_core_init_main_conf, /* init main configuration */
@@ -3436,6 +3421,15 @@ ngx_http_core_preconfiguration(ngx_conf_t *cf)
}
+static ngx_int_t
+ngx_http_core_postconfiguration(ngx_conf_t *cf)
+{
+ ngx_http_top_request_body_filter = ngx_http_request_body_save_filter;
+
+ return NGX_OK;
+}
+
+
static void *
ngx_http_core_create_main_conf(ngx_conf_t *cf)
{
@@ -3639,8 +3633,10 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
clcf->internal = NGX_CONF_UNSET;
clcf->sendfile = NGX_CONF_UNSET;
clcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE;
-#if (NGX_HAVE_FILE_AIO)
clcf->aio = NGX_CONF_UNSET;
+#if (NGX_THREADS)
+ clcf->thread_pool = NGX_CONF_UNSET_PTR;
+ clcf->thread_pool_value = NGX_CONF_UNSET_PTR;
#endif
clcf->read_ahead = NGX_CONF_UNSET_SIZE;
clcf->directio = NGX_CONF_UNSET;
@@ -3857,9 +3853,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
ngx_conf_merge_size_value(conf->sendfile_max_chunk,
prev->sendfile_max_chunk, 0);
-#if (NGX_HAVE_FILE_AIO)
+#if (NGX_HAVE_FILE_AIO || NGX_THREADS)
ngx_conf_merge_value(conf->aio, prev->aio, NGX_HTTP_AIO_OFF);
#endif
+#if (NGX_THREADS)
+ ngx_conf_merge_ptr_value(conf->thread_pool, prev->thread_pool, NULL);
+ ngx_conf_merge_ptr_value(conf->thread_pool_value, prev->thread_pool_value,
+ NULL);
+#endif
ngx_conf_merge_size_value(conf->read_ahead, prev->read_ahead, 0);
ngx_conf_merge_off_value(conf->directio, prev->directio,
NGX_OPEN_FILE_DIRECTIO_OFF);
@@ -4654,6 +4655,116 @@ ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
static char *
+ngx_http_core_set_aio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_core_loc_conf_t *clcf = conf;
+
+ ngx_str_t *value;
+
+ if (clcf->aio != NGX_CONF_UNSET) {
+ return "is duplicate";
+ }
+
+#if (NGX_THREADS)
+ clcf->thread_pool = NULL;
+ clcf->thread_pool_value = NULL;
+#endif
+
+ value = cf->args->elts;
+
+ if (ngx_strcmp(value[1].data, "off") == 0) {
+ clcf->aio = NGX_HTTP_AIO_OFF;
+ return NGX_CONF_OK;
+ }
+
+ if (ngx_strcmp(value[1].data, "on") == 0) {
+#if (NGX_HAVE_FILE_AIO)
+ clcf->aio = NGX_HTTP_AIO_ON;
+ return NGX_CONF_OK;
+#else
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"aio on\" "
+ "is unsupported on this platform");
+ return NGX_CONF_ERROR;
+#endif
+ }
+
+#if (NGX_HAVE_AIO_SENDFILE)
+
+ if (ngx_strcmp(value[1].data, "sendfile") == 0) {
+ clcf->aio = NGX_HTTP_AIO_ON;
+
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "the \"sendfile\" parameter of "
+ "the \"aio\" directive is deprecated");
+ return NGX_CONF_OK;
+ }
+
+#endif
+
+ if (ngx_strncmp(value[1].data, "threads", 7) == 0
+ && (value[1].len == 7 || value[1].data[7] == '='))
+ {
+#if (NGX_THREADS)
+ ngx_str_t name;
+ ngx_thread_pool_t *tp;
+ ngx_http_complex_value_t cv;
+ ngx_http_compile_complex_value_t ccv;
+
+ clcf->aio = NGX_HTTP_AIO_THREADS;
+
+ if (value[1].len >= 8) {
+ name.len = value[1].len - 8;
+ name.data = value[1].data + 8;
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &name;
+ ccv.complex_value = &cv;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (cv.lengths != NULL) {
+ clcf->thread_pool_value = ngx_palloc(cf->pool,
+ sizeof(ngx_http_complex_value_t));
+ if (clcf->thread_pool_value == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ *clcf->thread_pool_value = cv;
+
+ return NGX_CONF_OK;
+ }
+
+ tp = ngx_thread_pool_add(cf, &name);
+
+ } else {
+ tp = ngx_thread_pool_add(cf, NULL);
+ }
+
+ if (tp == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ clcf->thread_pool = tp;
+
+ return NGX_CONF_OK;
+#else
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"aio threads\" "
+ "is unsupported on this platform");
+ return NGX_CONF_ERROR;
+#endif
+ }
+
+ return "invalid value";
+}
+
+
+static char *
ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf = conf;
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index fc2c3d49b..e0ca2ce47 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -13,6 +13,10 @@
#include <ngx_core.h>
#include <ngx_http.h>
+#if (NGX_THREADS)
+#include <ngx_thread_pool.h>
+#endif
+
#define NGX_HTTP_GZIP_PROXIED_OFF 0x0002
#define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004
@@ -27,7 +31,7 @@
#define NGX_HTTP_AIO_OFF 0
#define NGX_HTTP_AIO_ON 1
-#define NGX_HTTP_AIO_SENDFILE 2
+#define NGX_HTTP_AIO_THREADS 2
#define NGX_HTTP_SATISFY_ALL 0
@@ -396,9 +400,7 @@ struct ngx_http_core_loc_conf_s {
/* client_body_in_singe_buffer */
ngx_flag_t internal; /* internal */
ngx_flag_t sendfile; /* sendfile */
-#if (NGX_HAVE_FILE_AIO)
ngx_flag_t aio; /* aio */
-#endif
ngx_flag_t tcp_nopush; /* tcp_nopush */
ngx_flag_t tcp_nodelay; /* tcp_nodelay */
ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */
@@ -424,6 +426,11 @@ struct ngx_http_core_loc_conf_s {
#endif
#endif
+#if (NGX_THREADS)
+ ngx_thread_pool_t *thread_pool;
+ ngx_http_complex_value_t *thread_pool_value;
+#endif
+
#if (NGX_HAVE_OPENAT)
ngx_uint_t disable_symlinks; /* disable_symlinks */
ngx_http_complex_value_t *disable_symlinks_from;
@@ -526,10 +533,14 @@ ngx_http_cleanup_t *ngx_http_cleanup_add(ngx_http_request_t *r, size_t size);
typedef ngx_int_t (*ngx_http_output_header_filter_pt)(ngx_http_request_t *r);
typedef ngx_int_t (*ngx_http_output_body_filter_pt)
(ngx_http_request_t *r, ngx_chain_t *chain);
+typedef ngx_int_t (*ngx_http_request_body_filter_pt)
+ (ngx_http_request_t *r, ngx_chain_t *chain);
ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *chain);
ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *chain);
+ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r,
+ ngx_chain_t *chain);
ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r,
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 00d4c0f5a..52cbdda83 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -181,8 +181,6 @@ ngx_http_file_cache_new(ngx_http_request_t *r)
c->file.log = r->connection->log;
c->file.fd = NGX_INVALID_FILE;
- c->last_modified = -1;
-
return NGX_OK;
}
@@ -258,7 +256,7 @@ ngx_int_t
ngx_http_file_cache_open(ngx_http_request_t *r)
{
ngx_int_t rc, rv;
- ngx_uint_t cold, test;
+ ngx_uint_t test;
ngx_http_cache_t *c;
ngx_pool_cleanup_t *cln;
ngx_open_file_info_t of;
@@ -300,8 +298,6 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
return NGX_HTTP_CACHE_SCARCE;
}
- cold = cache->sh->cold;
-
if (rc == NGX_OK) {
if (c->error) {
@@ -314,18 +310,18 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
} else { /* rc == NGX_DECLINED */
+ test = cache->sh->cold ? 1 : 0;
+
if (c->min_uses > 1) {
- if (!cold) {
+ if (!test) {
return NGX_HTTP_CACHE_SCARCE;
}
- test = 1;
rv = NGX_HTTP_CACHE_SCARCE;
} else {
c->temp_file = 1;
- test = cold ? 1 : 0;
rv = NGX_DECLINED;
}
}
@@ -650,7 +646,7 @@ ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c)
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
- if (!clcf->aio) {
+ if (clcf->aio != NGX_HTTP_AIO_ON) {
goto noaio;
}
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index b60f41bb6..0e0b3a237 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -2155,6 +2155,10 @@ ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
goto invalid;
case sw_chunk_size:
+ if (ctx->size > NGX_MAX_OFF_T_VALUE / 16) {
+ goto invalid;
+ }
+
if (ch >= '0' && ch <= '9') {
ctx->size = ctx->size * 16 + (ch - '0');
break;
@@ -2304,6 +2308,10 @@ data:
ctx->state = state;
b->pos = pos;
+ if (ctx->size > NGX_MAX_OFF_T_VALUE - 5) {
+ goto invalid;
+ }
+
switch (state) {
case sw_chunk_start:
@@ -2340,10 +2348,6 @@ data:
}
- if (ctx->size < 0 || ctx->length < 0) {
- goto invalid;
- }
-
return rc;
done:
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index a07d5e47f..9f98799a1 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -652,6 +652,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
if (n == -1) {
if (err == NGX_EAGAIN) {
+ rev->ready = 0;
if (!rev->timer_set) {
ngx_add_timer(rev, c->listening->post_accept_timeout);
@@ -2524,6 +2525,11 @@ ngx_http_finalize_connection(ngx_http_request_t *r)
return;
}
+ if (r->reading_body) {
+ r->keepalive = 0;
+ r->lingering_close = 1;
+ }
+
if (!ngx_terminate
&& !ngx_exiting
&& r->keepalive
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index cffab9a69..ead4d236f 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -473,6 +473,7 @@ struct ngx_http_request_s {
unsigned request_body_in_clean_file:1;
unsigned request_body_file_group_access:1;
unsigned request_body_file_log_level:3;
+ unsigned request_body_no_buffering:1;
unsigned subrequest_in_memory:1;
unsigned waited:1;
@@ -509,6 +510,7 @@ struct ngx_http_request_s {
unsigned keepalive:1;
unsigned lingering_close:1;
unsigned discard_body:1;
+ unsigned reading_body:1;
unsigned internal:1;
unsigned error_page:1;
unsigned filter_finalize:1;
@@ -574,12 +576,12 @@ struct ngx_http_request_s {
typedef struct {
ngx_http_posted_request_t terminal_posted_request;
-#if (NGX_HAVE_AIO_SENDFILE)
- u_char aio_preload;
-#endif
} ngx_http_ephemeral_t;
+#define ngx_http_ephemeral(r) (void *) (&r->uri_start)
+
+
extern ngx_http_header_t ngx_http_headers_in[];
extern ngx_http_header_out_t ngx_http_headers_out[];
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index bbf16fd25..ac5b530ba 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -24,8 +24,6 @@ static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r,
ngx_chain_t *in);
static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r,
ngx_chain_t *in);
-static ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r,
- ngx_chain_t *in);
ngx_int_t
@@ -44,12 +42,14 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
#if (NGX_HTTP_SPDY)
if (r->spdy_stream && r == r->main) {
+ r->request_body_no_buffering = 0;
rc = ngx_http_spdy_read_request_body(r, post_handler);
goto done;
}
#endif
if (r != r->main || r->request_body || r->discard_body) {
+ r->request_body_no_buffering = 0;
post_handler(r);
return NGX_OK;
}
@@ -59,6 +59,10 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
goto done;
}
+ if (r->request_body_no_buffering) {
+ r->request_body_in_file_only = 0;
+ }
+
rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
if (rb == NULL) {
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -81,6 +85,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
r->request_body = rb;
if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
+ r->request_body_no_buffering = 0;
post_handler(r);
return NGX_OK;
}
@@ -173,6 +178,8 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
}
}
+ r->request_body_no_buffering = 0;
+
post_handler(r);
return NGX_OK;
@@ -216,6 +223,21 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
done:
+ if (r->request_body_no_buffering
+ && (rc == NGX_OK || rc == NGX_AGAIN))
+ {
+ if (rc == NGX_OK) {
+ r->request_body_no_buffering = 0;
+
+ } else {
+ /* rc == NGX_AGAIN */
+ r->reading_body = 1;
+ }
+
+ r->read_event_handler = ngx_http_block_reading;
+ post_handler(r);
+ }
+
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
r->main->count--;
}
@@ -224,6 +246,26 @@ done:
}
+ngx_int_t
+ngx_http_read_unbuffered_request_body(ngx_http_request_t *r)
+{
+ ngx_int_t rc;
+
+ if (r->connection->read->timedout) {
+ r->connection->timedout = 1;
+ return NGX_HTTP_REQUEST_TIME_OUT;
+ }
+
+ rc = ngx_http_do_read_client_request_body(r);
+
+ if (rc == NGX_OK) {
+ r->reading_body = 0;
+ }
+
+ return rc;
+}
+
+
static void
ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
{
@@ -266,32 +308,43 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
for ( ;; ) {
if (rb->buf->last == rb->buf->end) {
- /* pass buffer to request body filter chain */
+ if (rb->buf->pos != rb->buf->last) {
- out.buf = rb->buf;
- out.next = NULL;
+ /* pass buffer to request body filter chain */
- rc = ngx_http_request_body_filter(r, &out);
+ out.buf = rb->buf;
+ out.next = NULL;
- if (rc != NGX_OK) {
- return rc;
- }
+ rc = ngx_http_request_body_filter(r, &out);
- /* write to file */
+ if (rc != NGX_OK) {
+ return rc;
+ }
- if (ngx_http_write_request_body(r) != NGX_OK) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
+ } else {
- /* update chains */
+ /* update chains */
- rc = ngx_http_request_body_filter(r, NULL);
+ rc = ngx_http_request_body_filter(r, NULL);
- if (rc != NGX_OK) {
- return rc;
+ if (rc != NGX_OK) {
+ return rc;
+ }
}
if (rb->busy != NULL) {
+ if (r->request_body_no_buffering) {
+ if (c->read->timer_set) {
+ ngx_del_timer(c->read);
+ }
+
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ return NGX_AGAIN;
+ }
+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -358,6 +411,22 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
}
if (!c->read->ready) {
+
+ if (r->request_body_no_buffering
+ && rb->buf->pos != rb->buf->last)
+ {
+ /* pass buffer to request body filter chain */
+
+ out.buf = rb->buf;
+ out.next = NULL;
+
+ rc = ngx_http_request_body_filter(r, &out);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+ }
+
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_add_timer(c->read, clcf->client_body_timeout);
@@ -403,9 +472,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
}
}
- r->read_event_handler = ngx_http_block_reading;
-
- rb->post_handler(r);
+ if (!r->request_body_no_buffering) {
+ r->read_event_handler = ngx_http_block_reading;
+ rb->post_handler(r);
+ }
return NGX_OK;
}
@@ -415,7 +485,7 @@ static ngx_int_t
ngx_http_write_request_body(ngx_http_request_t *r)
{
ssize_t n;
- ngx_chain_t *cl;
+ ngx_chain_t *cl, *ln;
ngx_temp_file_t *tf;
ngx_http_request_body_t *rb;
ngx_http_core_loc_conf_t *clcf;
@@ -478,8 +548,13 @@ ngx_http_write_request_body(ngx_http_request_t *r)
/* mark all buffers as written */
- for (cl = rb->bufs; cl; cl = cl->next) {
+ for (cl = rb->bufs; cl; /* void */) {
+
cl->buf->pos = cl->buf->last;
+
+ ln = cl;
+ cl = cl->next;
+ ngx_free_chain(r->pool, ln);
}
rb->bufs = NULL;
@@ -892,7 +967,7 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
ll = &tl->next;
}
- rc = ngx_http_request_body_save_filter(r, out);
+ rc = ngx_http_top_request_body_filter(r, out);
ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
(ngx_buf_tag_t) &ngx_http_read_client_request_body);
@@ -936,7 +1011,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
"http body chunked buf "
- "t:%d f:%d %p, pos %p, size: %z file: %O, size: %z",
+ "t:%d f:%d %p, pos %p, size: %z file: %O, size: %O",
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
cl->buf->last - cl->buf->pos,
@@ -1044,7 +1119,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
}
}
- rc = ngx_http_request_body_save_filter(r, out);
+ rc = ngx_http_top_request_body_filter(r, out);
ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
(ngx_buf_tag_t) &ngx_http_read_client_request_body);
@@ -1053,7 +1128,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
}
-static ngx_int_t
+ngx_int_t
ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
#if (NGX_DEBUG)
@@ -1068,7 +1143,7 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
for (cl = rb->bufs; cl; cl = cl->next) {
ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
"http body old buf t:%d f:%d %p, pos %p, size: %z "
- "file: %O, size: %z",
+ "file: %O, size: %O",
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
cl->buf->last - cl->buf->pos,
@@ -1079,7 +1154,7 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
for (cl = in; cl; cl = cl->next) {
ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
"http body new buf t:%d f:%d %p, pos %p, size: %z "
- "file: %O, size: %z",
+ "file: %O, size: %O",
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
cl->buf->last - cl->buf->pos,
@@ -1095,5 +1170,14 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
+ if (rb->rest > 0
+ && rb->buf && rb->buf->last == rb->buf->end
+ && !r->request_body_no_buffering)
+ {
+ if (ngx_http_write_request_body(r) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+
return NGX_OK;
}
diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c
index 6eac9326a..13b81a63a 100644
--- a/src/http/ngx_http_spdy.c
+++ b/src/http/ngx_http_spdy.c
@@ -1353,7 +1353,7 @@ ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos,
pos += NGX_SPDY_DELTA_SIZE;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy WINDOW_UPDATE sid:%ui delta:%ui", sid, delta);
+ "spdy WINDOW_UPDATE sid:%ui delta:%uz", sid, delta);
if (sid) {
stream = ngx_http_spdy_get_stream_by_id(sc, sid);
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index a41d5b377..0a04e611c 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -36,9 +36,12 @@ static void ngx_http_upstream_connect(ngx_http_request_t *r,
static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_send_request(ngx_http_request_t *r,
- ngx_http_upstream_t *u);
+ ngx_http_upstream_t *u, ngx_uint_t do_write);
+static ngx_int_t ngx_http_upstream_send_request_body(ngx_http_request_t *r,
+ ngx_http_upstream_t *u, ngx_uint_t do_write);
static void ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
ngx_http_upstream_t *u);
+static void ngx_http_upstream_read_request_handler(ngx_http_request_t *r);
static void ngx_http_upstream_process_header(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r,
@@ -76,7 +79,8 @@ static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
static void ngx_http_upstream_process_downstream(ngx_http_request_t *r);
static void ngx_http_upstream_process_upstream(ngx_http_request_t *r,
ngx_http_upstream_t *u);
-static void ngx_http_upstream_process_request(ngx_http_request_t *r);
+static void ngx_http_upstream_process_request(ngx_http_request_t *r,
+ ngx_http_upstream_t *u);
static void ngx_http_upstream_store(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_dummy_handler(ngx_http_request_t *r,
@@ -445,9 +449,6 @@ ngx_http_upstream_create(ngx_http_request_t *r)
u->peer.log = r->connection->log;
u->peer.log_error = NGX_ERROR_ERR;
-#if (NGX_THREADS)
- u->peer.lock = &r->connection->lock;
-#endif
#if (NGX_HTTP_CACHE)
r->cache = NULL;
@@ -570,8 +571,11 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)
u->output.pool = r->pool;
u->output.bufs.num = 1;
u->output.bufs.size = clcf->client_body_buffer_size;
- u->output.output_filter = ngx_chain_writer;
- u->output.filter_ctx = &u->writer;
+
+ if (u->output.output_filter == NULL) {
+ u->output.output_filter = ngx_chain_writer;
+ u->output.filter_ctx = &u->writer;
+ }
u->writer.pool = r->pool;
@@ -1434,7 +1438,7 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
#endif
- ngx_http_upstream_send_request(r, u);
+ ngx_http_upstream_send_request(r, u, 1);
}
@@ -1538,7 +1542,7 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
c = r->connection;
- ngx_http_upstream_send_request(r, u);
+ ngx_http_upstream_send_request(r, u, 1);
ngx_http_run_posted_requests(c);
return;
@@ -1726,7 +1730,8 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
static void
-ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
+ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u,
+ ngx_uint_t do_write)
{
ngx_int_t rc;
ngx_connection_t *c;
@@ -1743,21 +1748,25 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
c->log->action = "sending request to upstream";
- rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs);
-
- u->request_sent = 1;
+ rc = ngx_http_upstream_send_request_body(r, u, do_write);
if (rc == NGX_ERROR) {
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
return;
}
- if (c->write->timer_set) {
- ngx_del_timer(c->write);
+ if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+ ngx_http_upstream_finalize_request(r, u, rc);
+ return;
}
if (rc == NGX_AGAIN) {
- ngx_add_timer(c->write, u->conf->send_timeout);
+ if (!c->write->ready) {
+ ngx_add_timer(c->write, u->conf->send_timeout);
+
+ } else if (c->write->timer_set) {
+ ngx_del_timer(c->write);
+ }
if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
@@ -1770,6 +1779,10 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
/* rc == NGX_OK */
+ if (c->write->timer_set) {
+ ngx_del_timer(c->write);
+ }
+
if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
if (ngx_tcp_push(c->fd) == NGX_ERROR) {
ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
@@ -1799,6 +1812,123 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
}
+static ngx_int_t
+ngx_http_upstream_send_request_body(ngx_http_request_t *r,
+ ngx_http_upstream_t *u, ngx_uint_t do_write)
+{
+ int tcp_nodelay;
+ ngx_int_t rc;
+ ngx_chain_t *out, *cl, *ln;
+ ngx_connection_t *c;
+ ngx_http_core_loc_conf_t *clcf;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http upstream send request body");
+
+ if (!r->request_body_no_buffering) {
+
+ /* buffered request body */
+
+ if (!u->request_sent) {
+ u->request_sent = 1;
+ out = u->request_bufs;
+
+ } else {
+ out = NULL;
+ }
+
+ return ngx_output_chain(&u->output, out);
+ }
+
+ if (!u->request_sent) {
+ u->request_sent = 1;
+ out = u->request_bufs;
+
+ if (r->request_body->bufs) {
+ for (cl = out; cl->next; cl = out->next) { /* void */ }
+ cl->next = r->request_body->bufs;
+ r->request_body->bufs = NULL;
+ }
+
+ c = u->peer.connection;
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
+
+ tcp_nodelay = 1;
+
+ if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
+ (const void *) &tcp_nodelay, sizeof(int)) == -1)
+ {
+ ngx_connection_error(c, ngx_socket_errno,
+ "setsockopt(TCP_NODELAY) failed");
+ return NGX_ERROR;
+ }
+
+ c->tcp_nodelay = NGX_TCP_NODELAY_SET;
+ }
+
+ r->read_event_handler = ngx_http_upstream_read_request_handler;
+
+ } else {
+ out = NULL;
+ }
+
+ for ( ;; ) {
+
+ if (do_write) {
+ rc = ngx_output_chain(&u->output, out);
+
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ while (out) {
+ ln = out;
+ out = out->next;
+ ngx_free_chain(r->pool, ln);
+ }
+
+ if (rc == NGX_OK && !r->reading_body) {
+ break;
+ }
+ }
+
+ if (r->reading_body) {
+ /* read client request body */
+
+ rc = ngx_http_read_unbuffered_request_body(r);
+
+ if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+ return rc;
+ }
+
+ out = r->request_body->bufs;
+ r->request_body->bufs = NULL;
+ }
+
+ /* stop if there is nothing to send */
+
+ if (out == NULL) {
+ rc = NGX_AGAIN;
+ break;
+ }
+
+ do_write = 1;
+ }
+
+ if (!r->reading_body) {
+ if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
+ r->read_event_handler =
+ ngx_http_upstream_rd_check_broken_connection;
+ }
+ }
+
+ return rc;
+}
+
+
static void
ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
ngx_http_upstream_t *u)
@@ -1832,7 +1962,29 @@ ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
return;
}
- ngx_http_upstream_send_request(r, u);
+ ngx_http_upstream_send_request(r, u, 1);
+}
+
+
+static void
+ngx_http_upstream_read_request_handler(ngx_http_request_t *r)
+{
+ ngx_connection_t *c;
+ ngx_http_upstream_t *u;
+
+ c = r->connection;
+ u = r->upstream;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http upstream read request handler");
+
+ if (c->read->timedout) {
+ c->timedout = 1;
+ ngx_http_upstream_finalize_request(r, u, NGX_HTTP_REQUEST_TIME_OUT);
+ return;
+ }
+
+ ngx_http_upstream_send_request(r, u, 0);
}
@@ -2635,7 +2787,14 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
if (u->headers_in.etag) {
r->cache->etag = u->headers_in.etag->value;
+
+ } else {
+ ngx_str_null(&r->cache->etag);
}
+
+ } else {
+ r->cache->last_modified = -1;
+ ngx_str_null(&r->cache->etag);
}
if (ngx_http_file_cache_set_header(r, u->buffer.start) != NGX_OK) {
@@ -3342,7 +3501,7 @@ ngx_http_upstream_process_downstream(ngx_http_request_t *r)
}
}
- ngx_http_upstream_process_request(r);
+ ngx_http_upstream_process_request(r, u);
}
@@ -3410,18 +3569,17 @@ ngx_http_upstream_process_upstream(ngx_http_request_t *r,
}
}
- ngx_http_upstream_process_request(r);
+ ngx_http_upstream_process_request(r, u);
}
static void
-ngx_http_upstream_process_request(ngx_http_request_t *r)
+ngx_http_upstream_process_request(ngx_http_request_t *r,
+ ngx_http_upstream_t *u)
{
- ngx_temp_file_t *tf;
- ngx_event_pipe_t *p;
- ngx_http_upstream_t *u;
+ ngx_temp_file_t *tf;
+ ngx_event_pipe_t *p;
- u = r->upstream;
p = u->pipe;
if (u->peer.connection) {
@@ -3622,7 +3780,9 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
"upstream timed out");
}
- if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
+ if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR
+ && (!u->request_sent || !r->request_body_no_buffering))
+ {
status = 0;
/* TODO: inform balancer instead */
@@ -3670,6 +3830,7 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
if (u->peer.tries == 0
|| !(u->conf->next_upstream & ft_type)
+ || (u->request_sent && r->request_body_no_buffering)
|| (timeout && ngx_current_msec - u->peer.start_time >= timeout))
{
#if (NGX_HTTP_CACHE)
@@ -3744,11 +3905,15 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r,
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"finalize http upstream request: %i", rc);
- if (u->cleanup) {
- *u->cleanup = NULL;
- u->cleanup = NULL;
+ if (u->cleanup == NULL) {
+ /* the request was already finalized */
+ ngx_http_finalize_request(r, NGX_DONE);
+ return;
}
+ *u->cleanup = NULL;
+ u->cleanup = NULL;
+
if (u->resolved && u->resolved->ctx) {
ngx_resolve_name_done(u->resolved->ctx);
u->resolved->ctx = NULL;
@@ -5408,7 +5573,7 @@ ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
uscf->default_port = u->default_port;
uscf->no_port = u->no_port;
- if (u->naddrs == 1) {
+ if (u->naddrs == 1 && (u->port || u->family == AF_UNIX)) {
uscf->servers = ngx_array_create(cf->pool, 1,
sizeof(ngx_http_upstream_server_t));
if (uscf->servers == NULL) {
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index 98d7267b5..895a55966 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -160,6 +160,7 @@ typedef struct {
ngx_uint_t store_access;
ngx_uint_t next_upstream_tries;
ngx_flag_t buffering;
+ ngx_flag_t request_buffering;
ngx_flag_t pass_request_headers;
ngx_flag_t pass_request_body;
diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
index 9db82a63c..3bbba0b37 100644
--- a/src/http/ngx_http_upstream_round_robin.h
+++ b/src/http/ngx_http_upstream_round_robin.h
@@ -44,8 +44,6 @@ typedef struct ngx_http_upstream_rr_peers_s ngx_http_upstream_rr_peers_t;
struct ngx_http_upstream_rr_peers_s {
ngx_uint_t number;
- /* ngx_mutex_t *mutex; */
-
ngx_uint_t total_weight;
unsigned single:1;
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index 738f2237a..c65de358e 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -1081,6 +1081,10 @@ ngx_http_variable_content_length(ngx_http_request_t *r,
v->no_cacheable = 0;
v->not_found = 0;
+ } else if (r->reading_body) {
+ v->not_found = 1;
+ v->no_cacheable = 1;
+
} else if (r->headers_in.content_length_n >= 0) {
p = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
if (p == NULL) {
diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c
index a2db53024..c16444099 100644
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -73,7 +73,7 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
"write old buf t:%d f:%d %p, pos %p, size: %z "
- "file: %O, size: %z",
+ "file: %O, size: %O",
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
cl->buf->last - cl->buf->pos,
@@ -129,7 +129,7 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0,
"write new buf t:%d f:%d %p, pos %p, size: %z "
- "file: %O, size: %z",
+ "file: %O, size: %O",
cl->buf->temporary, cl->buf->in_file,
cl->buf->start, cl->buf->pos,
cl->buf->last - cl->buf->pos,
diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c
index 5a7cb6bf6..bf1b858df 100644
--- a/src/mail/ngx_mail.c
+++ b/src/mail/ngx_mail.c
@@ -98,7 +98,7 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
*(ngx_mail_conf_ctx_t **) conf = ctx;
- /* count the number of the http modules and set up their indices */
+ /* count the number of the mail modules and set up their indices */
ngx_mail_max_module = 0;
for (m = 0; ngx_modules[m]; m++) {
diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h
index dc39f1e13..02261390c 100644
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -336,6 +336,8 @@ struct ngx_mail_protocol_s {
ngx_mail_auth_state_pt auth_state;
ngx_str_t internal_server_error;
+ ngx_str_t cert_error;
+ ngx_str_t no_cert;
};
diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c
index eb7531c80..d93e94644 100644
--- a/src/mail/ngx_mail_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -16,6 +16,7 @@ typedef struct {
ngx_addr_t *peer;
ngx_msec_t timeout;
+ ngx_flag_t pass_client_cert;
ngx_str_t host_header;
ngx_str_t uri;
@@ -106,6 +107,13 @@ static ngx_command_t ngx_mail_auth_http_commands[] = {
0,
NULL },
+ { ngx_string("auth_http_pass_client_cert"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_auth_http_conf_t, pass_client_cert),
+ NULL },
+
ngx_null_command
};
@@ -1143,6 +1151,12 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
size_t len;
ngx_buf_t *b;
ngx_str_t login, passwd;
+#if (NGX_MAIL_SSL)
+ ngx_str_t verify, subject, issuer, serial, fingerprint,
+ raw_cert, cert;
+ ngx_connection_t *c;
+ ngx_mail_ssl_conf_t *sslcf;
+#endif
ngx_mail_core_srv_conf_t *cscf;
if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
@@ -1153,6 +1167,62 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
return NULL;
}
+#if (NGX_MAIL_SSL)
+
+ c = s->connection;
+ sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
+
+ if (c->ssl && sslcf->verify) {
+
+ /* certificate details */
+
+ if (ngx_ssl_get_client_verify(c, pool, &verify) != NGX_OK) {
+ return NULL;
+ }
+
+ if (ngx_ssl_get_subject_dn(c, pool, &subject) != NGX_OK) {
+ return NULL;
+ }
+
+ if (ngx_ssl_get_issuer_dn(c, pool, &issuer) != NGX_OK) {
+ return NULL;
+ }
+
+ if (ngx_ssl_get_serial_number(c, pool, &serial) != NGX_OK) {
+ return NULL;
+ }
+
+ if (ngx_ssl_get_fingerprint(c, pool, &fingerprint) != NGX_OK) {
+ return NULL;
+ }
+
+ if (ahcf->pass_client_cert) {
+
+ /* certificate itself, if configured */
+
+ if (ngx_ssl_get_raw_certificate(c, pool, &raw_cert) != NGX_OK) {
+ return NULL;
+ }
+
+ if (ngx_mail_auth_http_escape(pool, &raw_cert, &cert) != NGX_OK) {
+ return NULL;
+ }
+
+ } else {
+ ngx_str_null(&cert);
+ }
+
+ } else {
+ ngx_str_null(&verify);
+ ngx_str_null(&subject);
+ ngx_str_null(&issuer);
+ ngx_str_null(&serial);
+ ngx_str_null(&fingerprint);
+ ngx_str_null(&cert);
+ }
+
+#endif
+
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
@@ -1170,9 +1240,19 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
+ sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
+ sizeof(CRLF) - 1
+ sizeof("Client-Host: ") - 1 + s->host.len + sizeof(CRLF) - 1
- + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len
- + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len
- + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len
+ + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len + sizeof(CRLF) - 1
+ + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len + sizeof(CRLF) - 1
+ + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len + sizeof(CRLF) - 1
+#if (NGX_MAIL_SSL)
+ + sizeof("Auth-SSL: on" CRLF) - 1
+ + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + sizeof(CRLF) - 1
+ + sizeof("Auth-SSL-Subject: ") - 1 + subject.len + sizeof(CRLF) - 1
+ + sizeof("Auth-SSL-Issuer: ") - 1 + issuer.len + sizeof(CRLF) - 1
+ + sizeof("Auth-SSL-Serial: ") - 1 + serial.len + sizeof(CRLF) - 1
+ + sizeof("Auth-SSL-Fingerprint: ") - 1 + fingerprint.len
+ + sizeof(CRLF) - 1
+ + sizeof("Auth-SSL-Cert: ") - 1 + cert.len + sizeof(CRLF) - 1
+#endif
+ ahcf->header.len
+ sizeof(CRLF) - 1;
@@ -1255,6 +1335,57 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
}
+#if (NGX_MAIL_SSL)
+
+ if (c->ssl) {
+ b->last = ngx_cpymem(b->last, "Auth-SSL: on" CRLF,
+ sizeof("Auth-SSL: on" CRLF) - 1);
+
+ if (verify.len) {
+ b->last = ngx_cpymem(b->last, "Auth-SSL-Verify: ",
+ sizeof("Auth-SSL-Verify: ") - 1);
+ b->last = ngx_copy(b->last, verify.data, verify.len);
+ *b->last++ = CR; *b->last++ = LF;
+ }
+
+ if (subject.len) {
+ b->last = ngx_cpymem(b->last, "Auth-SSL-Subject: ",
+ sizeof("Auth-SSL-Subject: ") - 1);
+ b->last = ngx_copy(b->last, subject.data, subject.len);
+ *b->last++ = CR; *b->last++ = LF;
+ }
+
+ if (issuer.len) {
+ b->last = ngx_cpymem(b->last, "Auth-SSL-Issuer: ",
+ sizeof("Auth-SSL-Issuer: ") - 1);
+ b->last = ngx_copy(b->last, issuer.data, issuer.len);
+ *b->last++ = CR; *b->last++ = LF;
+ }
+
+ if (serial.len) {
+ b->last = ngx_cpymem(b->last, "Auth-SSL-Serial: ",
+ sizeof("Auth-SSL-Serial: ") - 1);
+ b->last = ngx_copy(b->last, serial.data, serial.len);
+ *b->last++ = CR; *b->last++ = LF;
+ }
+
+ if (fingerprint.len) {
+ b->last = ngx_cpymem(b->last, "Auth-SSL-Fingerprint: ",
+ sizeof("Auth-SSL-Fingerprint: ") - 1);
+ b->last = ngx_copy(b->last, fingerprint.data, fingerprint.len);
+ *b->last++ = CR; *b->last++ = LF;
+ }
+
+ if (cert.len) {
+ b->last = ngx_cpymem(b->last, "Auth-SSL-Cert: ",
+ sizeof("Auth-SSL-Cert: ") - 1);
+ b->last = ngx_copy(b->last, cert.data, cert.len);
+ *b->last++ = CR; *b->last++ = LF;
+ }
+ }
+
+#endif
+
if (ahcf->header.len) {
b->last = ngx_copy(b->last, ahcf->header.data, ahcf->header.len);
}
@@ -1263,14 +1394,9 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
*b->last++ = CR; *b->last++ = LF;
#if (NGX_DEBUG_MAIL_PASSWD)
- {
- ngx_str_t l;
-
- l.len = b->last - b->pos;
- l.data = b->pos;
- ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
- "mail auth http header:%N\"%V\"", &l);
- }
+ ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
+ "mail auth http header:%N\"%*s\"",
+ (size_t) (b->last - b->pos), b->pos);
#endif
return b;
@@ -1316,6 +1442,7 @@ ngx_mail_auth_http_create_conf(ngx_conf_t *cf)
}
ahcf->timeout = NGX_CONF_UNSET_MSEC;
+ ahcf->pass_client_cert = NGX_CONF_UNSET;
ahcf->file = cf->conf_file->file.name.data;
ahcf->line = cf->conf_file->line;
@@ -1351,6 +1478,8 @@ ngx_mail_auth_http_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
+ ngx_conf_merge_value(conf->pass_client_cert, prev->pass_client_cert, 0);
+
if (conf->headers == NULL) {
conf->headers = prev->headers;
conf->header = prev->header;
diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c
index a5388c847..05a47f5e3 100644
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_core_module.c
@@ -336,7 +336,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
off = offsetof(struct sockaddr_in6, sin6_addr);
len = 16;
sin6 = (struct sockaddr_in6 *) sa;
- port = sin6->sin6_port;
+ port = ntohs(sin6->sin6_port);
break;
#endif
@@ -352,7 +352,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
off = offsetof(struct sockaddr_in, sin_addr);
len = 4;
sin = (struct sockaddr_in *) sa;
- port = sin->sin_port;
+ port = ntohs(sin->sin_port);
break;
}
diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c
index 57b69b564..870b5eeed 100644
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -16,6 +16,8 @@ static void ngx_mail_init_session(ngx_connection_t *c);
#if (NGX_MAIL_SSL)
static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c);
static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c);
+static ngx_int_t ngx_mail_verify_cert(ngx_mail_session_t *s,
+ ngx_connection_t *c);
#endif
@@ -247,6 +249,10 @@ ngx_mail_ssl_handshake_handler(ngx_connection_t *c)
s = c->data;
+ if (ngx_mail_verify_cert(s, c) != NGX_OK) {
+ return;
+ }
+
if (s->starttls) {
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
@@ -267,6 +273,71 @@ ngx_mail_ssl_handshake_handler(ngx_connection_t *c)
ngx_mail_close_connection(c);
}
+
+static ngx_int_t
+ngx_mail_verify_cert(ngx_mail_session_t *s, ngx_connection_t *c)
+{
+ long rc;
+ X509 *cert;
+ ngx_mail_ssl_conf_t *sslcf;
+ ngx_mail_core_srv_conf_t *cscf;
+
+ sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
+
+ if (!sslcf->verify) {
+ return NGX_OK;
+ }
+
+ rc = SSL_get_verify_result(c->ssl->connection);
+
+ if (rc != X509_V_OK
+ && (sslcf->verify != 3 || !ngx_ssl_verify_error_optional(rc)))
+ {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "client SSL certificate verify error: (%l:%s)",
+ rc, X509_verify_cert_error_string(rc));
+
+ ngx_ssl_remove_cached_session(sslcf->ssl.ctx,
+ (SSL_get0_session(c->ssl->connection)));
+
+ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+ s->out = cscf->protocol->cert_error;
+ s->quit = 1;
+
+ c->write->handler = ngx_mail_send;
+
+ ngx_mail_send(s->connection->write);
+ return NGX_ERROR;
+ }
+
+ if (sslcf->verify == 1) {
+ cert = SSL_get_peer_certificate(c->ssl->connection);
+
+ if (cert == NULL) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "client sent no required SSL certificate");
+
+ ngx_ssl_remove_cached_session(sslcf->ssl.ctx,
+ (SSL_get0_session(c->ssl->connection)));
+
+ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+ s->out = cscf->protocol->no_cert;
+ s->quit = 1;
+
+ c->write->handler = ngx_mail_send;
+
+ ngx_mail_send(s->connection->write);
+ return NGX_ERROR;
+ }
+
+ X509_free(cert);
+ }
+
+ return NGX_OK;
+}
+
#endif
diff --git a/src/mail/ngx_mail_imap_module.c b/src/mail/ngx_mail_imap_module.c
index dc80b4fb4..d281070fb 100644
--- a/src/mail/ngx_mail_imap_module.c
+++ b/src/mail/ngx_mail_imap_module.c
@@ -52,7 +52,9 @@ static ngx_mail_protocol_t ngx_mail_imap_protocol = {
ngx_mail_imap_parse_command,
ngx_mail_imap_auth_state,
- ngx_string("* BAD internal server error" CRLF)
+ ngx_string("* BAD internal server error" CRLF),
+ ngx_string("* BYE SSL certificate error" CRLF),
+ ngx_string("* BYE No required SSL certificate" CRLF)
};
diff --git a/src/mail/ngx_mail_pop3_module.c b/src/mail/ngx_mail_pop3_module.c
index b59747290..73f8531bc 100644
--- a/src/mail/ngx_mail_pop3_module.c
+++ b/src/mail/ngx_mail_pop3_module.c
@@ -58,7 +58,9 @@ static ngx_mail_protocol_t ngx_mail_pop3_protocol = {
ngx_mail_pop3_parse_command,
ngx_mail_pop3_auth_state,
- ngx_string("-ERR internal server error" CRLF)
+ ngx_string("-ERR internal server error" CRLF),
+ ngx_string("-ERR SSL certificate error" CRLF),
+ ngx_string("-ERR No required SSL certificate" CRLF)
};
diff --git a/src/mail/ngx_mail_smtp_module.c b/src/mail/ngx_mail_smtp_module.c
index 02bbf1fb9..d5bb51cc2 100644
--- a/src/mail/ngx_mail_smtp_module.c
+++ b/src/mail/ngx_mail_smtp_module.c
@@ -45,7 +45,9 @@ static ngx_mail_protocol_t ngx_mail_smtp_protocol = {
ngx_mail_smtp_parse_command,
ngx_mail_smtp_auth_state,
- ngx_string("451 4.3.2 Internal server error" CRLF)
+ ngx_string("451 4.3.2 Internal server error" CRLF),
+ ngx_string("421 4.7.1 SSL certificate error" CRLF),
+ ngx_string("421 4.7.1 No required SSL certificate" CRLF)
};
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
index f864d9910..e1efb61d6 100644
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -46,6 +46,15 @@ static ngx_conf_bitmask_t ngx_mail_ssl_protocols[] = {
};
+static ngx_conf_enum_t ngx_mail_ssl_verify[] = {
+ { ngx_string("off"), 0 },
+ { ngx_string("on"), 1 },
+ { ngx_string("optional"), 2 },
+ { ngx_string("optional_no_ca"), 3 },
+ { ngx_null_string, 0 }
+};
+
+
static ngx_command_t ngx_mail_ssl_commands[] = {
{ ngx_string("ssl"),
@@ -146,6 +155,41 @@ static ngx_command_t ngx_mail_ssl_commands[] = {
offsetof(ngx_mail_ssl_conf_t, session_timeout),
NULL },
+ { ngx_string("ssl_verify_client"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_enum_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, verify),
+ &ngx_mail_ssl_verify },
+
+ { ngx_string("ssl_verify_depth"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, verify_depth),
+ NULL },
+
+ { ngx_string("ssl_client_certificate"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, client_certificate),
+ NULL },
+
+ { ngx_string("ssl_trusted_certificate"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, trusted_certificate),
+ NULL },
+
+ { ngx_string("ssl_crl"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, crl),
+ NULL },
+
ngx_null_command
};
@@ -198,6 +242,9 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
* scf->certificate_key = { 0, NULL };
* scf->dhparam = { 0, NULL };
* scf->ecdh_curve = { 0, NULL };
+ * scf->client_certificate = { 0, NULL };
+ * scf->trusted_certificate = { 0, NULL };
+ * scf->crl = { 0, NULL };
* scf->ciphers = { 0, NULL };
* scf->shm_zone = NULL;
*/
@@ -206,6 +253,8 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
scf->starttls = NGX_CONF_UNSET_UINT;
scf->passwords = NGX_CONF_UNSET_PTR;
scf->prefer_server_ciphers = NGX_CONF_UNSET;
+ scf->verify = NGX_CONF_UNSET_UINT;
+ scf->verify_depth = NGX_CONF_UNSET_UINT;
scf->builtin_session_cache = NGX_CONF_UNSET;
scf->session_timeout = NGX_CONF_UNSET;
scf->session_tickets = NGX_CONF_UNSET;
@@ -238,6 +287,9 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
(NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1
|NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+ ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
+ ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
+
ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, "");
@@ -248,6 +300,12 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve,
NGX_DEFAULT_ECDH_CURVE);
+ ngx_conf_merge_str_value(conf->client_certificate,
+ prev->client_certificate, "");
+ ngx_conf_merge_str_value(conf->trusted_certificate,
+ prev->trusted_certificate, "");
+ ngx_conf_merge_str_value(conf->crl, prev->crl, "");
+
ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);
@@ -320,6 +378,35 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
+ if (conf->verify) {
+
+ if (conf->client_certificate.len == 0 && conf->verify != 3) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no ssl_client_certificate for ssl_client_verify");
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_ssl_client_certificate(cf, &conf->ssl,
+ &conf->client_certificate,
+ conf->verify_depth)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_ssl_trusted_certificate(cf, &conf->ssl,
+ &conf->trusted_certificate,
+ conf->verify_depth)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
if (SSL_CTX_set_cipher_list(conf->ssl.ctx,
(const char *) conf->ciphers.data)
== 0)
@@ -334,7 +421,9 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
}
+#ifndef LIBRESSL_VERSION_NUMBER
SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback);
+#endif
if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) {
return NGX_CONF_ERROR;
diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h
index 987d029ef..296a6a21f 100644
--- a/src/mail/ngx_mail_ssl_module.h
+++ b/src/mail/ngx_mail_ssl_module.h
@@ -28,6 +28,9 @@ typedef struct {
ngx_uint_t starttls;
ngx_uint_t protocols;
+ ngx_uint_t verify;
+ ngx_uint_t verify_depth;
+
ssize_t builtin_session_cache;
time_t session_timeout;
@@ -36,6 +39,9 @@ typedef struct {
ngx_str_t certificate_key;
ngx_str_t dhparam;
ngx_str_t ecdh_curve;
+ ngx_str_t client_certificate;
+ ngx_str_t trusted_certificate;
+ ngx_str_t crl;
ngx_str_t ciphers;
diff --git a/src/os/unix/ngx_file_aio_read.c b/src/os/unix/ngx_file_aio_read.c
index 0bb383de5..b11cf8a3d 100644
--- a/src/os/unix/ngx_file_aio_read.c
+++ b/src/os/unix/ngx_file_aio_read.c
@@ -36,6 +36,28 @@ static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio,
static void ngx_file_aio_event_handler(ngx_event_t *ev);
+ngx_int_t
+ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool)
+{
+ ngx_event_aio_t *aio;
+
+ aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
+ if (aio == NULL) {
+ return NGX_ERROR;
+ }
+
+ aio->file = file;
+ aio->fd = file->fd;
+ aio->event.data = aio;
+ aio->event.ready = 1;
+ aio->event.log = file->log;
+
+ file->aio = aio;
+
+ return NGX_OK;
+}
+
+
ssize_t
ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
ngx_pool_t *pool)
@@ -48,25 +70,11 @@ ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
return ngx_read_file(file, buf, size, offset);
}
- aio = file->aio;
-
- if (aio == NULL) {
- aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
- if (aio == NULL) {
- return NGX_ERROR;
- }
-
- aio->file = file;
- aio->fd = file->fd;
- aio->event.data = aio;
- aio->event.ready = 1;
- aio->event.log = file->log;
-#if (NGX_HAVE_AIO_SENDFILE)
- aio->last_offset = -1;
-#endif
- file->aio = aio;
+ if (file->aio == NULL && ngx_file_aio_init(file, pool) != NGX_OK) {
+ return NGX_ERROR;
}
+ aio = file->aio;
ev = &aio->event;
if (!ev->ready) {
diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c
index c3ae47fdb..2a3ed2f26 100644
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -9,6 +9,12 @@
#include <ngx_core.h>
+#if (NGX_THREADS)
+#include <ngx_thread_pool.h>
+static void ngx_thread_read_handler(void *data, ngx_log_t *log);
+#endif
+
+
#if (NGX_HAVE_FILE_AIO)
ngx_uint_t ngx_file_aio = 1;
@@ -64,6 +70,109 @@ ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
}
+#if (NGX_THREADS)
+
+typedef struct {
+ ngx_fd_t fd;
+ u_char *buf;
+ size_t size;
+ off_t offset;
+
+ size_t read;
+ ngx_err_t err;
+} ngx_thread_read_ctx_t;
+
+
+ssize_t
+ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file, u_char *buf,
+ size_t size, off_t offset, ngx_pool_t *pool)
+{
+ ngx_thread_task_t *task;
+ ngx_thread_read_ctx_t *ctx;
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "thread read: %d, %p, %uz, %O",
+ file->fd, buf, size, offset);
+
+ task = *taskp;
+
+ if (task == NULL) {
+ task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_read_ctx_t));
+ if (task == NULL) {
+ return NGX_ERROR;
+ }
+
+ task->handler = ngx_thread_read_handler;
+
+ *taskp = task;
+ }
+
+ ctx = task->ctx;
+
+ if (task->event.complete) {
+ task->event.complete = 0;
+
+ if (ctx->err) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, ctx->err,
+ "pread() \"%s\" failed", file->name.data);
+ return NGX_ERROR;
+ }
+
+ return ctx->read;
+ }
+
+ ctx->fd = file->fd;
+ ctx->buf = buf;
+ ctx->size = size;
+ ctx->offset = offset;
+
+ if (file->thread_handler(task, file) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ return NGX_AGAIN;
+}
+
+
+#if (NGX_HAVE_PREAD)
+
+static void
+ngx_thread_read_handler(void *data, ngx_log_t *log)
+{
+ ngx_thread_read_ctx_t *ctx = data;
+
+ ssize_t n;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "thread read handler");
+
+ n = pread(ctx->fd, ctx->buf, ctx->size, ctx->offset);
+
+ if (n == -1) {
+ ctx->err = ngx_errno;
+
+ } else {
+ ctx->read = n;
+ ctx->err = 0;
+ }
+
+#if 0
+ ngx_time_update();
+#endif
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, log, 0,
+ "pread: %z (err: %i) of %uz @%O",
+ n, ctx->err, ctx->size, ctx->offset);
+}
+
+#else
+
+#error pread() is required!
+
+#endif
+
+#endif /* NGX_THREADS */
+
+
ssize_t
ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
{
diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h
index a78ec9613..b6990bc6e 100644
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -375,6 +375,7 @@ size_t ngx_fs_bsize(u_char *name);
#if (NGX_HAVE_FILE_AIO)
+ngx_int_t ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool);
ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size,
off_t offset, ngx_pool_t *pool);
@@ -382,5 +383,10 @@ extern ngx_uint_t ngx_file_aio;
#endif
+#if (NGX_THREADS)
+ssize_t ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file,
+ u_char *buf, size_t size, off_t offset, ngx_pool_t *pool);
+#endif
+
#endif /* _NGX_FILES_H_INCLUDED_ */
diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h
index 92b2928c8..8f060514d 100644
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -100,12 +100,6 @@ typedef struct aiocb ngx_aiocb_t;
#endif
-#if (__FreeBSD_version < 430000 || __FreeBSD_version < 500012)
-
-pid_t rfork_thread(int flags, void *stack, int (*func)(void *arg), void *arg);
-
-#endif
-
#ifndef IOV_MAX
#define IOV_MAX 1024
#endif
diff --git a/src/os/unix/ngx_freebsd_rfork_thread.c b/src/os/unix/ngx_freebsd_rfork_thread.c
deleted file mode 100644
index e92f9a9fd..000000000
--- a/src/os/unix/ngx_freebsd_rfork_thread.c
+++ /dev/null
@@ -1,756 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-
-/*
- * The threads implementation uses the rfork(RFPROC|RFTHREAD|RFMEM) syscall
- * to create threads. All threads use the stacks of the same size mmap()ed
- * below the main stack. Thus the current thread id is determined via
- * the stack pointer value.
- *
- * The mutex implementation uses the ngx_atomic_cmp_set() operation
- * to acquire a mutex and the SysV semaphore to wait on a mutex and to wake up
- * the waiting threads. The light mutex does not use semaphore, so after
- * spinning in the lock the thread calls sched_yield(). However the light
- * mutexes are intended to be used with the "trylock" operation only.
- * The SysV semop() is a cheap syscall, particularly if it has little sembuf's
- * and does not use SEM_UNDO.
- *
- * The condition variable implementation uses the signal #64.
- * The signal handler is SIG_IGN so the kill() is a cheap syscall.
- * The thread waits a signal in kevent(). The use of the EVFILT_SIGNAL
- * is safe since FreeBSD 4.10-STABLE.
- *
- * This threads implementation currently works on i386 (486+) and amd64
- * platforms only.
- */
-
-
-char *ngx_freebsd_kern_usrstack;
-size_t ngx_thread_stack_size;
-
-
-static size_t rz_size;
-static size_t usable_stack_size;
-static char *last_stack;
-
-static ngx_uint_t nthreads;
-static ngx_uint_t max_threads;
-
-static ngx_uint_t nkeys;
-static ngx_tid_t *tids; /* the threads tids array */
-void **ngx_tls; /* the threads tls's array */
-
-/* the thread-safe libc errno */
-
-static int errno0; /* the main thread's errno */
-static int *errnos; /* the threads errno's array */
-
-int *
-__error()
-{
- int tid;
-
- tid = ngx_gettid();
-
- return tid ? &errnos[tid - 1] : &errno0;
-}
-
-
-/*
- * __isthreaded enables the spinlocks in some libc functions, i.e. in malloc()
- * and some other places. Nevertheless we protect our malloc()/free() calls
- * by own mutex that is more efficient than the spinlock.
- *
- * _spinlock() is a weak referenced stub in src/lib/libc/gen/_spinlock_stub.c
- * that does nothing.
- */
-
-extern int __isthreaded;
-
-void
-_spinlock(ngx_atomic_t *lock)
-{
- ngx_int_t tries;
-
- tries = 0;
-
- for ( ;; ) {
-
- if (*lock) {
- if (ngx_ncpu > 1 && tries++ < 1000) {
- continue;
- }
-
- sched_yield();
- tries = 0;
-
- } else {
- if (ngx_atomic_cmp_set(lock, 0, 1)) {
- return;
- }
- }
- }
-}
-
-
-/*
- * Before FreeBSD 5.1 _spinunlock() is a simple #define in
- * src/lib/libc/include/spinlock.h that zeroes lock.
- *
- * Since FreeBSD 5.1 _spinunlock() is a weak referenced stub in
- * src/lib/libc/gen/_spinlock_stub.c that does nothing.
- */
-
-#ifndef _spinunlock
-
-void
-_spinunlock(ngx_atomic_t *lock)
-{
- *lock = 0;
-}
-
-#endif
-
-
-ngx_err_t
-ngx_create_thread(ngx_tid_t *tid, ngx_thread_value_t (*func)(void *arg),
- void *arg, ngx_log_t *log)
-{
- ngx_pid_t id;
- ngx_err_t err;
- char *stack, *stack_top;
-
- if (nthreads >= max_threads) {
- ngx_log_error(NGX_LOG_CRIT, log, 0,
- "no more than %ui threads can be created", max_threads);
- return NGX_ERROR;
- }
-
- last_stack -= ngx_thread_stack_size;
-
- stack = mmap(last_stack, usable_stack_size, PROT_READ|PROT_WRITE,
- MAP_STACK, -1, 0);
-
- if (stack == MAP_FAILED) {
- ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
- "mmap(%p:%uz, MAP_STACK) thread stack failed",
- last_stack, usable_stack_size);
- return NGX_ERROR;
- }
-
- if (stack != last_stack) {
- ngx_log_error(NGX_LOG_ALERT, log, 0,
- "stack %p address was changed to %p", last_stack, stack);
- return NGX_ERROR;
- }
-
- stack_top = stack + usable_stack_size;
-
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0,
- "thread stack: %p-%p", stack, stack_top);
-
- ngx_set_errno(0);
-
- id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top,
- (ngx_rfork_thread_func_pt) func, arg);
-
- err = ngx_errno;
-
- if (id == -1) {
- ngx_log_error(NGX_LOG_ALERT, log, err, "rfork() failed");
-
- } else {
- *tid = id;
- nthreads = (ngx_freebsd_kern_usrstack - stack_top)
- / ngx_thread_stack_size;
- tids[nthreads] = id;
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "rfork()ed thread: %P", id);
- }
-
- return err;
-}
-
-
-ngx_int_t
-ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle)
-{
- char *red_zone, *zone;
- size_t len;
- ngx_int_t i;
- struct sigaction sa;
-
- max_threads = n + 1;
-
- for (i = 0; i < n; i++) {
- ngx_memzero(&sa, sizeof(struct sigaction));
- sa.sa_handler = SIG_IGN;
- sigemptyset(&sa.sa_mask);
- if (sigaction(NGX_CV_SIGNAL, &sa, NULL) == -1) {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
- "sigaction(%d, SIG_IGN) failed", NGX_CV_SIGNAL);
- return NGX_ERROR;
- }
- }
-
- len = sizeof(ngx_freebsd_kern_usrstack);
- if (sysctlbyname("kern.usrstack", &ngx_freebsd_kern_usrstack, &len,
- NULL, 0) == -1)
- {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
- "sysctlbyname(kern.usrstack) failed");
- return NGX_ERROR;
- }
-
- /* the main thread stack red zone */
- rz_size = ngx_pagesize;
- red_zone = ngx_freebsd_kern_usrstack - (size + rz_size);
-
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
- "usrstack: %p red zone: %p",
- ngx_freebsd_kern_usrstack, red_zone);
-
- zone = mmap(red_zone, rz_size, PROT_NONE, MAP_ANON, -1, 0);
- if (zone == MAP_FAILED) {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
- "mmap(%p:%uz, PROT_NONE, MAP_ANON) red zone failed",
- red_zone, rz_size);
- return NGX_ERROR;
- }
-
- if (zone != red_zone) {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
- "red zone %p address was changed to %p", red_zone, zone);
- return NGX_ERROR;
- }
-
- /* create the thread errno' array */
-
- errnos = ngx_calloc(n * sizeof(int), cycle->log);
- if (errnos == NULL) {
- return NGX_ERROR;
- }
-
- /* create the thread tids array */
-
- tids = ngx_calloc((n + 1) * sizeof(ngx_tid_t), cycle->log);
- if (tids == NULL) {
- return NGX_ERROR;
- }
-
- tids[0] = ngx_pid;
-
- /* create the thread tls' array */
-
- ngx_tls = ngx_calloc(NGX_THREAD_KEYS_MAX * (n + 1) * sizeof(void *),
- cycle->log);
- if (ngx_tls == NULL) {
- return NGX_ERROR;
- }
-
- nthreads = 1;
-
- last_stack = zone + rz_size;
- usable_stack_size = size;
- ngx_thread_stack_size = size + rz_size;
-
- /* allow the spinlock in libc malloc() */
- __isthreaded = 1;
-
- ngx_threaded = 1;
-
- return NGX_OK;
-}
-
-
-ngx_tid_t
-ngx_thread_self(void)
-{
- ngx_int_t tid;
-
- tid = ngx_gettid();
-
- if (tids == NULL) {
- return ngx_pid;
- }
-
- return tids[tid];
-}
-
-
-ngx_err_t
-ngx_thread_key_create(ngx_tls_key_t *key)
-{
- if (nkeys >= NGX_THREAD_KEYS_MAX) {
- return NGX_ENOMEM;
- }
-
- *key = nkeys++;
-
- return 0;
-}
-
-
-ngx_err_t
-ngx_thread_set_tls(ngx_tls_key_t key, void *value)
-{
- if (key >= NGX_THREAD_KEYS_MAX) {
- return NGX_EINVAL;
- }
-
- ngx_tls[key * NGX_THREAD_KEYS_MAX + ngx_gettid()] = value;
- return 0;
-}
-
-
-ngx_mutex_t *
-ngx_mutex_init(ngx_log_t *log, ngx_uint_t flags)
-{
- ngx_mutex_t *m;
- union semun op;
-
- m = ngx_alloc(sizeof(ngx_mutex_t), log);
- if (m == NULL) {
- return NULL;
- }
-
- m->lock = 0;
- m->log = log;
-
- if (flags & NGX_MUTEX_LIGHT) {
- m->semid = -1;
- return m;
- }
-
- m->semid = semget(IPC_PRIVATE, 1, SEM_R|SEM_A);
- if (m->semid == -1) {
- ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semget() failed");
- return NULL;
- }
-
- op.val = 0;
-
- if (semctl(m->semid, 0, SETVAL, op) == -1) {
- ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "semctl(SETVAL) failed");
-
- if (semctl(m->semid, 0, IPC_RMID) == -1) {
- ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
- "semctl(IPC_RMID) failed");
- }
-
- return NULL;
- }
-
- return m;
-}
-
-
-void
-ngx_mutex_destroy(ngx_mutex_t *m)
-{
- if (semctl(m->semid, 0, IPC_RMID) == -1) {
- ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno,
- "semctl(IPC_RMID) failed");
- }
-
- ngx_free((void *) m);
-}
-
-
-ngx_int_t
-ngx_mutex_dolock(ngx_mutex_t *m, ngx_int_t try)
-{
- uint32_t lock, old;
- ngx_uint_t tries;
- struct sembuf op;
-
- if (!ngx_threaded) {
- return NGX_OK;
- }
-
-#if (NGX_DEBUG)
- if (try) {
- ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0,
- "try lock mutex %p lock:%XD", m, m->lock);
- } else {
- ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0,
- "lock mutex %p lock:%XD", m, m->lock);
- }
-#endif
-
- old = m->lock;
- tries = 0;
-
- for ( ;; ) {
- if (old & NGX_MUTEX_LOCK_BUSY) {
-
- if (try) {
- return NGX_AGAIN;
- }
-
- if (ngx_ncpu > 1 && tries++ < 1000) {
-
- /* the spinlock is used only on the SMP system */
-
- old = m->lock;
- continue;
- }
-
- if (m->semid == -1) {
- sched_yield();
-
- tries = 0;
- old = m->lock;
- continue;
- }
-
- ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0,
- "mutex %p lock:%XD", m, m->lock);
-
- /*
- * The mutex is locked so we increase a number
- * of the threads that are waiting on the mutex
- */
-
- lock = old + 1;
-
- if ((lock & ~NGX_MUTEX_LOCK_BUSY) > nthreads) {
- ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno,
- "%D threads wait for mutex %p, "
- "while only %ui threads are available",
- lock & ~NGX_MUTEX_LOCK_BUSY, m, nthreads);
- ngx_abort();
- }
-
- if (ngx_atomic_cmp_set(&m->lock, old, lock)) {
-
- ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0,
- "wait mutex %p lock:%XD", m, m->lock);
-
- /*
- * The number of the waiting threads has been increased
- * and we would wait on the SysV semaphore.
- * A semaphore should wake up us more efficiently than
- * a simple sched_yield() or usleep().
- */
-
- op.sem_num = 0;
- op.sem_op = -1;
- op.sem_flg = 0;
-
- if (semop(m->semid, &op, 1) == -1) {
- ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno,
- "semop() failed while waiting on mutex %p", m);
- ngx_abort();
- }
-
- ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0,
- "mutex waked up %p lock:%XD", m, m->lock);
-
- tries = 0;
- old = m->lock;
- continue;
- }
-
- old = m->lock;
-
- } else {
- lock = old | NGX_MUTEX_LOCK_BUSY;
-
- if (ngx_atomic_cmp_set(&m->lock, old, lock)) {
-
- /* we locked the mutex */
-
- break;
- }
-
- old = m->lock;
- }
-
- if (tries++ > 1000) {
-
- ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0,
- "mutex %p is contested", m);
-
- /* the mutex is probably contested so we are giving up now */
-
- sched_yield();
-
- tries = 0;
- old = m->lock;
- }
- }
-
- ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0,
- "mutex %p is locked, lock:%XD", m, m->lock);
-
- return NGX_OK;
-}
-
-
-void
-ngx_mutex_unlock(ngx_mutex_t *m)
-{
- uint32_t lock, old;
- struct sembuf op;
-
- if (!ngx_threaded) {
- return;
- }
-
- old = m->lock;
-
- if (!(old & NGX_MUTEX_LOCK_BUSY)) {
- ngx_log_error(NGX_LOG_ALERT, m->log, 0,
- "trying to unlock the free mutex %p", m);
- ngx_abort();
- }
-
- /* free the mutex */
-
-#if 0
- ngx_log_debug2(NGX_LOG_DEBUG_MUTEX, m->log, 0,
- "unlock mutex %p lock:%XD", m, old);
-#endif
-
- for ( ;; ) {
- lock = old & ~NGX_MUTEX_LOCK_BUSY;
-
- if (ngx_atomic_cmp_set(&m->lock, old, lock)) {
- break;
- }
-
- old = m->lock;
- }
-
- if (m->semid == -1) {
- ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0,
- "mutex %p is unlocked", m);
-
- return;
- }
-
- /* check whether we need to wake up a waiting thread */
-
- old = m->lock;
-
- for ( ;; ) {
- if (old & NGX_MUTEX_LOCK_BUSY) {
-
- /* the mutex is just locked by another thread */
-
- break;
- }
-
- if (old == 0) {
- break;
- }
-
- /* there are the waiting threads */
-
- lock = old - 1;
-
- if (ngx_atomic_cmp_set(&m->lock, old, lock)) {
-
- /* wake up the thread that waits on semaphore */
-
- ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0,
- "wake up mutex %p", m);
-
- op.sem_num = 0;
- op.sem_op = 1;
- op.sem_flg = 0;
-
- if (semop(m->semid, &op, 1) == -1) {
- ngx_log_error(NGX_LOG_ALERT, m->log, ngx_errno,
- "semop() failed while waking up on mutex %p", m);
- ngx_abort();
- }
-
- break;
- }
-
- old = m->lock;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0,
- "mutex %p is unlocked", m);
-
- return;
-}
-
-
-ngx_cond_t *
-ngx_cond_init(ngx_log_t *log)
-{
- ngx_cond_t *cv;
-
- cv = ngx_alloc(sizeof(ngx_cond_t), log);
- if (cv == NULL) {
- return NULL;
- }
-
- cv->signo = NGX_CV_SIGNAL;
- cv->tid = -1;
- cv->log = log;
- cv->kq = -1;
-
- return cv;
-}
-
-
-void
-ngx_cond_destroy(ngx_cond_t *cv)
-{
- if (close(cv->kq) == -1) {
- ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno,
- "kqueue close() failed");
- }
-
- ngx_free(cv);
-}
-
-
-ngx_int_t
-ngx_cond_wait(ngx_cond_t *cv, ngx_mutex_t *m)
-{
- int n;
- ngx_err_t err;
- struct kevent kev;
- struct timespec ts;
-
- if (cv->kq == -1) {
-
- /*
- * We have to add the EVFILT_SIGNAL filter in the rfork()ed thread.
- * Otherwise the thread would not get a signal event.
- *
- * However, we have not to open the kqueue in the thread,
- * it is simply handy do it together.
- */
-
- cv->kq = kqueue();
- if (cv->kq == -1) {
- ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, "kqueue() failed");
- return NGX_ERROR;
- }
-
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, cv->log, 0,
- "cv kq:%d signo:%d", cv->kq, cv->signo);
-
- kev.ident = cv->signo;
- kev.filter = EVFILT_SIGNAL;
- kev.flags = EV_ADD;
- kev.fflags = 0;
- kev.data = 0;
- kev.udata = NULL;
-
- ts.tv_sec = 0;
- ts.tv_nsec = 0;
-
- if (kevent(cv->kq, &kev, 1, NULL, 0, &ts) == -1) {
- ngx_log_error(NGX_LOG_ALERT, cv->log, ngx_errno, "kevent() failed");
- return NGX_ERROR;
- }
-
- cv->tid = ngx_thread_self();
- }
-
- ngx_mutex_unlock(m);
-
- ngx_log_debug3(NGX_LOG_DEBUG_CORE, cv->log, 0,
- "cv %p wait, kq:%d, signo:%d", cv, cv->kq, cv->signo);
-
- for ( ;; ) {
- n = kevent(cv->kq, NULL, 0, &kev, 1, NULL);
-
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, cv->log, 0,
- "cv %p kevent: %d", cv, n);
-
- if (n == -1) {
- err = ngx_errno;
- ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
- cv->log, ngx_errno,
- "kevent() failed while waiting condition variable %p",
- cv);
-
- if (err == NGX_EINTR) {
- break;
- }
-
- return NGX_ERROR;
- }
-
- if (n == 0) {
- ngx_log_error(NGX_LOG_ALERT, cv->log, 0,
- "kevent() returned no events "
- "while waiting condition variable %p",
- cv);
- continue;
- }
-
- if (kev.filter != EVFILT_SIGNAL) {
- ngx_log_error(NGX_LOG_ALERT, cv->log, 0,
- "kevent() returned unexpected events: %d "
- "while waiting condition variable %p",
- kev.filter, cv);
- continue;
- }
-
- if (kev.ident != (uintptr_t) cv->signo) {
- ngx_log_error(NGX_LOG_ALERT, cv->log, 0,
- "kevent() returned unexpected signal: %d ",
- "while waiting condition variable %p",
- kev.ident, cv);
- continue;
- }
-
- break;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p is waked up", cv);
-
- ngx_mutex_lock(m);
-
- return NGX_OK;
-}
-
-
-ngx_int_t
-ngx_cond_signal(ngx_cond_t *cv)
-{
- ngx_err_t err;
-
- ngx_log_debug3(NGX_LOG_DEBUG_CORE, cv->log, 0,
- "cv %p to signal %P %d",
- cv, cv->tid, cv->signo);
-
- if (cv->tid == -1) {
- return NGX_OK;
- }
-
- if (kill(cv->tid, cv->signo) == -1) {
-
- err = ngx_errno;
-
- ngx_log_error(NGX_LOG_ALERT, cv->log, err,
- "kill() failed while signaling condition variable %p", cv);
-
- if (err == NGX_ESRCH) {
- cv->tid = -1;
- }
-
- return NGX_ERROR;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p is signaled", cv);
-
- return NGX_OK;
-}
diff --git a/src/os/unix/ngx_freebsd_rfork_thread.h b/src/os/unix/ngx_freebsd_rfork_thread.h
deleted file mode 100644
index ff160449d..000000000
--- a/src/os/unix/ngx_freebsd_rfork_thread.h
+++ /dev/null
@@ -1,122 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
- */
-
-
-#ifndef _NGX_FREEBSD_RFORK_THREAD_H_INCLUDED_
-#define _NGX_FREEBSD_RFORK_THREAD_H_INCLUDED_
-
-
-#include <sys/ipc.h>
-#include <sys/sem.h>
-#include <sched.h>
-
-typedef pid_t ngx_tid_t;
-
-#define ngx_log_pid ngx_thread_self()
-#define ngx_log_tid 0
-
-#define NGX_TID_T_FMT "%P"
-
-
-#define NGX_MUTEX_LIGHT 1
-
-#define NGX_MUTEX_LOCK_BUSY 0x80000000
-
-typedef volatile struct {
- ngx_atomic_t lock;
- ngx_log_t *log;
- int semid;
-} ngx_mutex_t;
-
-
-#define NGX_CV_SIGNAL 64
-
-typedef struct {
- int signo;
- int kq;
- ngx_tid_t tid;
- ngx_log_t *log;
-} ngx_cond_t;
-
-
-#define ngx_thread_sigmask(how, set, oset) \
- (sigprocmask(how, set, oset) == -1) ? ngx_errno : 0
-
-#define ngx_thread_sigmask_n "sigprocmask()"
-
-#define ngx_thread_join(t, p)
-
-#define ngx_setthrtitle(n) setproctitle(n)
-
-
-extern char *ngx_freebsd_kern_usrstack;
-extern size_t ngx_thread_stack_size;
-
-
-static ngx_inline ngx_int_t
-ngx_gettid(void)
-{
- char *sp;
-
- if (ngx_thread_stack_size == 0) {
- return 0;
- }
-
-#if ( __i386__ )
-
- __asm__ volatile ("mov %%esp, %0" : "=q" (sp));
-
-#elif ( __amd64__ )
-
- __asm__ volatile ("mov %%rsp, %0" : "=q" (sp));
-
-#else
-
-#error "rfork()ed threads are not supported on this platform"
-
-#endif
-
- return (ngx_freebsd_kern_usrstack - sp) / ngx_thread_stack_size;
-}
-
-
-ngx_tid_t ngx_thread_self(void);
-
-
-typedef ngx_uint_t ngx_tls_key_t;
-
-#define NGX_THREAD_KEYS_MAX 16
-
-extern void **ngx_tls;
-
-ngx_err_t ngx_thread_key_create(ngx_tls_key_t *key);
-#define ngx_thread_key_create_n "the tls key creation"
-
-ngx_err_t ngx_thread_set_tls(ngx_tls_key_t key, void *value);
-#define ngx_thread_set_tls_n "the tls key setting"
-
-
-static void *
-ngx_thread_get_tls(ngx_tls_key_t key)
-{
- if (key >= NGX_THREAD_KEYS_MAX) {
- return NULL;
- }
-
- return ngx_tls[key * NGX_THREAD_KEYS_MAX + ngx_gettid()];
-}
-
-
-#define ngx_mutex_trylock(m) ngx_mutex_dolock(m, 1)
-#define ngx_mutex_lock(m) (void) ngx_mutex_dolock(m, 0)
-ngx_int_t ngx_mutex_dolock(ngx_mutex_t *m, ngx_int_t try);
-void ngx_mutex_unlock(ngx_mutex_t *m);
-
-
-typedef int (*ngx_rfork_thread_func_pt)(void *arg);
-
-
-#endif /* _NGX_FREEBSD_RFORK_THREAD_H_INCLUDED_ */
diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c
index 7199c8654..25790b6b6 100644
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -32,19 +32,23 @@
ngx_chain_t *
ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
{
- int rc, flags;
- off_t send, prev_send, sent;
- size_t file_size;
- ssize_t n;
- ngx_uint_t eintr, eagain;
- ngx_err_t err;
- ngx_buf_t *file;
- ngx_event_t *wev;
- ngx_chain_t *cl;
- ngx_iovec_t header, trailer;
- struct sf_hdtr hdtr;
- struct iovec headers[NGX_IOVS_PREALLOCATE];
- struct iovec trailers[NGX_IOVS_PREALLOCATE];
+ int rc, flags;
+ off_t send, prev_send, sent;
+ size_t file_size;
+ ssize_t n;
+ ngx_uint_t eintr, eagain;
+ ngx_err_t err;
+ ngx_buf_t *file;
+ ngx_event_t *wev;
+ ngx_chain_t *cl;
+ ngx_iovec_t header, trailer;
+ struct sf_hdtr hdtr;
+ struct iovec headers[NGX_IOVS_PREALLOCATE];
+ struct iovec trailers[NGX_IOVS_PREALLOCATE];
+#if (NGX_HAVE_AIO_SENDFILE)
+ ngx_uint_t ebusy;
+ ngx_event_aio_t *aio;
+#endif
wev = c->write;
@@ -73,6 +77,11 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
eagain = 0;
flags = 0;
+#if (NGX_HAVE_AIO_SENDFILE && NGX_SUPPRESS_WARN)
+ aio = NULL;
+ file = NULL;
+#endif
+
header.iovs = headers;
header.nalloc = NGX_IOVS_PREALLOCATE;
@@ -81,6 +90,9 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
for ( ;; ) {
eintr = 0;
+#if (NGX_HAVE_AIO_SENDFILE)
+ ebusy = 0;
+#endif
prev_send = send;
/* create the header iovec and coalesce the neighbouring bufs */
@@ -160,7 +172,8 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
sent = 0;
#if (NGX_HAVE_AIO_SENDFILE)
- flags = c->aio_sendfile ? SF_NODISKIO : 0;
+ aio = file->file->aio;
+ flags = (aio && aio->preload_handler) ? SF_NODISKIO : 0;
#endif
rc = sendfile(file->file->fd, c->fd, file->file_pos,
@@ -180,7 +193,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
#if (NGX_HAVE_AIO_SENDFILE)
case NGX_EBUSY:
- c->busy_sendfile = file;
+ ebusy = 1;
break;
#endif
@@ -232,9 +245,41 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
in = ngx_chain_update_sent(in, sent);
#if (NGX_HAVE_AIO_SENDFILE)
- if (c->busy_sendfile) {
+
+ if (ebusy) {
+ if (sent == 0) {
+ c->busy_count++;
+
+ if (c->busy_count > 2) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "sendfile(%V) returned busy again",
+ &file->file->name);
+
+ c->busy_count = 0;
+ aio->preload_handler = NULL;
+
+ send = prev_send;
+ continue;
+ }
+
+ } else {
+ c->busy_count = 0;
+ }
+
+ rc = aio->preload_handler(file);
+
+ if (rc > 0) {
+ send = prev_send + sent;
+ continue;
+ }
+
return in;
}
+
+ if (flags == SF_NODISKIO) {
+ c->busy_count = 0;
+ }
+
#endif
if (eagain) {
diff --git a/src/os/unix/ngx_linux_aio_read.c b/src/os/unix/ngx_linux_aio_read.c
index 8273c13f9..b0a923604 100644
--- a/src/os/unix/ngx_linux_aio_read.c
+++ b/src/os/unix/ngx_linux_aio_read.c
@@ -24,6 +24,28 @@ io_submit(aio_context_t ctx, long n, struct iocb **paiocb)
}
+ngx_int_t
+ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool)
+{
+ ngx_event_aio_t *aio;
+
+ aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
+ if (aio == NULL) {
+ return NGX_ERROR;
+ }
+
+ aio->file = file;
+ aio->fd = file->fd;
+ aio->event.data = aio;
+ aio->event.ready = 1;
+ aio->event.log = file->log;
+
+ file->aio = aio;
+
+ return NGX_OK;
+}
+
+
ssize_t
ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
ngx_pool_t *pool)
@@ -37,22 +59,11 @@ ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
return ngx_read_file(file, buf, size, offset);
}
- aio = file->aio;
-
- if (aio == NULL) {
- aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
- if (aio == NULL) {
- return NGX_ERROR;
- }
-
- aio->file = file;
- aio->fd = file->fd;
- aio->event.data = aio;
- aio->event.ready = 1;
- aio->event.log = file->log;
- file->aio = aio;
+ if (file->aio == NULL && ngx_file_aio_init(file, pool) != NGX_OK) {
+ return NGX_ERROR;
}
+ aio = file->aio;
ev = &aio->event;
if (!ev->ready) {
diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h
index c6c02c93e..0c0b168d7 100644
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -93,11 +93,11 @@ extern ssize_t sendfile(int s, int fd, int32_t *offset, size_t size);
#endif
-#if (NGX_HAVE_FILE_AIO)
#if (NGX_HAVE_SYS_EVENTFD_H)
#include <sys/eventfd.h>
#endif
#include <sys/syscall.h>
+#if (NGX_HAVE_FILE_AIO)
#include <linux/aio_abi.h>
typedef struct iocb ngx_aiocb_t;
#endif
diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c
index d696438be..97f741d0a 100644
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -10,6 +10,22 @@
#include <ngx_event.h>
+static ssize_t ngx_linux_sendfile(ngx_connection_t *c, ngx_buf_t *file,
+ size_t size);
+
+#if (NGX_THREADS)
+#include <ngx_thread_pool.h>
+
+#if !(NGX_HAVE_SENDFILE64)
+#error sendfile64() is required!
+#endif
+
+static ngx_int_t ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file,
+ size_t size, size_t *sent);
+static void ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log);
+#endif
+
+
/*
* On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit
* offsets only, and the including <sys/sendfile.h> breaks the compiling,
@@ -31,20 +47,18 @@ ngx_chain_t *
ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
{
int tcp_nodelay;
- off_t send, prev_send, sent;
- size_t file_size;
+ off_t send, prev_send;
+ size_t file_size, sent;
ssize_t n;
ngx_err_t err;
ngx_buf_t *file;
- ngx_uint_t eintr;
ngx_event_t *wev;
ngx_chain_t *cl;
ngx_iovec_t header;
struct iovec headers[NGX_IOVS_PREALLOCATE];
-#if (NGX_HAVE_SENDFILE64)
- off_t offset;
-#else
- int32_t offset;
+#if (NGX_THREADS)
+ ngx_int_t rc;
+ ngx_uint_t thread_handled, thread_complete;
#endif
wev = c->write;
@@ -67,8 +81,11 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
header.nalloc = NGX_IOVS_PREALLOCATE;
for ( ;; ) {
- eintr = 0;
prev_send = send;
+#if (NGX_THREADS)
+ thread_handled = 0;
+ thread_complete = 0;
+#endif
/* create the iovec and coalesce the neighbouring bufs */
@@ -161,43 +178,38 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
return NGX_CHAIN_ERROR;
}
#endif
-#if (NGX_HAVE_SENDFILE64)
- offset = file->file_pos;
-#else
- offset = (int32_t) file->file_pos;
-#endif
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "sendfile: @%O %uz", file->file_pos, file_size);
+#if (NGX_THREADS)
+ if (file->file->thread_handler) {
+ rc = ngx_linux_sendfile_thread(c, file, file_size, &sent);
- n = sendfile(c->fd, file->file->fd, &offset, file_size);
-
- if (n == -1) {
- err = ngx_errno;
+ switch (rc) {
+ case NGX_OK:
+ thread_handled = 1;
+ break;
- switch (err) {
- case NGX_EAGAIN:
+ case NGX_DONE:
+ thread_complete = 1;
break;
- case NGX_EINTR:
- eintr = 1;
+ case NGX_AGAIN:
break;
- default:
- wev->error = 1;
- ngx_connection_error(c, err, "sendfile() failed");
+ default: /* NGX_ERROR */
return NGX_CHAIN_ERROR;
}
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
- "sendfile() is not ready");
- }
+ } else
+#endif
+ {
+ n = ngx_linux_sendfile(c, file, file_size);
- sent = n > 0 ? n : 0;
+ if (n == NGX_ERROR) {
+ return NGX_CHAIN_ERROR;
+ }
- ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "sendfile: %z, @%O %O:%uz",
- n, file->file_pos, sent, file_size);
+ sent = (n == NGX_AGAIN) ? 0 : n;
+ }
} else {
n = ngx_writev(c, &header);
@@ -213,12 +225,17 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
in = ngx_chain_update_sent(in, sent);
- if (eintr) {
- send = prev_send;
- continue;
- }
+ if ((size_t) (send - prev_send) != sent) {
+#if (NGX_THREADS)
+ if (thread_handled) {
+ return in;
+ }
- if (send - prev_send != sent) {
+ if (thread_complete) {
+ send = prev_send + sent;
+ continue;
+ }
+#endif
wev->ready = 0;
return in;
}
@@ -228,3 +245,175 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
}
}
}
+
+
+static ssize_t
+ngx_linux_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size)
+{
+#if (NGX_HAVE_SENDFILE64)
+ off_t offset;
+#else
+ int32_t offset;
+#endif
+ ssize_t n;
+ ngx_err_t err;
+
+#if (NGX_HAVE_SENDFILE64)
+ offset = file->file_pos;
+#else
+ offset = (int32_t) file->file_pos;
+#endif
+
+eintr:
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "sendfile: @%O %uz", file->file_pos, size);
+
+ n = sendfile(c->fd, file->file->fd, &offset, size);
+
+ if (n == -1) {
+ err = ngx_errno;
+
+ switch (err) {
+ case NGX_EAGAIN:
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "sendfile() is not ready");
+ return NGX_AGAIN;
+
+ case NGX_EINTR:
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
+ "sendfile() was interrupted");
+ goto eintr;
+
+ default:
+ c->write->error = 1;
+ ngx_connection_error(c, err, "sendfile() failed");
+ return NGX_ERROR;
+ }
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %z of %uz @%O",
+ n, size, file->file_pos);
+
+ return n;
+}
+
+
+#if (NGX_THREADS)
+
+typedef struct {
+ ngx_buf_t *file;
+ ngx_socket_t socket;
+ size_t size;
+
+ size_t sent;
+ ngx_err_t err;
+} ngx_linux_sendfile_ctx_t;
+
+
+static ngx_int_t
+ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size,
+ size_t *sent)
+{
+ ngx_uint_t flags;
+ ngx_event_t *wev;
+ ngx_thread_task_t *task;
+ ngx_linux_sendfile_ctx_t *ctx;
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "linux sendfile thread: %d, %uz, %O",
+ file->file->fd, size, file->file_pos);
+
+ task = c->sendfile_task;
+
+ if (task == NULL) {
+ task = ngx_thread_task_alloc(c->pool, sizeof(ngx_linux_sendfile_ctx_t));
+ if (task == NULL) {
+ return NGX_ERROR;
+ }
+
+ task->handler = ngx_linux_sendfile_thread_handler;
+
+ c->sendfile_task = task;
+ }
+
+ ctx = task->ctx;
+ wev = c->write;
+
+ if (task->event.complete) {
+ task->event.complete = 0;
+
+ if (ctx->err && ctx->err != NGX_EAGAIN) {
+ wev->error = 1;
+ ngx_connection_error(c, ctx->err, "sendfile() failed");
+ return NGX_ERROR;
+ }
+
+ *sent = ctx->sent;
+
+ return (ctx->sent == ctx->size) ? NGX_DONE : NGX_AGAIN;
+ }
+
+ ctx->file = file;
+ ctx->socket = c->fd;
+ ctx->size = size;
+
+ if (wev->active) {
+ flags = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ? NGX_CLEAR_EVENT
+ : NGX_LEVEL_EVENT;
+
+ if (ngx_del_event(wev, NGX_WRITE_EVENT, flags) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+ }
+
+ if (file->file->thread_handler(task, file->file) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ *sent = 0;
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log)
+{
+ ngx_linux_sendfile_ctx_t *ctx = data;
+
+ off_t offset;
+ ssize_t n;
+ ngx_buf_t *file;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "linux sendfile thread handler");
+
+ file = ctx->file;
+ offset = file->file_pos;
+
+again:
+
+ n = sendfile(ctx->socket, file->file->fd, &offset, ctx->size);
+
+ if (n == -1) {
+ ctx->err = ngx_errno;
+
+ } else {
+ ctx->sent = n;
+ ctx->err = 0;
+ }
+
+#if 0
+ ngx_time_update();
+#endif
+
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0,
+ "sendfile: %z (err: %i) of %uz @%O",
+ n, ctx->err, ctx->size, file->file_pos);
+
+ if (ctx->err == NGX_EINTR) {
+ goto again;
+ }
+}
+
+#endif /* NGX_THREADS */
diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c
index 51cf72544..1d5e700a8 100644
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -23,10 +23,6 @@ static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data);
static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker);
static void ngx_worker_process_exit(ngx_cycle_t *cycle);
static void ngx_channel_handler(ngx_event_t *ev);
-#if (NGX_THREADS)
-static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle);
-static ngx_thread_value_t ngx_worker_thread_cycle(void *data);
-#endif
static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data);
static void ngx_cache_manager_process_handler(ngx_event_t *ev);
static void ngx_cache_loader_process_handler(ngx_event_t *ev);
@@ -34,7 +30,6 @@ static void ngx_cache_loader_process_handler(ngx_event_t *ev);
ngx_uint_t ngx_process;
ngx_pid_t ngx_pid;
-ngx_uint_t ngx_threaded;
sig_atomic_t ngx_reap;
sig_atomic_t ngx_sigio;
@@ -56,12 +51,6 @@ ngx_uint_t ngx_noaccepting;
ngx_uint_t ngx_restart;
-#if (NGX_THREADS)
-volatile ngx_thread_t ngx_threads[NGX_MAX_THREADS];
-ngx_int_t ngx_threads_n;
-#endif
-
-
static u_char master_process[] = "master process";
@@ -747,52 +736,6 @@ ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
ngx_setproctitle("worker process");
-#if (NGX_THREADS)
- {
- ngx_int_t n;
- ngx_err_t err;
- ngx_core_conf_t *ccf;
-
- ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
-
- if (ngx_threads_n) {
- if (ngx_init_threads(ngx_threads_n, ccf->thread_stack_size, cycle)
- == NGX_ERROR)
- {
- /* fatal */
- exit(2);
- }
-
- err = ngx_thread_key_create(&ngx_core_tls_key);
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
- ngx_thread_key_create_n " failed");
- /* fatal */
- exit(2);
- }
-
- for (n = 0; n < ngx_threads_n; n++) {
-
- ngx_threads[n].cv = ngx_cond_init(cycle->log);
-
- if (ngx_threads[n].cv == NULL) {
- /* fatal */
- exit(2);
- }
-
- if (ngx_create_thread((ngx_tid_t *) &ngx_threads[n].tid,
- ngx_worker_thread_cycle,
- (void *) &ngx_threads[n], cycle->log)
- != 0)
- {
- /* fatal */
- exit(2);
- }
- }
- }
- }
-#endif
-
for ( ;; ) {
if (ngx_exiting) {
@@ -1032,12 +975,6 @@ ngx_worker_process_exit(ngx_cycle_t *cycle)
ngx_uint_t i;
ngx_connection_t *c;
-#if (NGX_THREADS)
- ngx_terminate = 1;
-
- ngx_wakeup_worker_threads(cycle);
-#endif
-
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->exit_process) {
ngx_modules[i]->exit_process(cycle);
@@ -1181,132 +1118,6 @@ ngx_channel_handler(ngx_event_t *ev)
}
-#if (NGX_THREADS)
-
-static void
-ngx_wakeup_worker_threads(ngx_cycle_t *cycle)
-{
- ngx_int_t i;
- ngx_uint_t live;
-
- for ( ;; ) {
-
- live = 0;
-
- for (i = 0; i < ngx_threads_n; i++) {
- if (ngx_threads[i].state < NGX_THREAD_EXIT) {
- if (ngx_cond_signal(ngx_threads[i].cv) == NGX_ERROR) {
- ngx_threads[i].state = NGX_THREAD_DONE;
-
- } else {
- live = 1;
- }
- }
-
- if (ngx_threads[i].state == NGX_THREAD_EXIT) {
- ngx_thread_join(ngx_threads[i].tid, NULL);
- ngx_threads[i].state = NGX_THREAD_DONE;
- }
- }
-
- if (live == 0) {
- ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0,
- "all worker threads are joined");
-
- /* STUB */
- ngx_done_events(cycle);
-
- return;
- }
-
- ngx_sched_yield();
- }
-}
-
-
-static ngx_thread_value_t
-ngx_worker_thread_cycle(void *data)
-{
- ngx_thread_t *thr = data;
-
- sigset_t set;
- ngx_err_t err;
- ngx_core_tls_t *tls;
- ngx_cycle_t *cycle;
-
- cycle = (ngx_cycle_t *) ngx_cycle;
-
- sigemptyset(&set);
- sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
- sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
- sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));
-
- err = ngx_thread_sigmask(SIG_BLOCK, &set, NULL);
- if (err) {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
- ngx_thread_sigmask_n " failed");
- return (ngx_thread_value_t) 1;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
- "thread " NGX_TID_T_FMT " started", ngx_thread_self());
-
- ngx_setthrtitle("worker thread");
-
- tls = ngx_calloc(sizeof(ngx_core_tls_t), cycle->log);
- if (tls == NULL) {
- return (ngx_thread_value_t) 1;
- }
-
- err = ngx_thread_set_tls(ngx_core_tls_key, tls);
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
- ngx_thread_set_tls_n " failed");
- return (ngx_thread_value_t) 1;
- }
-
- for ( ;; ) {
- thr->state = NGX_THREAD_FREE;
-
-#if 0
- if (ngx_cond_wait(thr->cv, ngx_posted_events_mutex) == NGX_ERROR) {
- return (ngx_thread_value_t) 1;
- }
-#endif
-
- if (ngx_terminate) {
- thr->state = NGX_THREAD_EXIT;
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
- "thread " NGX_TID_T_FMT " is done",
- ngx_thread_self());
-
- return (ngx_thread_value_t) 0;
- }
-
- thr->state = NGX_THREAD_BUSY;
-
-#if 0
- if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) {
- return (ngx_thread_value_t) 1;
- }
-
- if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) {
- return (ngx_thread_value_t) 1;
- }
-#endif
-
- if (ngx_process_changes) {
- if (ngx_process_changes(cycle, 1) == NGX_ERROR) {
- return (ngx_thread_value_t) 1;
- }
- }
- }
-}
-
-#endif
-
-
static void
ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data)
{
diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h
index 94747b85d..d44c377ce 100644
--- a/src/os/unix/ngx_process_cycle.h
+++ b/src/os/unix/ngx_process_cycle.h
@@ -43,7 +43,6 @@ extern ngx_pid_t ngx_pid;
extern ngx_pid_t ngx_new_binary;
extern ngx_uint_t ngx_inherited;
extern ngx_uint_t ngx_daemonized;
-extern ngx_uint_t ngx_threaded;
extern ngx_uint_t ngx_exiting;
extern sig_atomic_t ngx_reap;
diff --git a/src/os/unix/ngx_pthread_thread.c b/src/os/unix/ngx_pthread_thread.c
deleted file mode 100644
index 1cf31c3bc..000000000
--- a/src/os/unix/ngx_pthread_thread.c
+++ /dev/null
@@ -1,278 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-
-
-static ngx_uint_t nthreads;
-static ngx_uint_t max_threads;
-
-
-static pthread_attr_t thr_attr;
-
-
-ngx_err_t
-ngx_create_thread(ngx_tid_t *tid, ngx_thread_value_t (*func)(void *arg),
- void *arg, ngx_log_t *log)
-{
- int err;
-
- if (nthreads >= max_threads) {
- ngx_log_error(NGX_LOG_CRIT, log, 0,
- "no more than %ui threads can be created", max_threads);
- return NGX_ERROR;
- }
-
- err = pthread_create(tid, &thr_attr, func, arg);
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_create() failed");
- return err;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
- "thread is created: " NGX_TID_T_FMT, *tid);
-
- nthreads++;
-
- return err;
-}
-
-
-ngx_int_t
-ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle)
-{
- int err;
-
- max_threads = n;
-
- err = pthread_attr_init(&thr_attr);
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
- "pthread_attr_init() failed");
- return NGX_ERROR;
- }
-
- err = pthread_attr_setstacksize(&thr_attr, size);
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
- "pthread_attr_setstacksize() failed");
- return NGX_ERROR;
- }
-
- ngx_threaded = 1;
-
- return NGX_OK;
-}
-
-
-ngx_mutex_t *
-ngx_mutex_init(ngx_log_t *log, ngx_uint_t flags)
-{
- int err;
- ngx_mutex_t *m;
-
- m = ngx_alloc(sizeof(ngx_mutex_t), log);
- if (m == NULL) {
- return NULL;
- }
-
- m->log = log;
-
- err = pthread_mutex_init(&m->mutex, NULL);
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, m->log, err,
- "pthread_mutex_init() failed");
- return NULL;
- }
-
- return m;
-}
-
-
-void
-ngx_mutex_destroy(ngx_mutex_t *m)
-{
- int err;
-
- err = pthread_mutex_destroy(&m->mutex);
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, m->log, err,
- "pthread_mutex_destroy(%p) failed", m);
- }
-
- ngx_free(m);
-}
-
-
-void
-ngx_mutex_lock(ngx_mutex_t *m)
-{
- int err;
-
- if (!ngx_threaded) {
- return;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "lock mutex %p", m);
-
- err = pthread_mutex_lock(&m->mutex);
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, m->log, err,
- "pthread_mutex_lock(%p) failed", m);
- ngx_abort();
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is locked", m);
-
- return;
-}
-
-
-ngx_int_t
-ngx_mutex_trylock(ngx_mutex_t *m)
-{
- int err;
-
- if (!ngx_threaded) {
- return NGX_OK;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "try lock mutex %p", m);
-
- err = pthread_mutex_trylock(&m->mutex);
-
- if (err == NGX_EBUSY) {
- return NGX_AGAIN;
- }
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, m->log, err,
- "pthread_mutex_trylock(%p) failed", m);
- ngx_abort();
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is locked", m);
-
- return NGX_OK;
-}
-
-
-void
-ngx_mutex_unlock(ngx_mutex_t *m)
-{
- int err;
-
- if (!ngx_threaded) {
- return;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "unlock mutex %p", m);
-
- err = pthread_mutex_unlock(&m->mutex);
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, m->log, err,
- "pthread_mutex_unlock(%p) failed", m);
- ngx_abort();
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is unlocked", m);
-
- return;
-}
-
-
-ngx_cond_t *
-ngx_cond_init(ngx_log_t *log)
-{
- int err;
- ngx_cond_t *cv;
-
- cv = ngx_alloc(sizeof(ngx_cond_t), log);
- if (cv == NULL) {
- return NULL;
- }
-
- cv->log = log;
-
- err = pthread_cond_init(&cv->cond, NULL);
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, cv->log, err,
- "pthread_cond_init() failed");
- return NULL;
- }
-
- return cv;
-}
-
-
-void
-ngx_cond_destroy(ngx_cond_t *cv)
-{
- int err;
-
- err = pthread_cond_destroy(&cv->cond);
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, cv->log, err,
- "pthread_cond_destroy(%p) failed", cv);
- }
-
- ngx_free(cv);
-}
-
-
-ngx_int_t
-ngx_cond_wait(ngx_cond_t *cv, ngx_mutex_t *m)
-{
- int err;
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p wait", cv);
-
- err = pthread_cond_wait(&cv->cond, &m->mutex);
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, cv->log, err,
- "pthread_cond_wait(%p) failed", cv);
- return NGX_ERROR;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p is waked up", cv);
-
- ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, m->log, 0, "mutex %p is locked", m);
-
- return NGX_OK;
-}
-
-
-ngx_int_t
-ngx_cond_signal(ngx_cond_t *cv)
-{
- int err;
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p to signal", cv);
-
- err = pthread_cond_signal(&cv->cond);
-
- if (err != 0) {
- ngx_log_error(NGX_LOG_ALERT, cv->log, err,
- "pthread_cond_signal(%p) failed", cv);
- return NGX_ERROR;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, cv->log, 0, "cv %p is signaled", cv);
-
- return NGX_OK;
-}
diff --git a/src/os/unix/ngx_thread.h b/src/os/unix/ngx_thread.h
index 49c5d5656..1b52dd7fb 100644
--- a/src/os/unix/ngx_thread.h
+++ b/src/os/unix/ngx_thread.h
@@ -14,114 +14,57 @@
#if (NGX_THREADS)
-#define NGX_MAX_THREADS 128
-
-#if (NGX_USE_RFORK)
-#include <ngx_freebsd_rfork_thread.h>
-
-
-#else /* use pthreads */
-
#include <pthread.h>
-typedef pthread_t ngx_tid_t;
-
-#define ngx_thread_self() pthread_self()
-#define ngx_log_tid (int) ngx_thread_self()
-#if (NGX_FREEBSD) && !(NGX_LINUXTHREADS)
-#define NGX_TID_T_FMT "%p"
-#else
-#define NGX_TID_T_FMT "%d"
-#endif
+typedef pthread_mutex_t ngx_thread_mutex_t;
+ngx_int_t ngx_thread_mutex_create(ngx_thread_mutex_t *mtx, ngx_log_t *log);
+ngx_int_t ngx_thread_mutex_destroy(ngx_thread_mutex_t *mtx, ngx_log_t *log);
+ngx_int_t ngx_thread_mutex_lock(ngx_thread_mutex_t *mtx, ngx_log_t *log);
+ngx_int_t ngx_thread_mutex_unlock(ngx_thread_mutex_t *mtx, ngx_log_t *log);
-typedef pthread_key_t ngx_tls_key_t;
-#define ngx_thread_key_create(key) pthread_key_create(key, NULL)
-#define ngx_thread_key_create_n "pthread_key_create()"
-#define ngx_thread_set_tls pthread_setspecific
-#define ngx_thread_set_tls_n "pthread_setspecific()"
-#define ngx_thread_get_tls pthread_getspecific
+typedef pthread_cond_t ngx_thread_cond_t;
+ngx_int_t ngx_thread_cond_create(ngx_thread_cond_t *cond, ngx_log_t *log);
+ngx_int_t ngx_thread_cond_destroy(ngx_thread_cond_t *cond, ngx_log_t *log);
+ngx_int_t ngx_thread_cond_signal(ngx_thread_cond_t *cond, ngx_log_t *log);
+ngx_int_t ngx_thread_cond_wait(ngx_thread_cond_t *cond, ngx_thread_mutex_t *mtx,
+ ngx_log_t *log);
-#define NGX_MUTEX_LIGHT 0
-typedef struct {
- pthread_mutex_t mutex;
- ngx_log_t *log;
-} ngx_mutex_t;
+#if (NGX_LINUX)
-typedef struct {
- pthread_cond_t cond;
- ngx_log_t *log;
-} ngx_cond_t;
+typedef pid_t ngx_tid_t;
+#define NGX_TID_T_FMT "%P"
-#define ngx_thread_sigmask pthread_sigmask
-#define ngx_thread_sigmask_n "pthread_sigmask()"
+#elif (NGX_FREEBSD)
-#define ngx_thread_join(t, p) pthread_join(t, p)
+typedef uint32_t ngx_tid_t;
+#define NGX_TID_T_FMT "%uD"
-#define ngx_setthrtitle(n)
+#elif (NGX_DARWIN)
+typedef uint64_t ngx_tid_t;
+#define NGX_TID_T_FMT "%uA"
+#else
-ngx_int_t ngx_mutex_trylock(ngx_mutex_t *m);
-void ngx_mutex_lock(ngx_mutex_t *m);
-void ngx_mutex_unlock(ngx_mutex_t *m);
+typedef uint64_t ngx_tid_t;
+#define NGX_TID_T_FMT "%uA"
#endif
+ngx_tid_t ngx_thread_tid(void);
-#define ngx_thread_volatile volatile
-
-
-typedef struct {
- ngx_tid_t tid;
- ngx_cond_t *cv;
- ngx_uint_t state;
-} ngx_thread_t;
-
-#define NGX_THREAD_FREE 1
-#define NGX_THREAD_BUSY 2
-#define NGX_THREAD_EXIT 3
-#define NGX_THREAD_DONE 4
-
-extern ngx_int_t ngx_threads_n;
-extern volatile ngx_thread_t ngx_threads[NGX_MAX_THREADS];
+#define ngx_log_tid ngx_thread_tid()
-
-typedef void * ngx_thread_value_t;
-
-ngx_int_t ngx_init_threads(int n, size_t size, ngx_cycle_t *cycle);
-ngx_err_t ngx_create_thread(ngx_tid_t *tid,
- ngx_thread_value_t (*func)(void *arg), void *arg, ngx_log_t *log);
-
-ngx_mutex_t *ngx_mutex_init(ngx_log_t *log, ngx_uint_t flags);
-void ngx_mutex_destroy(ngx_mutex_t *m);
-
-
-ngx_cond_t *ngx_cond_init(ngx_log_t *log);
-void ngx_cond_destroy(ngx_cond_t *cv);
-ngx_int_t ngx_cond_wait(ngx_cond_t *cv, ngx_mutex_t *m);
-ngx_int_t ngx_cond_signal(ngx_cond_t *cv);
-
-
-#else /* !NGX_THREADS */
-
-#define ngx_thread_volatile
+#else
#define ngx_log_tid 0
#define NGX_TID_T_FMT "%d"
-#define ngx_mutex_trylock(m) NGX_OK
-#define ngx_mutex_lock(m)
-#define ngx_mutex_unlock(m)
-
-#define ngx_cond_signal(cv)
-
-#define ngx_thread_main() 1
-
#endif
diff --git a/src/os/unix/ngx_thread_cond.c b/src/os/unix/ngx_thread_cond.c
new file mode 100644
index 000000000..f5246966a
--- /dev/null
+++ b/src/os/unix/ngx_thread_cond.c
@@ -0,0 +1,87 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_int_t
+ngx_thread_cond_create(ngx_thread_cond_t *cond, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_cond_init(cond, NULL);
+ if (err == 0) {
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "pthread_cond_init(%p)", cond);
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_init() failed");
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_thread_cond_destroy(ngx_thread_cond_t *cond, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_cond_destroy(cond);
+ if (err == 0) {
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "pthread_cond_destroy(%p)", cond);
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_destroy() failed");
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_thread_cond_signal(ngx_thread_cond_t *cond, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_cond_signal(cond);
+ if (err == 0) {
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "pthread_cond_signal(%p)", cond);
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_signal() failed");
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_thread_cond_wait(ngx_thread_cond_t *cond, ngx_thread_mutex_t *mtx,
+ ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "pthread_cond_wait(%p) enter", cond);
+
+ err = pthread_cond_wait(cond, mtx);
+
+#if 0
+ ngx_time_update();
+#endif
+
+ if (err == 0) {
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "pthread_cond_wait(%p) exit", cond);
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_cond_wait() failed");
+
+ return NGX_ERROR;
+}
diff --git a/src/os/unix/ngx_thread_id.c b/src/os/unix/ngx_thread_id.c
new file mode 100644
index 000000000..5174f1abc
--- /dev/null
+++ b/src/os/unix/ngx_thread_id.c
@@ -0,0 +1,70 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_thread_pool.h>
+
+
+#if (NGX_LINUX)
+
+/*
+ * Linux thread id is a pid of thread created by clone(2),
+ * glibc does not provide a wrapper for gettid().
+ */
+
+ngx_tid_t
+ngx_thread_tid(void)
+{
+ return syscall(SYS_gettid);
+}
+
+#elif (NGX_FREEBSD) && (__FreeBSD_version >= 900031)
+
+#include <pthread_np.h>
+
+ngx_tid_t
+ngx_thread_tid(void)
+{
+ return pthread_getthreadid_np();
+}
+
+#elif (NGX_DARWIN)
+
+/*
+ * MacOSX thread has two thread ids:
+ *
+ * 1) MacOSX 10.6 (Snow Leoprad) has pthread_threadid_np() returning
+ * an uint64_t value, which is obtained using the __thread_selfid()
+ * syscall. It is a number above 300,000.
+ */
+
+ngx_tid_t
+ngx_thread_tid(void)
+{
+ uint64_t tid;
+
+ (void) pthread_threadid_np(NULL, &tid);
+ return tid;
+}
+
+/*
+ * 2) Kernel thread mach_port_t returned by pthread_mach_thread_np().
+ * It is a number in range 100-100,000.
+ *
+ * return pthread_mach_thread_np(pthread_self());
+ */
+
+#else
+
+ngx_tid_t
+ngx_thread_tid(void)
+{
+ return (uint64_t) (uintptr_t) pthread_self();
+}
+
+#endif
diff --git a/src/os/unix/ngx_thread_mutex.c b/src/os/unix/ngx_thread_mutex.c
new file mode 100644
index 000000000..6e8385ef5
--- /dev/null
+++ b/src/os/unix/ngx_thread_mutex.c
@@ -0,0 +1,174 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * All modern pthread mutex implementations try to acquire a lock
+ * atomically in userland before going to sleep in kernel. Some
+ * spins before the sleeping.
+ *
+ * In Solaris since version 8 all mutex types spin before sleeping.
+ * The default spin count is 1000. It can be overridden using
+ * _THREAD_ADAPTIVE_SPIN=100 environment variable.
+ *
+ * In MacOSX all mutex types spin to acquire a lock protecting a mutex's
+ * internals. If the mutex is busy, thread calls Mach semaphore_wait().
+ *
+ *
+ * PTHREAD_MUTEX_NORMAL lacks deadlock detection and is the fastest
+ * mutex type.
+ *
+ * Linux: No spinning. The internal name PTHREAD_MUTEX_TIMED_NP
+ * remains from the times when pthread_mutex_timedlock() was
+ * non-standard extension. Alias name: PTHREAD_MUTEX_FAST_NP.
+ * FreeBSD: No spinning.
+ *
+ *
+ * PTHREAD_MUTEX_ERRORCHECK is usually as fast as PTHREAD_MUTEX_NORMAL
+ * yet has lightweight deadlock detection.
+ *
+ * Linux: No spinning. The internal name: PTHREAD_MUTEX_ERRORCHECK_NP.
+ * FreeBSD: No spinning.
+ *
+ *
+ * PTHREAD_MUTEX_RECURSIVE allows recursive locking.
+ *
+ * Linux: No spinning. The internal name: PTHREAD_MUTEX_RECURSIVE_NP.
+ * FreeBSD: No spinning.
+ *
+ *
+ * PTHREAD_MUTEX_ADAPTIVE_NP spins on SMP systems before sleeping.
+ *
+ * Linux: No deadlock detection. Dynamically changes a spin count
+ * for each mutex from 10 to 100 based on spin count taken
+ * previously.
+ * FreeBSD: Deadlock detection. The default spin count is 2000.
+ * It can be overriden using LIBPTHREAD_SPINLOOPS environment
+ * variable or by pthread_mutex_setspinloops_np(). If a lock
+ * is still busy, sched_yield() can be called on both UP and
+ * SMP systems. The default yield loop count is zero, but
+ * it can be set by LIBPTHREAD_YIELDLOOPS environment
+ * variable or by pthread_mutex_setyieldloops_np().
+ * Solaris: No PTHREAD_MUTEX_ADAPTIVE_NP.
+ * MacOSX: No PTHREAD_MUTEX_ADAPTIVE_NP.
+ *
+ *
+ * PTHREAD_MUTEX_ELISION_NP is a Linux extension to elide locks using
+ * Intel Restricted Transactional Memory. It is the most suitable for
+ * rwlock pattern access because it allows simultaneous reads without lock.
+ * Supported since glibc 2.18.
+ *
+ *
+ * PTHREAD_MUTEX_DEFAULT is default mutex type.
+ *
+ * Linux: PTHREAD_MUTEX_NORMAL.
+ * FreeBSD: PTHREAD_MUTEX_ERRORCHECK.
+ * Solaris: PTHREAD_MUTEX_NORMAL.
+ * MacOSX: PTHREAD_MUTEX_NORMAL.
+ */
+
+
+ngx_int_t
+ngx_thread_mutex_create(ngx_thread_mutex_t *mtx, ngx_log_t *log)
+{
+ ngx_err_t err;
+ pthread_mutexattr_t attr;
+
+ err = pthread_mutexattr_init(&attr);
+ if (err != 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, err,
+ "pthread_mutexattr_init() failed");
+ return NGX_ERROR;
+ }
+
+ err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+ if (err != 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, err,
+ "pthread_mutexattr_settype"
+ "(PTHREAD_MUTEX_ERRORCHECK) failed");
+ return NGX_ERROR;
+ }
+
+ err = pthread_mutex_init(mtx, &attr);
+ if (err != 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, err,
+ "pthread_mutex_init() failed");
+ return NGX_ERROR;
+ }
+
+ err = pthread_mutexattr_destroy(&attr);
+ if (err != 0) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "pthread_mutexattr_destroy() failed");
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "pthread_mutex_init(%p)", mtx);
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_thread_mutex_destroy(ngx_thread_mutex_t *mtx, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_mutex_destroy(mtx);
+ if (err != 0) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "pthread_mutex_destroy() failed");
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "pthread_mutex_destroy(%p)", mtx);
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_thread_mutex_lock(ngx_thread_mutex_t *mtx, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "pthread_mutex_lock(%p) enter", mtx);
+
+ err = pthread_mutex_lock(mtx);
+ if (err == 0) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_mutex_lock() failed");
+
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_thread_mutex_unlock(ngx_thread_mutex_t *mtx, ngx_log_t *log)
+{
+ ngx_err_t err;
+
+ err = pthread_mutex_unlock(mtx);
+
+#if 0
+ ngx_time_update();
+#endif
+
+ if (err == 0) {
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "pthread_mutex_unlock(%p) exit", mtx);
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_mutex_unlock() failed");
+
+ return NGX_ERROR;
+}
diff --git a/src/os/unix/ngx_user.c b/src/os/unix/ngx_user.c
index 3491f1c9e..27c76ef80 100644
--- a/src/os/unix/ngx_user.c
+++ b/src/os/unix/ngx_user.c
@@ -64,16 +64,6 @@ ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
size_t len;
ngx_err_t err;
-#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT)
-
- /* crypt() is a time consuming function, so we only try to lock */
-
- if (ngx_mutex_trylock(ngx_crypt_mutex) != NGX_OK) {
- return NGX_AGAIN;
- }
-
-#endif
-
value = crypt((char *) key, (char *) salt);
if (value) {
@@ -81,25 +71,15 @@ ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
*encrypted = ngx_pnalloc(pool, len);
if (*encrypted == NULL) {
-#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT)
- ngx_mutex_unlock(ngx_crypt_mutex);
-#endif
return NGX_ERROR;
}
ngx_memcpy(*encrypted, value, len);
-#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT)
- ngx_mutex_unlock(ngx_crypt_mutex);
-#endif
return NGX_OK;
}
err = ngx_errno;
-#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT)
- ngx_mutex_unlock(ngx_crypt_mutex);
-#endif
-
ngx_log_error(NGX_LOG_CRIT, pool->log, err, "crypt() failed");
return NGX_ERROR;
diff --git a/src/os/unix/rfork_thread.S b/src/os/unix/rfork_thread.S
deleted file mode 100644
index e570349f9..000000000
--- a/src/os/unix/rfork_thread.S
+++ /dev/null
@@ -1,73 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
- */
-
-
-#include <sys/syscall.h>
-#include <machine/asm.h>
-
-/*
- * rfork_thread(3) - rfork_thread(flags, stack, func, arg);
- */
-
-#define KERNCALL int $0x80
-
-ENTRY(rfork_thread)
- push %ebp
- mov %esp, %ebp
- push %esi
-
- mov 12(%ebp), %esi # the thread stack address
-
- sub $4, %esi
- mov 20(%ebp), %eax # the thread argument
- mov %eax, (%esi)
-
- sub $4, %esi
- mov 16(%ebp), %eax # the thread start address
- mov %eax, (%esi)
-
- push 8(%ebp) # rfork(2) flags
- push $0
- mov $SYS_rfork, %eax
- KERNCALL
- jc error
-
- cmp $0, %edx
- jne child
-
-parent:
- add $8, %esp
- pop %esi
- leave
- ret
-
-child:
- mov %esi, %esp
- pop %eax
- call *%eax # call a thread start address ...
- add $4, %esp
-
- push %eax
- push $0
- mov $SYS_exit, %eax # ... and exit(2) after a thread would return
- KERNCALL
-
-error:
- add $8, %esp
- pop %esi
- leave
- PIC_PROLOGUE
-
- /* libc's cerror: jmp PIC_PLT(HIDENAME(cerror)) */
-
- push %eax
- call PIC_PLT(CNAME(__error))
- pop %ecx
- PIC_EPILOGUE
- mov %ecx, (%eax)
- mov $-1, %eax
- mov $-1, %edx
- ret