diff options
author | 2017-10-31 12:40:17 +0000 | |
---|---|---|
committer | 2017-10-31 14:19:39 +0000 | |
commit | e18a033b921d0d79fa8278f853548e6125b93e0c (patch) | |
tree | a6a55edf6ddceef824561818c9836914c326340d /app/nginx/src/os | |
parent | 7e18fa1bf263822c46d7431a911b41d6377d5f69 (diff) |
Integrate TLDK with NGINX
Created a clone of nginx (from https://github.com/nginx/nginx)
to demonstrate and benchmark TLDK library integrated with real
world application.
A new nginx module is created and and BSD socket-like API is implemented
on top of native TLDK API.
Note, that right now only minimalistic subset of socket-like API is provided:
- accept
- close
- readv
- recv
- writev
so only limited nginx functionality is available for a moment.
Change-Id: Ie1efe9349a0538da4348a48fb8306cbf636b5a92
Signed-off-by: Mohammad Abdul Awal <mohammad.abdul.awal@intel.com>
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
Signed-off-by: Remy Horton <remy.horton@intel.com>
Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
Diffstat (limited to 'app/nginx/src/os')
107 files changed, 15870 insertions, 0 deletions
diff --git a/app/nginx/src/os/unix/ngx_alloc.c b/app/nginx/src/os/unix/ngx_alloc.c new file mode 100644 index 0000000..5c2f787 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_alloc.c @@ -0,0 +1,90 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +ngx_uint_t ngx_pagesize; +ngx_uint_t ngx_pagesize_shift; +ngx_uint_t ngx_cacheline_size; + + +void * +ngx_alloc(size_t size, ngx_log_t *log) +{ + void *p; + + p = malloc(size); + if (p == NULL) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "malloc(%uz) failed", size); + } + + ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size); + + return p; +} + + +void * +ngx_calloc(size_t size, ngx_log_t *log) +{ + void *p; + + p = ngx_alloc(size, log); + + if (p) { + ngx_memzero(p, size); + } + + return p; +} + + +#if (NGX_HAVE_POSIX_MEMALIGN) + +void * +ngx_memalign(size_t alignment, size_t size, ngx_log_t *log) +{ + void *p; + int err; + + err = posix_memalign(&p, alignment, size); + + if (err) { + ngx_log_error(NGX_LOG_EMERG, log, err, + "posix_memalign(%uz, %uz) failed", alignment, size); + p = NULL; + } + + ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0, + "posix_memalign: %p:%uz @%uz", p, size, alignment); + + return p; +} + +#elif (NGX_HAVE_MEMALIGN) + +void * +ngx_memalign(size_t alignment, size_t size, ngx_log_t *log) +{ + void *p; + + p = memalign(alignment, size); + if (p == NULL) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "memalign(%uz, %uz) failed", alignment, size); + } + + ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0, + "memalign: %p:%uz @%uz", p, size, alignment); + + return p; +} + +#endif diff --git a/app/nginx/src/os/unix/ngx_alloc.h b/app/nginx/src/os/unix/ngx_alloc.h new file mode 100644 index 0000000..655db25 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_alloc.h @@ -0,0 +1,45 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_ALLOC_H_INCLUDED_ +#define _NGX_ALLOC_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +void *ngx_alloc(size_t size, ngx_log_t *log); +void *ngx_calloc(size_t size, ngx_log_t *log); + +#define ngx_free free + + +/* + * Linux has memalign() or posix_memalign() + * Solaris has memalign() + * FreeBSD 7.0 has posix_memalign(), besides, early version's malloc() + * aligns allocations bigger than page size at the page boundary + */ + +#if (NGX_HAVE_POSIX_MEMALIGN || NGX_HAVE_MEMALIGN) + +void *ngx_memalign(size_t alignment, size_t size, ngx_log_t *log); + +#else + +#define ngx_memalign(alignment, size, log) ngx_alloc(size, log) + +#endif + + +extern ngx_uint_t ngx_pagesize; +extern ngx_uint_t ngx_pagesize_shift; +extern ngx_uint_t ngx_cacheline_size; + + +#endif /* _NGX_ALLOC_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_atomic.h b/app/nginx/src/os/unix/ngx_atomic.h new file mode 100644 index 0000000..74b8b7f --- /dev/null +++ b/app/nginx/src/os/unix/ngx_atomic.h @@ -0,0 +1,313 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_ATOMIC_H_INCLUDED_ +#define _NGX_ATOMIC_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#if (NGX_HAVE_LIBATOMIC) + +#define AO_REQUIRE_CAS +#include <atomic_ops.h> + +#define NGX_HAVE_ATOMIC_OPS 1 + +typedef long ngx_atomic_int_t; +typedef AO_t ngx_atomic_uint_t; +typedef volatile ngx_atomic_uint_t ngx_atomic_t; + +#if (NGX_PTR_SIZE == 8) +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) +#else +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) +#endif + +#define ngx_atomic_cmp_set(lock, old, new) \ + AO_compare_and_swap(lock, old, new) +#define ngx_atomic_fetch_add(value, add) \ + AO_fetch_and_add(value, add) +#define ngx_memory_barrier() AO_nop() +#define ngx_cpu_pause() + + +#elif (NGX_DARWIN_ATOMIC) + +/* + * use Darwin 8 atomic(3) and barrier(3) operations + * optimized at run-time for UP and SMP + */ + +#include <libkern/OSAtomic.h> + +/* "bool" conflicts with perl's CORE/handy.h */ +#if 0 +#undef bool +#endif + + +#define NGX_HAVE_ATOMIC_OPS 1 + +#if (NGX_PTR_SIZE == 8) + +typedef int64_t ngx_atomic_int_t; +typedef uint64_t ngx_atomic_uint_t; +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) + +#define ngx_atomic_cmp_set(lock, old, new) \ + OSAtomicCompareAndSwap64Barrier(old, new, (int64_t *) lock) + +#define ngx_atomic_fetch_add(value, add) \ + (OSAtomicAdd64(add, (int64_t *) value) - add) + +#else + +typedef int32_t ngx_atomic_int_t; +typedef uint32_t ngx_atomic_uint_t; +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) + +#define ngx_atomic_cmp_set(lock, old, new) \ + OSAtomicCompareAndSwap32Barrier(old, new, (int32_t *) lock) + +#define ngx_atomic_fetch_add(value, add) \ + (OSAtomicAdd32(add, (int32_t *) value) - add) + +#endif + +#define ngx_memory_barrier() OSMemoryBarrier() + +#define ngx_cpu_pause() + +typedef volatile ngx_atomic_uint_t ngx_atomic_t; + + +#elif (NGX_HAVE_GCC_ATOMIC) + +/* GCC 4.1 builtin atomic operations */ + +#define NGX_HAVE_ATOMIC_OPS 1 + +typedef long ngx_atomic_int_t; +typedef unsigned long ngx_atomic_uint_t; + +#if (NGX_PTR_SIZE == 8) +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) +#else +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) +#endif + +typedef volatile ngx_atomic_uint_t ngx_atomic_t; + + +#define ngx_atomic_cmp_set(lock, old, set) \ + __sync_bool_compare_and_swap(lock, old, set) + +#define ngx_atomic_fetch_add(value, add) \ + __sync_fetch_and_add(value, add) + +#define ngx_memory_barrier() __sync_synchronize() + +#if ( __i386__ || __i386 || __amd64__ || __amd64 ) +#define ngx_cpu_pause() __asm__ ("pause") +#else +#define ngx_cpu_pause() +#endif + + +#elif ( __i386__ || __i386 ) + +typedef int32_t ngx_atomic_int_t; +typedef uint32_t ngx_atomic_uint_t; +typedef volatile ngx_atomic_uint_t ngx_atomic_t; +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) + + +#if ( __SUNPRO_C ) + +#define NGX_HAVE_ATOMIC_OPS 1 + +ngx_atomic_uint_t +ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, + ngx_atomic_uint_t set); + +ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add); + +/* + * Sun Studio 12 exits with segmentation fault on '__asm ("pause")', + * so ngx_cpu_pause is declared in src/os/unix/ngx_sunpro_x86.il + */ + +void +ngx_cpu_pause(void); + +/* the code in src/os/unix/ngx_sunpro_x86.il */ + +#define ngx_memory_barrier() __asm (".volatile"); __asm (".nonvolatile") + + +#else /* ( __GNUC__ || __INTEL_COMPILER ) */ + +#define NGX_HAVE_ATOMIC_OPS 1 + +#include "ngx_gcc_atomic_x86.h" + +#endif + + +#elif ( __amd64__ || __amd64 ) + +typedef int64_t ngx_atomic_int_t; +typedef uint64_t ngx_atomic_uint_t; +typedef volatile ngx_atomic_uint_t ngx_atomic_t; +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) + + +#if ( __SUNPRO_C ) + +#define NGX_HAVE_ATOMIC_OPS 1 + +ngx_atomic_uint_t +ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, + ngx_atomic_uint_t set); + +ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add); + +/* + * Sun Studio 12 exits with segmentation fault on '__asm ("pause")', + * so ngx_cpu_pause is declared in src/os/unix/ngx_sunpro_amd64.il + */ + +void +ngx_cpu_pause(void); + +/* the code in src/os/unix/ngx_sunpro_amd64.il */ + +#define ngx_memory_barrier() __asm (".volatile"); __asm (".nonvolatile") + + +#else /* ( __GNUC__ || __INTEL_COMPILER ) */ + +#define NGX_HAVE_ATOMIC_OPS 1 + +#include "ngx_gcc_atomic_amd64.h" + +#endif + + +#elif ( __sparc__ || __sparc || __sparcv9 ) + +#if (NGX_PTR_SIZE == 8) + +typedef int64_t ngx_atomic_int_t; +typedef uint64_t ngx_atomic_uint_t; +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) + +#else + +typedef int32_t ngx_atomic_int_t; +typedef uint32_t ngx_atomic_uint_t; +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) + +#endif + +typedef volatile ngx_atomic_uint_t ngx_atomic_t; + + +#if ( __SUNPRO_C ) + +#define NGX_HAVE_ATOMIC_OPS 1 + +#include "ngx_sunpro_atomic_sparc64.h" + + +#else /* ( __GNUC__ || __INTEL_COMPILER ) */ + +#define NGX_HAVE_ATOMIC_OPS 1 + +#include "ngx_gcc_atomic_sparc64.h" + +#endif + + +#elif ( __powerpc__ || __POWERPC__ ) + +#define NGX_HAVE_ATOMIC_OPS 1 + +#if (NGX_PTR_SIZE == 8) + +typedef int64_t ngx_atomic_int_t; +typedef uint64_t ngx_atomic_uint_t; +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) + +#else + +typedef int32_t ngx_atomic_int_t; +typedef uint32_t ngx_atomic_uint_t; +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) + +#endif + +typedef volatile ngx_atomic_uint_t ngx_atomic_t; + + +#include "ngx_gcc_atomic_ppc.h" + +#endif + + +#if !(NGX_HAVE_ATOMIC_OPS) + +#define NGX_HAVE_ATOMIC_OPS 0 + +typedef int32_t ngx_atomic_int_t; +typedef uint32_t ngx_atomic_uint_t; +typedef volatile ngx_atomic_uint_t ngx_atomic_t; +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) + + +static ngx_inline ngx_atomic_uint_t +ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, + ngx_atomic_uint_t set) +{ + if (*lock == old) { + *lock = set; + return 1; + } + + return 0; +} + + +static ngx_inline ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) +{ + ngx_atomic_int_t old; + + old = *value; + *value += add; + + return old; +} + +#define ngx_memory_barrier() +#define ngx_cpu_pause() + +#endif + + +void ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin); + +#define ngx_trylock(lock) (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1)) +#define ngx_unlock(lock) *(lock) = 0 + + +#endif /* _NGX_ATOMIC_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_channel.c b/app/nginx/src/os/unix/ngx_channel.c new file mode 100644 index 0000000..1efa066 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_channel.c @@ -0,0 +1,253 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_channel.h> + + +ngx_int_t +ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, + ngx_log_t *log) +{ + ssize_t n; + ngx_err_t err; + struct iovec iov[1]; + struct msghdr msg; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + + union { + struct cmsghdr cm; + char space[CMSG_SPACE(sizeof(int))]; + } cmsg; + + if (ch->fd == -1) { + msg.msg_control = NULL; + msg.msg_controllen = 0; + + } else { + msg.msg_control = (caddr_t) &cmsg; + msg.msg_controllen = sizeof(cmsg); + + ngx_memzero(&cmsg, sizeof(cmsg)); + + cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int)); + cmsg.cm.cmsg_level = SOL_SOCKET; + cmsg.cm.cmsg_type = SCM_RIGHTS; + + /* + * We have to use ngx_memcpy() instead of simple + * *(int *) CMSG_DATA(&cmsg.cm) = ch->fd; + * because some gcc 4.4 with -O2/3/s optimization issues the warning: + * dereferencing type-punned pointer will break strict-aliasing rules + * + * Fortunately, gcc with -O1 compiles this ngx_memcpy() + * in the same simple assignment as in the code above + */ + + ngx_memcpy(CMSG_DATA(&cmsg.cm), &ch->fd, sizeof(int)); + } + + msg.msg_flags = 0; + +#else + + if (ch->fd == -1) { + msg.msg_accrights = NULL; + msg.msg_accrightslen = 0; + + } else { + msg.msg_accrights = (caddr_t) &ch->fd; + msg.msg_accrightslen = sizeof(int); + } + +#endif + + iov[0].iov_base = (char *) ch; + iov[0].iov_len = size; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + n = sendmsg(s, &msg, 0); + + if (n == -1) { + err = ngx_errno; + if (err == NGX_EAGAIN) { + return NGX_AGAIN; + } + + ngx_log_error(NGX_LOG_ALERT, log, err, "sendmsg() failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log) +{ + ssize_t n; + ngx_err_t err; + struct iovec iov[1]; + struct msghdr msg; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + union { + struct cmsghdr cm; + char space[CMSG_SPACE(sizeof(int))]; + } cmsg; +#else + int fd; +#endif + + iov[0].iov_base = (char *) ch; + iov[0].iov_len = size; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + msg.msg_control = (caddr_t) &cmsg; + msg.msg_controllen = sizeof(cmsg); +#else + msg.msg_accrights = (caddr_t) &fd; + msg.msg_accrightslen = sizeof(int); +#endif + + n = recvmsg(s, &msg, 0); + + if (n == -1) { + err = ngx_errno; + if (err == NGX_EAGAIN) { + return NGX_AGAIN; + } + + ngx_log_error(NGX_LOG_ALERT, log, err, "recvmsg() failed"); + return NGX_ERROR; + } + + if (n == 0) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "recvmsg() returned zero"); + return NGX_ERROR; + } + + if ((size_t) n < sizeof(ngx_channel_t)) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "recvmsg() returned not enough data: %z", n); + return NGX_ERROR; + } + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + + if (ch->command == NGX_CMD_OPEN_CHANNEL) { + + if (cmsg.cm.cmsg_len < (socklen_t) CMSG_LEN(sizeof(int))) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "recvmsg() returned too small ancillary data"); + return NGX_ERROR; + } + + if (cmsg.cm.cmsg_level != SOL_SOCKET || cmsg.cm.cmsg_type != SCM_RIGHTS) + { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "recvmsg() returned invalid ancillary data " + "level %d or type %d", + cmsg.cm.cmsg_level, cmsg.cm.cmsg_type); + return NGX_ERROR; + } + + /* ch->fd = *(int *) CMSG_DATA(&cmsg.cm); */ + + ngx_memcpy(&ch->fd, CMSG_DATA(&cmsg.cm), sizeof(int)); + } + + if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "recvmsg() truncated data"); + } + +#else + + if (ch->command == NGX_CMD_OPEN_CHANNEL) { + if (msg.msg_accrightslen != sizeof(int)) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "recvmsg() returned no ancillary data"); + return NGX_ERROR; + } + + ch->fd = fd; + } + +#endif + + return n; +} + + +ngx_int_t +ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, ngx_int_t event, + ngx_event_handler_pt handler) +{ + ngx_event_t *ev, *rev, *wev; + ngx_connection_t *c; + + c = ngx_get_connection(fd, cycle->log); + + if (c == NULL) { + return NGX_ERROR; + } + + c->pool = cycle->pool; + + rev = c->read; + wev = c->write; + + rev->log = cycle->log; + wev->log = cycle->log; + + rev->channel = 1; + wev->channel = 1; + + ev = (event == NGX_READ_EVENT) ? rev : wev; + + ev->handler = handler; + + if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { + if (ngx_add_conn(c) == NGX_ERROR) { + ngx_free_connection(c); + return NGX_ERROR; + } + + } else { + if (ngx_add_event(ev, event, 0) == NGX_ERROR) { + ngx_free_connection(c); + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +void +ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log) +{ + if (close(fd[0]) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed"); + } + + if (close(fd[1]) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed"); + } +} diff --git a/app/nginx/src/os/unix/ngx_channel.h b/app/nginx/src/os/unix/ngx_channel.h new file mode 100644 index 0000000..362cc64 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_channel.h @@ -0,0 +1,34 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_CHANNEL_H_INCLUDED_ +#define _NGX_CHANNEL_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +typedef struct { + ngx_uint_t command; + ngx_pid_t pid; + ngx_int_t slot; + ngx_fd_t fd; +} ngx_channel_t; + + +ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, + ngx_log_t *log); +ngx_int_t ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, + ngx_log_t *log); +ngx_int_t ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, + ngx_int_t event, ngx_event_handler_pt handler); +void ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log); + + +#endif /* _NGX_CHANNEL_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_daemon.c b/app/nginx/src/os/unix/ngx_daemon.c new file mode 100644 index 0000000..ab67211 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_daemon.c @@ -0,0 +1,70 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +ngx_int_t +ngx_daemon(ngx_log_t *log) +{ + int fd; + + switch (fork()) { + case -1: + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed"); + return NGX_ERROR; + + case 0: + break; + + default: + exit(0); + } + + ngx_pid = ngx_getpid(); + + if (setsid() == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed"); + return NGX_ERROR; + } + + umask(0); + + fd = open("/dev/null", O_RDWR); + if (fd == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "open(\"/dev/null\") failed"); + return NGX_ERROR; + } + + if (dup2(fd, STDIN_FILENO) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed"); + return NGX_ERROR; + } + + if (dup2(fd, STDOUT_FILENO) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed"); + return NGX_ERROR; + } + +#if 0 + if (dup2(fd, STDERR_FILENO) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed"); + return NGX_ERROR; + } +#endif + + if (fd > STDERR_FILENO) { + if (close(fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed"); + return NGX_ERROR; + } + } + + return NGX_OK; +} diff --git a/app/nginx/src/os/unix/ngx_darwin.h b/app/nginx/src/os/unix/ngx_darwin.h new file mode 100644 index 0000000..4d01b26 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_darwin.h @@ -0,0 +1,23 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_DARWIN_H_INCLUDED_ +#define _NGX_DARWIN_H_INCLUDED_ + + +void ngx_debug_init(void); +ngx_chain_t *ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + +extern int ngx_darwin_kern_osreldate; +extern int ngx_darwin_hw_ncpu; +extern u_long ngx_darwin_net_inet_tcp_sendspace; + +extern ngx_uint_t ngx_debug_malloc; + + +#endif /* _NGX_DARWIN_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_darwin_config.h b/app/nginx/src/os/unix/ngx_darwin_config.h new file mode 100644 index 0000000..cfe3ce2 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_darwin_config.h @@ -0,0 +1,97 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_DARWIN_CONFIG_H_INCLUDED_ +#define _NGX_DARWIN_CONFIG_H_INCLUDED_ + + +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#include <inttypes.h> +#include <stdarg.h> +#include <stddef.h> /* offsetof() */ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <pwd.h> +#include <grp.h> +#include <dirent.h> +#include <glob.h> +#include <sys/mount.h> /* statfs() */ + +#include <sys/filio.h> /* FIONBIO */ +#include <sys/ioctl.h> +#include <sys/uio.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <sys/wait.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sched.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> /* TCP_NODELAY */ +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/un.h> + +#include <sys/sysctl.h> +#include <xlocale.h> + +#include <dlfcn.h> + + +#ifndef IOV_MAX +#define IOV_MAX 64 +#endif + + +#include <ngx_auto_config.h> + + +#if (NGX_HAVE_POSIX_SEM) +#include <semaphore.h> +#endif + + +#if (NGX_HAVE_POLL) +#include <poll.h> +#endif + + +#if (NGX_HAVE_KQUEUE) +#include <sys/event.h> +#endif + + +#define NGX_LISTEN_BACKLOG -1 + + +#ifndef NGX_HAVE_INHERITED_NONBLOCK +#define NGX_HAVE_INHERITED_NONBLOCK 1 +#endif + + +#ifndef NGX_HAVE_CASELESS_FILESYSTEM +#define NGX_HAVE_CASELESS_FILESYSTEM 1 +#endif + + +#define NGX_HAVE_OS_SPECIFIC_INIT 1 +#define NGX_HAVE_DEBUG_MALLOC 1 + + +extern char **environ; + + +#endif /* _NGX_DARWIN_CONFIG_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_darwin_init.c b/app/nginx/src/os/unix/ngx_darwin_init.c new file mode 100644 index 0000000..aabe02f --- /dev/null +++ b/app/nginx/src/os/unix/ngx_darwin_init.c @@ -0,0 +1,198 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +char ngx_darwin_kern_ostype[16]; +char ngx_darwin_kern_osrelease[128]; +int ngx_darwin_hw_ncpu; +int ngx_darwin_kern_ipc_somaxconn; +u_long ngx_darwin_net_inet_tcp_sendspace; + +ngx_uint_t ngx_debug_malloc; + + +static ngx_os_io_t ngx_darwin_io = { + ngx_unix_recv, + ngx_readv_chain, + ngx_udp_unix_recv, + ngx_unix_send, + ngx_udp_unix_send, + ngx_udp_unix_sendmsg_chain, +#if (NGX_HAVE_SENDFILE) + ngx_darwin_sendfile_chain, + NGX_IO_SENDFILE +#else + ngx_writev_chain, + 0 +#endif +}; + + +typedef struct { + char *name; + void *value; + size_t size; + ngx_uint_t exists; +} sysctl_t; + + +sysctl_t sysctls[] = { + { "hw.ncpu", + &ngx_darwin_hw_ncpu, + sizeof(ngx_darwin_hw_ncpu), 0 }, + + { "net.inet.tcp.sendspace", + &ngx_darwin_net_inet_tcp_sendspace, + sizeof(ngx_darwin_net_inet_tcp_sendspace), 0 }, + + { "kern.ipc.somaxconn", + &ngx_darwin_kern_ipc_somaxconn, + sizeof(ngx_darwin_kern_ipc_somaxconn), 0 }, + + { NULL, NULL, 0, 0 } +}; + + +void +ngx_debug_init(void) +{ +#if (NGX_DEBUG_MALLOC) + + /* + * MacOSX 10.6, 10.7: MallocScribble fills freed memory with 0x55 + * and fills allocated memory with 0xAA. + * MacOSX 10.4, 10.5: MallocScribble fills freed memory with 0x55, + * MallocPreScribble fills allocated memory with 0xAA. + * MacOSX 10.3: MallocScribble fills freed memory with 0x55, + * and no way to fill allocated memory. + */ + + setenv("MallocScribble", "1", 0); + + ngx_debug_malloc = 1; + +#else + + if (getenv("MallocScribble")) { + ngx_debug_malloc = 1; + } + +#endif +} + + +ngx_int_t +ngx_os_specific_init(ngx_log_t *log) +{ + size_t size; + ngx_err_t err; + ngx_uint_t i; + + size = sizeof(ngx_darwin_kern_ostype); + if (sysctlbyname("kern.ostype", ngx_darwin_kern_ostype, &size, NULL, 0) + == -1) + { + err = ngx_errno; + + if (err != NGX_ENOENT) { + + ngx_log_error(NGX_LOG_ALERT, log, err, + "sysctlbyname(kern.ostype) failed"); + + if (err != NGX_ENOMEM) { + return NGX_ERROR; + } + + ngx_darwin_kern_ostype[size - 1] = '\0'; + } + } + + size = sizeof(ngx_darwin_kern_osrelease); + if (sysctlbyname("kern.osrelease", ngx_darwin_kern_osrelease, &size, + NULL, 0) + == -1) + { + err = ngx_errno; + + if (err != NGX_ENOENT) { + + ngx_log_error(NGX_LOG_ALERT, log, err, + "sysctlbyname(kern.osrelease) failed"); + + if (err != NGX_ENOMEM) { + return NGX_ERROR; + } + + ngx_darwin_kern_osrelease[size - 1] = '\0'; + } + } + + for (i = 0; sysctls[i].name; i++) { + size = sysctls[i].size; + + if (sysctlbyname(sysctls[i].name, sysctls[i].value, &size, NULL, 0) + == 0) + { + sysctls[i].exists = 1; + continue; + } + + err = ngx_errno; + + if (err == NGX_ENOENT) { + continue; + } + + ngx_log_error(NGX_LOG_ALERT, log, err, + "sysctlbyname(%s) failed", sysctls[i].name); + return NGX_ERROR; + } + + ngx_ncpu = ngx_darwin_hw_ncpu; + + if (ngx_darwin_kern_ipc_somaxconn > 32767) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "sysctl kern.ipc.somaxconn must be less than 32768"); + return NGX_ERROR; + } + + ngx_tcp_nodelay_and_tcp_nopush = 1; + + ngx_os_io = ngx_darwin_io; + + return NGX_OK; +} + + +void +ngx_os_specific_status(ngx_log_t *log) +{ + u_long value; + ngx_uint_t i; + + if (ngx_darwin_kern_ostype[0]) { + ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s", + ngx_darwin_kern_ostype, ngx_darwin_kern_osrelease); + } + + for (i = 0; sysctls[i].name; i++) { + if (sysctls[i].exists) { + if (sysctls[i].size == sizeof(long)) { + value = *(long *) sysctls[i].value; + + } else { + value = *(int *) sysctls[i].value; + } + + ngx_log_error(NGX_LOG_NOTICE, log, 0, "%s: %l", + sysctls[i].name, value); + } + } +} diff --git a/app/nginx/src/os/unix/ngx_darwin_sendfile_chain.c b/app/nginx/src/os/unix/ngx_darwin_sendfile_chain.c new file mode 100644 index 0000000..2a76c15 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_darwin_sendfile_chain.c @@ -0,0 +1,206 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +/* + * It seems that Darwin 9.4 (Mac OS X 1.5) sendfile() has the same + * old bug as early FreeBSD sendfile() syscall: + * http://bugs.freebsd.org/33771 + * + * Besides sendfile() has another bug: if one calls sendfile() + * with both a header and a trailer, then sendfile() ignores a file part + * at all and sends only the header and the trailer together. + * For this reason we send a trailer only if there is no a header. + * + * Although sendfile() allows to pass a header or a trailer, + * it may send the header or the trailer and a part of the file + * in different packets. And FreeBSD workaround (TCP_NOPUSH option) + * does not help. + */ + + +ngx_chain_t * +ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + int rc; + off_t send, prev_send, sent; + off_t file_size; + ssize_t n; + ngx_uint_t eintr; + 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]; + + wev = c->write; + + if (!wev->ready) { + return in; + } + +#if (NGX_HAVE_KQUEUE) + + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) { + (void) ngx_connection_error(c, wev->kq_errno, + "kevent() reported about an closed connection"); + wev->error = 1; + return NGX_CHAIN_ERROR; + } + +#endif + + /* the maximum limit size is the maximum size_t value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) { + limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; + } + + send = 0; + + header.iovs = headers; + header.nalloc = NGX_IOVS_PREALLOCATE; + + trailer.iovs = trailers; + trailer.nalloc = NGX_IOVS_PREALLOCATE; + + for ( ;; ) { + eintr = 0; + prev_send = send; + + /* create the header iovec and coalesce the neighbouring bufs */ + + cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); + + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + + send += header.size; + + if (cl && cl->buf->in_file && send < limit) { + file = cl->buf; + + /* coalesce the neighbouring file bufs */ + + file_size = ngx_chain_coalesce_file(&cl, limit - send); + + send += file_size; + + if (header.count == 0 && send < limit) { + + /* + * create the trailer iovec and coalesce the neighbouring bufs + */ + + cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send, + c->log); + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + + send += trailer.size; + + } else { + trailer.count = 0; + } + + /* + * sendfile() returns EINVAL if sf_hdtr's count is 0, + * but corresponding pointer is not NULL + */ + + hdtr.headers = header.count ? header.iovs : NULL; + hdtr.hdr_cnt = header.count; + hdtr.trailers = trailer.count ? trailer.iovs : NULL; + hdtr.trl_cnt = trailer.count; + + sent = header.size + file_size; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendfile: @%O %O h:%uz", + file->file_pos, sent, header.size); + + rc = sendfile(file->file->fd, c->fd, file->file_pos, + &sent, &hdtr, 0); + + if (rc == -1) { + err = ngx_errno; + + switch (err) { + case NGX_EAGAIN: + break; + + case NGX_EINTR: + eintr = 1; + break; + + default: + wev->error = 1; + (void) ngx_connection_error(c, err, "sendfile() failed"); + return NGX_CHAIN_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendfile() sent only %O bytes", sent); + } + + if (rc == 0 && sent == 0) { + + /* + * if rc and sent equal to zero, then someone + * has truncated the file, so the offset became beyond + * the end of the file + */ + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfile() reported that \"%s\" was truncated", + file->file->name.data); + + return NGX_CHAIN_ERROR; + } + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendfile: %d, @%O %O:%O", + rc, file->file_pos, sent, file_size + header.size); + + } else { + n = ngx_writev(c, &header); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + sent = (n == NGX_AGAIN) ? 0 : n; + } + + c->sent += sent; + + in = ngx_chain_update_sent(in, sent); + + if (eintr) { + send = prev_send + sent; + continue; + } + + if (send - prev_send != sent) { + wev->ready = 0; + return in; + } + + if (send >= limit || in == NULL) { + return in; + } + } +} diff --git a/app/nginx/src/os/unix/ngx_dlopen.c b/app/nginx/src/os/unix/ngx_dlopen.c new file mode 100644 index 0000000..a0efc69 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_dlopen.c @@ -0,0 +1,28 @@ + +/* + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#if (NGX_HAVE_DLOPEN) + +char * +ngx_dlerror(void) +{ + char *err; + + err = (char *) dlerror(); + + if (err == NULL) { + return ""; + } + + return err; +} + +#endif diff --git a/app/nginx/src/os/unix/ngx_dlopen.h b/app/nginx/src/os/unix/ngx_dlopen.h new file mode 100644 index 0000000..7a3159f --- /dev/null +++ b/app/nginx/src/os/unix/ngx_dlopen.h @@ -0,0 +1,31 @@ + +/* + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_DLOPEN_H_INCLUDED_ +#define _NGX_DLOPEN_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define ngx_dlopen(path) dlopen((char *) path, RTLD_NOW | RTLD_GLOBAL) +#define ngx_dlopen_n "dlopen()" + +#define ngx_dlsym(handle, symbol) dlsym(handle, symbol) +#define ngx_dlsym_n "dlsym()" + +#define ngx_dlclose(handle) dlclose(handle) +#define ngx_dlclose_n "dlclose()" + + +#if (NGX_HAVE_DLOPEN) +char *ngx_dlerror(void); +#endif + + +#endif /* _NGX_DLOPEN_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_errno.c b/app/nginx/src/os/unix/ngx_errno.c new file mode 100644 index 0000000..e787b23 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_errno.c @@ -0,0 +1,87 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +/* + * The strerror() messages are copied because: + * + * 1) strerror() and strerror_r() functions are not Async-Signal-Safe, + * therefore, they cannot be used in signal handlers; + * + * 2) a direct sys_errlist[] array may be used instead of these functions, + * but Linux linker warns about its usage: + * + * warning: `sys_errlist' is deprecated; use `strerror' or `strerror_r' instead + * warning: `sys_nerr' is deprecated; use `strerror' or `strerror_r' instead + * + * causing false bug reports. + */ + + +static ngx_str_t *ngx_sys_errlist; +static ngx_str_t ngx_unknown_error = ngx_string("Unknown error"); + + +u_char * +ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) +{ + ngx_str_t *msg; + + msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]: + &ngx_unknown_error; + size = ngx_min(size, msg->len); + + return ngx_cpymem(errstr, msg->data, size); +} + + +ngx_int_t +ngx_strerror_init(void) +{ + char *msg; + u_char *p; + size_t len; + ngx_err_t err; + + /* + * ngx_strerror() is not ready to work at this stage, therefore, + * malloc() is used and possible errors are logged using strerror(). + */ + + len = NGX_SYS_NERR * sizeof(ngx_str_t); + + ngx_sys_errlist = malloc(len); + if (ngx_sys_errlist == NULL) { + goto failed; + } + + for (err = 0; err < NGX_SYS_NERR; err++) { + msg = strerror(err); + len = ngx_strlen(msg); + + p = malloc(len); + if (p == NULL) { + goto failed; + } + + ngx_memcpy(p, msg, len); + ngx_sys_errlist[err].len = len; + ngx_sys_errlist[err].data = p; + } + + return NGX_OK; + +failed: + + err = errno; + ngx_log_stderr(0, "malloc(%uz) failed (%d: %s)", len, err, strerror(err)); + + return NGX_ERROR; +} diff --git a/app/nginx/src/os/unix/ngx_errno.h b/app/nginx/src/os/unix/ngx_errno.h new file mode 100644 index 0000000..7d6ca76 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_errno.h @@ -0,0 +1,79 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_ERRNO_H_INCLUDED_ +#define _NGX_ERRNO_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +typedef int ngx_err_t; + +#define NGX_EPERM EPERM +#define NGX_ENOENT ENOENT +#define NGX_ENOPATH ENOENT +#define NGX_ESRCH ESRCH +#define NGX_EINTR EINTR +#define NGX_ECHILD ECHILD +#define NGX_ENOMEM ENOMEM +#define NGX_EACCES EACCES +#define NGX_EBUSY EBUSY +#define NGX_EEXIST EEXIST +#define NGX_EEXIST_FILE EEXIST +#define NGX_EXDEV EXDEV +#define NGX_ENOTDIR ENOTDIR +#define NGX_EISDIR EISDIR +#define NGX_EINVAL EINVAL +#define NGX_ENFILE ENFILE +#define NGX_EMFILE EMFILE +#define NGX_ENOSPC ENOSPC +#define NGX_EPIPE EPIPE +#define NGX_EINPROGRESS EINPROGRESS +#define NGX_ENOPROTOOPT ENOPROTOOPT +#define NGX_EOPNOTSUPP EOPNOTSUPP +#define NGX_EADDRINUSE EADDRINUSE +#define NGX_ECONNABORTED ECONNABORTED +#define NGX_ECONNRESET ECONNRESET +#define NGX_ENOTCONN ENOTCONN +#define NGX_ETIMEDOUT ETIMEDOUT +#define NGX_ECONNREFUSED ECONNREFUSED +#define NGX_ENAMETOOLONG ENAMETOOLONG +#define NGX_ENETDOWN ENETDOWN +#define NGX_ENETUNREACH ENETUNREACH +#define NGX_EHOSTDOWN EHOSTDOWN +#define NGX_EHOSTUNREACH EHOSTUNREACH +#define NGX_ENOSYS ENOSYS +#define NGX_ECANCELED ECANCELED +#define NGX_EILSEQ EILSEQ +#define NGX_ENOMOREFILES 0 +#define NGX_ELOOP ELOOP +#define NGX_EBADF EBADF + +#if (NGX_HAVE_OPENAT) +#define NGX_EMLINK EMLINK +#endif + +#if (__hpux__) +#define NGX_EAGAIN EWOULDBLOCK +#else +#define NGX_EAGAIN EAGAIN +#endif + + +#define ngx_errno errno +#define ngx_socket_errno errno +#define ngx_set_errno(err) errno = err +#define ngx_set_socket_errno(err) errno = err + + +u_char *ngx_strerror(ngx_err_t err, u_char *errstr, size_t size); +ngx_int_t ngx_strerror_init(void); + + +#endif /* _NGX_ERRNO_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_file_aio_read.c b/app/nginx/src/os/unix/ngx_file_aio_read.c new file mode 100644 index 0000000..aedc3c9 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_file_aio_read.c @@ -0,0 +1,216 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +/* + * FreeBSD file AIO features and quirks: + * + * if an asked data are already in VM cache, then aio_error() returns 0, + * and the data are already copied in buffer; + * + * aio_read() preread in VM cache as minimum 16K (probably BKVASIZE); + * the first AIO preload may be up to 128K; + * + * aio_read/aio_error() may return EINPROGRESS for just written data; + * + * kqueue EVFILT_AIO filter is level triggered only: an event repeats + * until aio_return() will be called; + * + * aio_cancel() cannot cancel file AIO: it returns AIO_NOTCANCELED always. + */ + + +extern int ngx_kqueue; + + +static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, + ngx_event_t *ev); +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) +{ + int n; + ngx_event_t *ev; + ngx_event_aio_t *aio; + + if (!ngx_file_aio) { + return ngx_read_file(file, buf, size, offset); + } + + if (file->aio == NULL && ngx_file_aio_init(file, pool) != NGX_OK) { + return NGX_ERROR; + } + + aio = file->aio; + ev = &aio->event; + + if (!ev->ready) { + ngx_log_error(NGX_LOG_ALERT, file->log, 0, + "second aio post for \"%V\"", &file->name); + return NGX_AGAIN; + } + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, + "aio complete:%d @%O:%uz %V", + ev->complete, offset, size, &file->name); + + if (ev->complete) { + ev->complete = 0; + ngx_set_errno(aio->err); + + if (aio->err == 0) { + return aio->nbytes; + } + + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "aio read \"%s\" failed", file->name.data); + + return NGX_ERROR; + } + + ngx_memzero(&aio->aiocb, sizeof(struct aiocb)); + + aio->aiocb.aio_fildes = file->fd; + aio->aiocb.aio_offset = offset; + aio->aiocb.aio_buf = buf; + aio->aiocb.aio_nbytes = size; +#if (NGX_HAVE_KQUEUE) + aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue; + aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; + aio->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev; +#endif + ev->handler = ngx_file_aio_event_handler; + + n = aio_read(&aio->aiocb); + + if (n == -1) { + n = ngx_errno; + + if (n == NGX_EAGAIN) { + return ngx_read_file(file, buf, size, offset); + } + + ngx_log_error(NGX_LOG_CRIT, file->log, n, + "aio_read(\"%V\") failed", &file->name); + + if (n == NGX_ENOSYS) { + ngx_file_aio = 0; + return ngx_read_file(file, buf, size, offset); + } + + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, + "aio_read: fd:%d %d", file->fd, n); + + ev->active = 1; + ev->ready = 0; + ev->complete = 0; + + return ngx_file_aio_result(aio->file, aio, ev); +} + + +static ssize_t +ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, ngx_event_t *ev) +{ + int n; + ngx_err_t err; + + n = aio_error(&aio->aiocb); + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, + "aio_error: fd:%d %d", file->fd, n); + + if (n == -1) { + err = ngx_errno; + aio->err = err; + + ngx_log_error(NGX_LOG_ALERT, file->log, err, + "aio_error(\"%V\") failed", &file->name); + return NGX_ERROR; + } + + if (n == NGX_EINPROGRESS) { + if (ev->ready) { + ev->ready = 0; + ngx_log_error(NGX_LOG_ALERT, file->log, n, + "aio_read(\"%V\") still in progress", + &file->name); + } + + return NGX_AGAIN; + } + + n = aio_return(&aio->aiocb); + + if (n == -1) { + err = ngx_errno; + aio->err = err; + ev->ready = 1; + + ngx_log_error(NGX_LOG_CRIT, file->log, err, + "aio_return(\"%V\") failed", &file->name); + return NGX_ERROR; + } + + aio->err = 0; + aio->nbytes = n; + ev->ready = 1; + ev->active = 0; + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0, + "aio_return: fd:%d %d", file->fd, n); + + return n; +} + + +static void +ngx_file_aio_event_handler(ngx_event_t *ev) +{ + ngx_event_aio_t *aio; + + aio = ev->data; + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0, + "aio event handler fd:%d %V", aio->fd, &aio->file->name); + + if (ngx_file_aio_result(aio->file, aio, ev) != NGX_AGAIN) { + aio->handler(ev); + } +} diff --git a/app/nginx/src/os/unix/ngx_files.c b/app/nginx/src/os/unix/ngx_files.c new file mode 100644 index 0000000..7fbb7c9 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_files.c @@ -0,0 +1,906 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#if (NGX_THREADS) +#include <ngx_thread_pool.h> +static void ngx_thread_read_handler(void *data, ngx_log_t *log); +static void ngx_thread_write_chain_to_file_handler(void *data, ngx_log_t *log); +#endif + +static ngx_chain_t *ngx_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *cl); +static ssize_t ngx_writev_file(ngx_file_t *file, ngx_iovec_t *vec, + off_t offset); + + +#if (NGX_HAVE_FILE_AIO) + +ngx_uint_t ngx_file_aio = 1; + +#endif + + +ssize_t +ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) +{ + ssize_t n; + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, + "read: %d, %p, %uz, %O", file->fd, buf, size, offset); + +#if (NGX_HAVE_PREAD) + + n = pread(file->fd, buf, size, offset); + + if (n == -1) { + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "pread() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + +#else + + if (file->sys_offset != offset) { + if (lseek(file->fd, offset, SEEK_SET) == -1) { + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "lseek() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + file->sys_offset = offset; + } + + n = read(file->fd, buf, size); + + if (n == -1) { + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "read() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + file->sys_offset += n; + +#endif + + file->offset += n; + + return n; +} + + +#if (NGX_THREADS) + +typedef struct { + ngx_fd_t fd; + ngx_uint_t write; /* unsigned write:1; */ + + u_char *buf; + size_t size; + ngx_chain_t *chain; + off_t offset; + + size_t nbytes; + ngx_err_t err; +} ngx_thread_file_ctx_t; + + +ssize_t +ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, + ngx_pool_t *pool) +{ + ngx_thread_task_t *task; + ngx_thread_file_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 = file->thread_task; + + if (task == NULL) { + task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_file_ctx_t)); + if (task == NULL) { + return NGX_ERROR; + } + + file->thread_task = task; + } + + ctx = task->ctx; + + if (task->event.complete) { + task->event.complete = 0; + + if (ctx->write) { + ngx_log_error(NGX_LOG_ALERT, file->log, 0, + "invalid thread call, read instead of write"); + return NGX_ERROR; + } + + if (ctx->err) { + ngx_log_error(NGX_LOG_CRIT, file->log, ctx->err, + "pread() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + return ctx->nbytes; + } + + task->handler = ngx_thread_read_handler; + + ctx->write = 0; + + 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_file_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->nbytes = n; + ctx->err = 0; + } + +#if 0 + ngx_time_update(); +#endif + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, log, 0, + "pread: %z (err: %d) 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) +{ + ssize_t n, written; + ngx_err_t err; + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, + "write: %d, %p, %uz, %O", file->fd, buf, size, offset); + + written = 0; + +#if (NGX_HAVE_PWRITE) + + for ( ;; ) { + n = pwrite(file->fd, buf + written, size, offset); + + if (n == -1) { + err = ngx_errno; + + if (err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err, + "pwrite() was interrupted"); + continue; + } + + ngx_log_error(NGX_LOG_CRIT, file->log, err, + "pwrite() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + file->offset += n; + written += n; + + if ((size_t) n == size) { + return written; + } + + offset += n; + size -= n; + } + +#else + + if (file->sys_offset != offset) { + if (lseek(file->fd, offset, SEEK_SET) == -1) { + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "lseek() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + file->sys_offset = offset; + } + + for ( ;; ) { + n = write(file->fd, buf + written, size); + + if (n == -1) { + err = ngx_errno; + + if (err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err, + "write() was interrupted"); + continue; + } + + ngx_log_error(NGX_LOG_CRIT, file->log, err, + "write() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + file->sys_offset += n; + file->offset += n; + written += n; + + if ((size_t) n == size) { + return written; + } + + size -= n; + } +#endif +} + + +ngx_fd_t +ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access) +{ + ngx_fd_t fd; + + fd = open((const char *) name, O_CREAT|O_EXCL|O_RDWR, + access ? access : 0600); + + if (fd != -1 && !persistent) { + (void) unlink((const char *) name); + } + + return fd; +} + + +ssize_t +ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, + ngx_pool_t *pool) +{ + ssize_t total, n; + ngx_iovec_t vec; + struct iovec iovs[NGX_IOVS_PREALLOCATE]; + + /* use pwrite() if there is the only buf in a chain */ + + if (cl->next == NULL) { + return ngx_write_file(file, cl->buf->pos, + (size_t) (cl->buf->last - cl->buf->pos), + offset); + } + + total = 0; + + vec.iovs = iovs; + vec.nalloc = NGX_IOVS_PREALLOCATE; + + do { + /* create the iovec and coalesce the neighbouring bufs */ + cl = ngx_chain_to_iovec(&vec, cl); + + /* use pwrite() if there is the only iovec buffer */ + + if (vec.count == 1) { + n = ngx_write_file(file, (u_char *) iovs[0].iov_base, + iovs[0].iov_len, offset); + + if (n == NGX_ERROR) { + return n; + } + + return total + n; + } + + n = ngx_writev_file(file, &vec, offset); + + if (n == NGX_ERROR) { + return n; + } + + offset += n; + total += n; + + } while (cl); + + return total; +} + + +static ngx_chain_t * +ngx_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *cl) +{ + size_t total, size; + u_char *prev; + ngx_uint_t n; + struct iovec *iov; + + iov = NULL; + prev = NULL; + total = 0; + n = 0; + + for ( /* void */ ; cl; cl = cl->next) { + + if (ngx_buf_special(cl->buf)) { + continue; + } + + size = cl->buf->last - cl->buf->pos; + + if (prev == cl->buf->pos) { + iov->iov_len += size; + + } else { + if (n == vec->nalloc) { + break; + } + + iov = &vec->iovs[n++]; + + iov->iov_base = (void *) cl->buf->pos; + iov->iov_len = size; + } + + prev = cl->buf->pos + size; + total += size; + } + + vec->count = n; + vec->size = total; + + return cl; +} + + +static ssize_t +ngx_writev_file(ngx_file_t *file, ngx_iovec_t *vec, off_t offset) +{ + ssize_t n; + ngx_err_t err; + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, file->log, 0, + "writev: %d, %uz, %O", file->fd, vec->size, offset); + +#if (NGX_HAVE_PWRITEV) + +eintr: + + n = pwritev(file->fd, vec->iovs, vec->count, offset); + + if (n == -1) { + err = ngx_errno; + + if (err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err, + "pwritev() was interrupted"); + goto eintr; + } + + ngx_log_error(NGX_LOG_CRIT, file->log, err, + "pwritev() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + if ((size_t) n != vec->size) { + ngx_log_error(NGX_LOG_CRIT, file->log, 0, + "pwritev() \"%s\" has written only %z of %uz", + file->name.data, n, vec->size); + return NGX_ERROR; + } + +#else + + if (file->sys_offset != offset) { + if (lseek(file->fd, offset, SEEK_SET) == -1) { + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "lseek() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + file->sys_offset = offset; + } + +eintr: + + n = writev(file->fd, vec->iovs, vec->count); + + if (n == -1) { + err = ngx_errno; + + if (err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, file->log, err, + "writev() was interrupted"); + goto eintr; + } + + ngx_log_error(NGX_LOG_CRIT, file->log, err, + "writev() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + if ((size_t) n != vec->size) { + ngx_log_error(NGX_LOG_CRIT, file->log, 0, + "writev() \"%s\" has written only %z of %uz", + file->name.data, n, vec->size); + return NGX_ERROR; + } + + file->sys_offset += n; + +#endif + + file->offset += n; + + return n; +} + + +#if (NGX_THREADS) + +ssize_t +ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, + ngx_pool_t *pool) +{ + ngx_thread_task_t *task; + ngx_thread_file_ctx_t *ctx; + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, file->log, 0, + "thread write chain: %d, %p, %O", + file->fd, cl, offset); + + task = file->thread_task; + + if (task == NULL) { + task = ngx_thread_task_alloc(pool, + sizeof(ngx_thread_file_ctx_t)); + if (task == NULL) { + return NGX_ERROR; + } + + file->thread_task = task; + } + + ctx = task->ctx; + + if (task->event.complete) { + task->event.complete = 0; + + if (!ctx->write) { + ngx_log_error(NGX_LOG_ALERT, file->log, 0, + "invalid thread call, write instead of read"); + return NGX_ERROR; + } + + if (ctx->err || ctx->nbytes == 0) { + ngx_log_error(NGX_LOG_CRIT, file->log, ctx->err, + "pwritev() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + file->offset += ctx->nbytes; + return ctx->nbytes; + } + + task->handler = ngx_thread_write_chain_to_file_handler; + + ctx->write = 1; + + ctx->fd = file->fd; + ctx->chain = cl; + ctx->offset = offset; + + if (file->thread_handler(task, file) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +static void +ngx_thread_write_chain_to_file_handler(void *data, ngx_log_t *log) +{ + ngx_thread_file_ctx_t *ctx = data; + +#if (NGX_HAVE_PWRITEV) + + off_t offset; + ssize_t n; + ngx_err_t err; + ngx_chain_t *cl; + ngx_iovec_t vec; + struct iovec iovs[NGX_IOVS_PREALLOCATE]; + + vec.iovs = iovs; + vec.nalloc = NGX_IOVS_PREALLOCATE; + + cl = ctx->chain; + offset = ctx->offset; + + ctx->nbytes = 0; + ctx->err = 0; + + do { + /* create the iovec and coalesce the neighbouring bufs */ + cl = ngx_chain_to_iovec(&vec, cl); + +eintr: + + n = pwritev(ctx->fd, iovs, vec.count, offset); + + if (n == -1) { + err = ngx_errno; + + if (err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, err, + "pwritev() was interrupted"); + goto eintr; + } + + ctx->err = err; + return; + } + + if ((size_t) n != vec.size) { + ctx->nbytes = 0; + return; + } + + ctx->nbytes += n; + offset += n; + } while (cl); + +#else + + ctx->err = NGX_ENOSYS; + return; + +#endif +} + +#endif /* NGX_THREADS */ + + +ngx_int_t +ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s) +{ + struct timeval tv[2]; + + tv[0].tv_sec = ngx_time(); + tv[0].tv_usec = 0; + tv[1].tv_sec = s; + tv[1].tv_usec = 0; + + if (utimes((char *) name, tv) != -1) { + return NGX_OK; + } + + return NGX_ERROR; +} + + +ngx_int_t +ngx_create_file_mapping(ngx_file_mapping_t *fm) +{ + fm->fd = ngx_open_file(fm->name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, + NGX_FILE_DEFAULT_ACCESS); + if (fm->fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", fm->name); + return NGX_ERROR; + } + + if (ftruncate(fm->fd, fm->size) == -1) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "ftruncate() \"%s\" failed", fm->name); + goto failed; + } + + fm->addr = mmap(NULL, fm->size, PROT_READ|PROT_WRITE, MAP_SHARED, + fm->fd, 0); + if (fm->addr != MAP_FAILED) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "mmap(%uz) \"%s\" failed", fm->size, fm->name); + +failed: + + if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", fm->name); + } + + return NGX_ERROR; +} + + +void +ngx_close_file_mapping(ngx_file_mapping_t *fm) +{ + if (munmap(fm->addr, fm->size) == -1) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "munmap(%uz) \"%s\" failed", fm->size, fm->name); + } + + if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", fm->name); + } +} + + +ngx_int_t +ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir) +{ + dir->dir = opendir((const char *) name->data); + + if (dir->dir == NULL) { + return NGX_ERROR; + } + + dir->valid_info = 0; + + return NGX_OK; +} + + +ngx_int_t +ngx_read_dir(ngx_dir_t *dir) +{ + dir->de = readdir(dir->dir); + + if (dir->de) { +#if (NGX_HAVE_D_TYPE) + dir->type = dir->de->d_type; +#else + dir->type = 0; +#endif + return NGX_OK; + } + + return NGX_ERROR; +} + + +ngx_int_t +ngx_open_glob(ngx_glob_t *gl) +{ + int n; + + n = glob((char *) gl->pattern, 0, NULL, &gl->pglob); + + if (n == 0) { + return NGX_OK; + } + +#ifdef GLOB_NOMATCH + + if (n == GLOB_NOMATCH && gl->test) { + return NGX_OK; + } + +#endif + + return NGX_ERROR; +} + + +ngx_int_t +ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name) +{ + size_t count; + +#ifdef GLOB_NOMATCH + count = (size_t) gl->pglob.gl_pathc; +#else + count = (size_t) gl->pglob.gl_matchc; +#endif + + if (gl->n < count) { + + name->len = (size_t) ngx_strlen(gl->pglob.gl_pathv[gl->n]); + name->data = (u_char *) gl->pglob.gl_pathv[gl->n]; + gl->n++; + + return NGX_OK; + } + + return NGX_DONE; +} + + +void +ngx_close_glob(ngx_glob_t *gl) +{ + globfree(&gl->pglob); +} + + +ngx_err_t +ngx_trylock_fd(ngx_fd_t fd) +{ + struct flock fl; + + ngx_memzero(&fl, sizeof(struct flock)); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + + if (fcntl(fd, F_SETLK, &fl) == -1) { + return ngx_errno; + } + + return 0; +} + + +ngx_err_t +ngx_lock_fd(ngx_fd_t fd) +{ + struct flock fl; + + ngx_memzero(&fl, sizeof(struct flock)); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + + if (fcntl(fd, F_SETLKW, &fl) == -1) { + return ngx_errno; + } + + return 0; +} + + +ngx_err_t +ngx_unlock_fd(ngx_fd_t fd) +{ + struct flock fl; + + ngx_memzero(&fl, sizeof(struct flock)); + fl.l_type = F_UNLCK; + fl.l_whence = SEEK_SET; + + if (fcntl(fd, F_SETLK, &fl) == -1) { + return ngx_errno; + } + + return 0; +} + + +#if (NGX_HAVE_POSIX_FADVISE) && !(NGX_HAVE_F_READAHEAD) + +ngx_int_t +ngx_read_ahead(ngx_fd_t fd, size_t n) +{ + int err; + + err = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL); + + if (err == 0) { + return 0; + } + + ngx_set_errno(err); + return NGX_FILE_ERROR; +} + +#endif + + +#if (NGX_HAVE_O_DIRECT) + +ngx_int_t +ngx_directio_on(ngx_fd_t fd) +{ + int flags; + + flags = fcntl(fd, F_GETFL); + + if (flags == -1) { + return NGX_FILE_ERROR; + } + + return fcntl(fd, F_SETFL, flags | O_DIRECT); +} + + +ngx_int_t +ngx_directio_off(ngx_fd_t fd) +{ + int flags; + + flags = fcntl(fd, F_GETFL); + + if (flags == -1) { + return NGX_FILE_ERROR; + } + + return fcntl(fd, F_SETFL, flags & ~O_DIRECT); +} + +#endif + + +#if (NGX_HAVE_STATFS) + +size_t +ngx_fs_bsize(u_char *name) +{ + struct statfs fs; + + if (statfs((char *) name, &fs) == -1) { + return 512; + } + + if ((fs.f_bsize % 512) != 0) { + return 512; + } + + return (size_t) fs.f_bsize; +} + +#elif (NGX_HAVE_STATVFS) + +size_t +ngx_fs_bsize(u_char *name) +{ + struct statvfs fs; + + if (statvfs((char *) name, &fs) == -1) { + return 512; + } + + if ((fs.f_frsize % 512) != 0) { + return 512; + } + + return (size_t) fs.f_frsize; +} + +#else + +size_t +ngx_fs_bsize(u_char *name) +{ + return 512; +} + +#endif diff --git a/app/nginx/src/os/unix/ngx_files.h b/app/nginx/src/os/unix/ngx_files.h new file mode 100644 index 0000000..07872b1 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_files.h @@ -0,0 +1,395 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_FILES_H_INCLUDED_ +#define _NGX_FILES_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +typedef int ngx_fd_t; +typedef struct stat ngx_file_info_t; +typedef ino_t ngx_file_uniq_t; + + +typedef struct { + u_char *name; + size_t size; + void *addr; + ngx_fd_t fd; + ngx_log_t *log; +} ngx_file_mapping_t; + + +typedef struct { + DIR *dir; + struct dirent *de; + struct stat info; + + unsigned type:8; + unsigned valid_info:1; +} ngx_dir_t; + + +typedef struct { + size_t n; + glob_t pglob; + u_char *pattern; + ngx_log_t *log; + ngx_uint_t test; +} ngx_glob_t; + + +#define NGX_INVALID_FILE -1 +#define NGX_FILE_ERROR -1 + + + +#ifdef __CYGWIN__ + +#ifndef NGX_HAVE_CASELESS_FILESYSTEM +#define NGX_HAVE_CASELESS_FILESYSTEM 1 +#endif + +#define ngx_open_file(name, mode, create, access) \ + open((const char *) name, mode|create|O_BINARY, access) + +#else + +#define ngx_open_file(name, mode, create, access) \ + open((const char *) name, mode|create, access) + +#endif + +#define ngx_open_file_n "open()" + +#define NGX_FILE_RDONLY O_RDONLY +#define NGX_FILE_WRONLY O_WRONLY +#define NGX_FILE_RDWR O_RDWR +#define NGX_FILE_CREATE_OR_OPEN O_CREAT +#define NGX_FILE_OPEN 0 +#define NGX_FILE_TRUNCATE (O_CREAT|O_TRUNC) +#define NGX_FILE_APPEND (O_WRONLY|O_APPEND) +#define NGX_FILE_NONBLOCK O_NONBLOCK + +#if (NGX_HAVE_OPENAT) +#define NGX_FILE_NOFOLLOW O_NOFOLLOW + +#if defined(O_DIRECTORY) +#define NGX_FILE_DIRECTORY O_DIRECTORY +#else +#define NGX_FILE_DIRECTORY 0 +#endif + +#if defined(O_SEARCH) +#define NGX_FILE_SEARCH (O_SEARCH|NGX_FILE_DIRECTORY) + +#elif defined(O_EXEC) +#define NGX_FILE_SEARCH (O_EXEC|NGX_FILE_DIRECTORY) + +#elif (NGX_HAVE_O_PATH) +#define NGX_FILE_SEARCH (O_PATH|O_RDONLY|NGX_FILE_DIRECTORY) + +#else +#define NGX_FILE_SEARCH (O_RDONLY|NGX_FILE_DIRECTORY) +#endif + +#endif /* NGX_HAVE_OPENAT */ + +#define NGX_FILE_DEFAULT_ACCESS 0644 +#define NGX_FILE_OWNER_ACCESS 0600 + + +#define ngx_close_file close +#define ngx_close_file_n "close()" + + +#define ngx_delete_file(name) unlink((const char *) name) +#define ngx_delete_file_n "unlink()" + + +ngx_fd_t ngx_open_tempfile(u_char *name, ngx_uint_t persistent, + ngx_uint_t access); +#define ngx_open_tempfile_n "open()" + + +ssize_t ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset); +#if (NGX_HAVE_PREAD) +#define ngx_read_file_n "pread()" +#else +#define ngx_read_file_n "read()" +#endif + +ssize_t ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, + off_t offset); + +ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *ce, + off_t offset, ngx_pool_t *pool); + + +#define ngx_read_fd read +#define ngx_read_fd_n "read()" + +/* + * we use inlined function instead of simple #define + * because glibc 2.3 sets warn_unused_result attribute for write() + * and in this case gcc 4.3 ignores (void) cast + */ +static ngx_inline ssize_t +ngx_write_fd(ngx_fd_t fd, void *buf, size_t n) +{ + return write(fd, buf, n); +} + +#define ngx_write_fd_n "write()" + + +#define ngx_write_console ngx_write_fd + + +#define ngx_linefeed(p) *p++ = LF; +#define NGX_LINEFEED_SIZE 1 +#define NGX_LINEFEED "\x0a" + + +#define ngx_rename_file(o, n) rename((const char *) o, (const char *) n) +#define ngx_rename_file_n "rename()" + + +#define ngx_change_file_access(n, a) chmod((const char *) n, a) +#define ngx_change_file_access_n "chmod()" + + +ngx_int_t ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s); +#define ngx_set_file_time_n "utimes()" + + +#define ngx_file_info(file, sb) stat((const char *) file, sb) +#define ngx_file_info_n "stat()" + +#define ngx_fd_info(fd, sb) fstat(fd, sb) +#define ngx_fd_info_n "fstat()" + +#define ngx_link_info(file, sb) lstat((const char *) file, sb) +#define ngx_link_info_n "lstat()" + +#define ngx_is_dir(sb) (S_ISDIR((sb)->st_mode)) +#define ngx_is_file(sb) (S_ISREG((sb)->st_mode)) +#define ngx_is_link(sb) (S_ISLNK((sb)->st_mode)) +#define ngx_is_exec(sb) (((sb)->st_mode & S_IXUSR) == S_IXUSR) +#define ngx_file_access(sb) ((sb)->st_mode & 0777) +#define ngx_file_size(sb) (sb)->st_size +#define ngx_file_fs_size(sb) ngx_max((sb)->st_size, (sb)->st_blocks * 512) +#define ngx_file_mtime(sb) (sb)->st_mtime +#define ngx_file_uniq(sb) (sb)->st_ino + + +ngx_int_t ngx_create_file_mapping(ngx_file_mapping_t *fm); +void ngx_close_file_mapping(ngx_file_mapping_t *fm); + + +#define ngx_realpath(p, r) (u_char *) realpath((char *) p, (char *) r) +#define ngx_realpath_n "realpath()" +#define ngx_getcwd(buf, size) (getcwd((char *) buf, size) != NULL) +#define ngx_getcwd_n "getcwd()" +#define ngx_path_separator(c) ((c) == '/') + + +#if defined(PATH_MAX) + +#define NGX_HAVE_MAX_PATH 1 +#define NGX_MAX_PATH PATH_MAX + +#else + +#define NGX_MAX_PATH 4096 + +#endif + + +#define NGX_DIR_MASK_LEN 0 + + +ngx_int_t ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir); +#define ngx_open_dir_n "opendir()" + + +#define ngx_close_dir(d) closedir((d)->dir) +#define ngx_close_dir_n "closedir()" + + +ngx_int_t ngx_read_dir(ngx_dir_t *dir); +#define ngx_read_dir_n "readdir()" + + +#define ngx_create_dir(name, access) mkdir((const char *) name, access) +#define ngx_create_dir_n "mkdir()" + + +#define ngx_delete_dir(name) rmdir((const char *) name) +#define ngx_delete_dir_n "rmdir()" + + +#define ngx_dir_access(a) (a | (a & 0444) >> 2) + + +#define ngx_de_name(dir) ((u_char *) (dir)->de->d_name) +#if (NGX_HAVE_D_NAMLEN) +#define ngx_de_namelen(dir) (dir)->de->d_namlen +#else +#define ngx_de_namelen(dir) ngx_strlen((dir)->de->d_name) +#endif + +static ngx_inline ngx_int_t +ngx_de_info(u_char *name, ngx_dir_t *dir) +{ + dir->type = 0; + return stat((const char *) name, &dir->info); +} + +#define ngx_de_info_n "stat()" +#define ngx_de_link_info(name, dir) lstat((const char *) name, &(dir)->info) +#define ngx_de_link_info_n "lstat()" + +#if (NGX_HAVE_D_TYPE) + +/* + * some file systems (e.g. XFS on Linux and CD9660 on FreeBSD) + * do not set dirent.d_type + */ + +#define ngx_de_is_dir(dir) \ + (((dir)->type) ? ((dir)->type == DT_DIR) : (S_ISDIR((dir)->info.st_mode))) +#define ngx_de_is_file(dir) \ + (((dir)->type) ? ((dir)->type == DT_REG) : (S_ISREG((dir)->info.st_mode))) +#define ngx_de_is_link(dir) \ + (((dir)->type) ? ((dir)->type == DT_LNK) : (S_ISLNK((dir)->info.st_mode))) + +#else + +#define ngx_de_is_dir(dir) (S_ISDIR((dir)->info.st_mode)) +#define ngx_de_is_file(dir) (S_ISREG((dir)->info.st_mode)) +#define ngx_de_is_link(dir) (S_ISLNK((dir)->info.st_mode)) + +#endif + +#define ngx_de_access(dir) (((dir)->info.st_mode) & 0777) +#define ngx_de_size(dir) (dir)->info.st_size +#define ngx_de_fs_size(dir) \ + ngx_max((dir)->info.st_size, (dir)->info.st_blocks * 512) +#define ngx_de_mtime(dir) (dir)->info.st_mtime + + +ngx_int_t ngx_open_glob(ngx_glob_t *gl); +#define ngx_open_glob_n "glob()" +ngx_int_t ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name); +void ngx_close_glob(ngx_glob_t *gl); + + +ngx_err_t ngx_trylock_fd(ngx_fd_t fd); +ngx_err_t ngx_lock_fd(ngx_fd_t fd); +ngx_err_t ngx_unlock_fd(ngx_fd_t fd); + +#define ngx_trylock_fd_n "fcntl(F_SETLK, F_WRLCK)" +#define ngx_lock_fd_n "fcntl(F_SETLKW, F_WRLCK)" +#define ngx_unlock_fd_n "fcntl(F_SETLK, F_UNLCK)" + + +#if (NGX_HAVE_F_READAHEAD) + +#define NGX_HAVE_READ_AHEAD 1 + +#define ngx_read_ahead(fd, n) fcntl(fd, F_READAHEAD, (int) n) +#define ngx_read_ahead_n "fcntl(fd, F_READAHEAD)" + +#elif (NGX_HAVE_POSIX_FADVISE) + +#define NGX_HAVE_READ_AHEAD 1 + +ngx_int_t ngx_read_ahead(ngx_fd_t fd, size_t n); +#define ngx_read_ahead_n "posix_fadvise(POSIX_FADV_SEQUENTIAL)" + +#else + +#define ngx_read_ahead(fd, n) 0 +#define ngx_read_ahead_n "ngx_read_ahead_n" + +#endif + + +#if (NGX_HAVE_O_DIRECT) + +ngx_int_t ngx_directio_on(ngx_fd_t fd); +#define ngx_directio_on_n "fcntl(O_DIRECT)" + +ngx_int_t ngx_directio_off(ngx_fd_t fd); +#define ngx_directio_off_n "fcntl(!O_DIRECT)" + +#elif (NGX_HAVE_F_NOCACHE) + +#define ngx_directio_on(fd) fcntl(fd, F_NOCACHE, 1) +#define ngx_directio_on_n "fcntl(F_NOCACHE, 1)" + +#elif (NGX_HAVE_DIRECTIO) + +#define ngx_directio_on(fd) directio(fd, DIRECTIO_ON) +#define ngx_directio_on_n "directio(DIRECTIO_ON)" + +#else + +#define ngx_directio_on(fd) 0 +#define ngx_directio_on_n "ngx_directio_on_n" + +#endif + +size_t ngx_fs_bsize(u_char *name); + + +#if (NGX_HAVE_OPENAT) + +#define ngx_openat_file(fd, name, mode, create, access) \ + openat(fd, (const char *) name, mode|create, access) + +#define ngx_openat_file_n "openat()" + +#define ngx_file_at_info(fd, name, sb, flag) \ + fstatat(fd, (const char *) name, sb, flag) + +#define ngx_file_at_info_n "fstatat()" + +#define NGX_AT_FDCWD (ngx_fd_t) AT_FDCWD + +#endif + + +#define ngx_stdout STDOUT_FILENO +#define ngx_stderr STDERR_FILENO +#define ngx_set_stderr(fd) dup2(fd, STDERR_FILENO) +#define ngx_set_stderr_n "dup2(STDERR_FILENO)" + + +#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); + +extern ngx_uint_t ngx_file_aio; + +#endif + +#if (NGX_THREADS) +ssize_t ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, + off_t offset, ngx_pool_t *pool); +ssize_t ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, + off_t offset, ngx_pool_t *pool); +#endif + + +#endif /* _NGX_FILES_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_freebsd.h b/app/nginx/src/os/unix/ngx_freebsd.h new file mode 100644 index 0000000..4f93da5 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_freebsd.h @@ -0,0 +1,25 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_FREEBSD_H_INCLUDED_ +#define _NGX_FREEBSD_H_INCLUDED_ + + +void ngx_debug_init(void); +ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + +extern int ngx_freebsd_kern_osreldate; +extern int ngx_freebsd_hw_ncpu; +extern u_long ngx_freebsd_net_inet_tcp_sendspace; + +extern ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; +extern ngx_uint_t ngx_freebsd_use_tcp_nopush; +extern ngx_uint_t ngx_debug_malloc; + + +#endif /* _NGX_FREEBSD_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_freebsd_config.h b/app/nginx/src/os/unix/ngx_freebsd_config.h new file mode 100644 index 0000000..b7da48c --- /dev/null +++ b/app/nginx/src/os/unix/ngx_freebsd_config.h @@ -0,0 +1,123 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_FREEBSD_CONFIG_H_INCLUDED_ +#define _NGX_FREEBSD_CONFIG_H_INCLUDED_ + + +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#include <stdarg.h> +#include <stddef.h> /* offsetof() */ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <pwd.h> +#include <grp.h> +#include <dirent.h> +#include <glob.h> +#include <time.h> +#include <sys/param.h> /* ALIGN() */ +#include <sys/mount.h> /* statfs() */ + +#include <sys/filio.h> /* FIONBIO */ +#include <sys/uio.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <sys/wait.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sched.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> /* TCP_NODELAY, TCP_NOPUSH */ +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/un.h> + +#include <libutil.h> /* setproctitle() before 4.1 */ +#include <osreldate.h> +#include <sys/sysctl.h> + +#include <dlfcn.h> + + +#if __FreeBSD_version < 400017 + +/* + * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA() + */ + +#undef CMSG_SPACE +#define CMSG_SPACE(l) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l)) + +#undef CMSG_LEN +#define CMSG_LEN(l) (ALIGN(sizeof(struct cmsghdr)) + (l)) + +#undef CMSG_DATA +#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr))) + +#endif + + +#include <ngx_auto_config.h> + + +#if (NGX_HAVE_POSIX_SEM) +#include <semaphore.h> +#endif + + +#if (NGX_HAVE_POLL) +#include <poll.h> +#endif + + +#if (NGX_HAVE_KQUEUE) +#include <sys/event.h> +#endif + + +#if (NGX_HAVE_FILE_AIO) +#include <aio.h> +typedef struct aiocb ngx_aiocb_t; +#endif + + +#define NGX_LISTEN_BACKLOG -1 + + +#ifdef __DragonFly__ +#define NGX_KEEPALIVE_FACTOR 1000 +#endif + + +#ifndef IOV_MAX +#define IOV_MAX 1024 +#endif + + +#ifndef NGX_HAVE_INHERITED_NONBLOCK +#define NGX_HAVE_INHERITED_NONBLOCK 1 +#endif + + +#define NGX_HAVE_OS_SPECIFIC_INIT 1 +#define NGX_HAVE_DEBUG_MALLOC 1 + + +extern char **environ; +extern char *malloc_options; + + +#endif /* _NGX_FREEBSD_CONFIG_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_freebsd_init.c b/app/nginx/src/os/unix/ngx_freebsd_init.c new file mode 100644 index 0000000..1823f02 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_freebsd_init.c @@ -0,0 +1,262 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +/* FreeBSD 3.0 at least */ +char ngx_freebsd_kern_ostype[16]; +char ngx_freebsd_kern_osrelease[128]; +int ngx_freebsd_kern_osreldate; +int ngx_freebsd_hw_ncpu; +int ngx_freebsd_kern_ipc_somaxconn; +u_long ngx_freebsd_net_inet_tcp_sendspace; + +/* FreeBSD 4.9 */ +int ngx_freebsd_machdep_hlt_logical_cpus; + + +ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; +ngx_uint_t ngx_freebsd_use_tcp_nopush; + +ngx_uint_t ngx_debug_malloc; + + +static ngx_os_io_t ngx_freebsd_io = { + ngx_unix_recv, + ngx_readv_chain, + ngx_udp_unix_recv, + ngx_unix_send, + ngx_udp_unix_send, + ngx_udp_unix_sendmsg_chain, +#if (NGX_HAVE_SENDFILE) + ngx_freebsd_sendfile_chain, + NGX_IO_SENDFILE +#else + ngx_writev_chain, + 0 +#endif +}; + + +typedef struct { + char *name; + void *value; + size_t size; + ngx_uint_t exists; +} sysctl_t; + + +sysctl_t sysctls[] = { + { "hw.ncpu", + &ngx_freebsd_hw_ncpu, + sizeof(ngx_freebsd_hw_ncpu), 0 }, + + { "machdep.hlt_logical_cpus", + &ngx_freebsd_machdep_hlt_logical_cpus, + sizeof(ngx_freebsd_machdep_hlt_logical_cpus), 0 }, + + { "net.inet.tcp.sendspace", + &ngx_freebsd_net_inet_tcp_sendspace, + sizeof(ngx_freebsd_net_inet_tcp_sendspace), 0 }, + + { "kern.ipc.somaxconn", + &ngx_freebsd_kern_ipc_somaxconn, + sizeof(ngx_freebsd_kern_ipc_somaxconn), 0 }, + + { NULL, NULL, 0, 0 } +}; + + +void +ngx_debug_init(void) +{ +#if (NGX_DEBUG_MALLOC) + +#if __FreeBSD_version >= 500014 && __FreeBSD_version < 1000011 + _malloc_options = "J"; +#elif __FreeBSD_version < 500014 + malloc_options = "J"; +#endif + + ngx_debug_malloc = 1; + +#else + char *mo; + + mo = getenv("MALLOC_OPTIONS"); + + if (mo && ngx_strchr(mo, 'J')) { + ngx_debug_malloc = 1; + } +#endif +} + + +ngx_int_t +ngx_os_specific_init(ngx_log_t *log) +{ + int version; + size_t size; + ngx_err_t err; + ngx_uint_t i; + + size = sizeof(ngx_freebsd_kern_ostype); + if (sysctlbyname("kern.ostype", + ngx_freebsd_kern_ostype, &size, NULL, 0) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sysctlbyname(kern.ostype) failed"); + + if (ngx_errno != NGX_ENOMEM) { + return NGX_ERROR; + } + + ngx_freebsd_kern_ostype[size - 1] = '\0'; + } + + size = sizeof(ngx_freebsd_kern_osrelease); + if (sysctlbyname("kern.osrelease", + ngx_freebsd_kern_osrelease, &size, NULL, 0) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sysctlbyname(kern.osrelease) failed"); + + if (ngx_errno != NGX_ENOMEM) { + return NGX_ERROR; + } + + ngx_freebsd_kern_osrelease[size - 1] = '\0'; + } + + + size = sizeof(int); + if (sysctlbyname("kern.osreldate", + &ngx_freebsd_kern_osreldate, &size, NULL, 0) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sysctlbyname(kern.osreldate) failed"); + return NGX_ERROR; + } + + version = ngx_freebsd_kern_osreldate; + + +#if (NGX_HAVE_SENDFILE) + + /* + * The determination of the sendfile() "nbytes bug" is complex enough. + * There are two sendfile() syscalls: a new #393 has no bug while + * an old #336 has the bug in some versions and has not in others. + * Besides libc_r wrapper also emulates the bug in some versions. + * There is no way to say exactly if syscall #336 in FreeBSD circa 4.6 + * has the bug. We use the algorithm that is correct at least for + * RELEASEs and for syscalls only (not libc_r wrapper). + * + * 4.6.1-RELEASE and below have the bug + * 4.6.2-RELEASE and above have the new syscall + * + * We detect the new sendfile() syscall available at the compile time + * to allow an old binary to run correctly on an updated FreeBSD system. + */ + +#if (__FreeBSD__ == 4 && __FreeBSD_version >= 460102) \ + || __FreeBSD_version == 460002 || __FreeBSD_version >= 500039 + + /* a new syscall without the bug */ + + ngx_freebsd_sendfile_nbytes_bug = 0; + +#else + + /* an old syscall that may have the bug */ + + ngx_freebsd_sendfile_nbytes_bug = 1; + +#endif + +#endif /* NGX_HAVE_SENDFILE */ + + + if ((version < 500000 && version >= 440003) || version >= 500017) { + ngx_freebsd_use_tcp_nopush = 1; + } + + + for (i = 0; sysctls[i].name; i++) { + size = sysctls[i].size; + + if (sysctlbyname(sysctls[i].name, sysctls[i].value, &size, NULL, 0) + == 0) + { + sysctls[i].exists = 1; + continue; + } + + err = ngx_errno; + + if (err == NGX_ENOENT) { + continue; + } + + ngx_log_error(NGX_LOG_ALERT, log, err, + "sysctlbyname(%s) failed", sysctls[i].name); + return NGX_ERROR; + } + + if (ngx_freebsd_machdep_hlt_logical_cpus) { + ngx_ncpu = ngx_freebsd_hw_ncpu / 2; + + } else { + ngx_ncpu = ngx_freebsd_hw_ncpu; + } + + if (version < 600008 && ngx_freebsd_kern_ipc_somaxconn > 32767) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "sysctl kern.ipc.somaxconn must be less than 32768"); + return NGX_ERROR; + } + + ngx_tcp_nodelay_and_tcp_nopush = 1; + + ngx_os_io = ngx_freebsd_io; + + return NGX_OK; +} + + +void +ngx_os_specific_status(ngx_log_t *log) +{ + u_long value; + ngx_uint_t i; + + ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s", + ngx_freebsd_kern_ostype, ngx_freebsd_kern_osrelease); + +#ifdef __DragonFly_version + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "kern.osreldate: %d, built on %d", + ngx_freebsd_kern_osreldate, __DragonFly_version); +#else + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "kern.osreldate: %d, built on %d", + ngx_freebsd_kern_osreldate, __FreeBSD_version); +#endif + + for (i = 0; sysctls[i].name; i++) { + if (sysctls[i].exists) { + if (sysctls[i].size == sizeof(long)) { + value = *(long *) sysctls[i].value; + + } else { + value = *(int *) sysctls[i].value; + } + + ngx_log_error(NGX_LOG_NOTICE, log, 0, "%s: %l", + sysctls[i].name, value); + } + } +} diff --git a/app/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c b/app/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c new file mode 100644 index 0000000..4822e72 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -0,0 +1,333 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +/* + * Although FreeBSD sendfile() allows to pass a header and a trailer, + * it cannot send a header with a part of the file in one packet until + * FreeBSD 5.3. Besides, over the fast ethernet connection sendfile() + * may send the partially filled packets, i.e. the 8 file pages may be sent + * as the 11 full 1460-bytes packets, then one incomplete 324-bytes packet, + * and then again the 11 full 1460-bytes packets. + * + * Therefore we use the TCP_NOPUSH option (similar to Linux's TCP_CORK) + * to postpone the sending - it not only sends a header and the first part of + * the file in one packet, but also sends the file pages in the full packets. + * + * But until FreeBSD 4.5 turning TCP_NOPUSH off does not flush a pending + * data that less than MSS, so that data may be sent with 5 second delay. + * So we do not use TCP_NOPUSH on FreeBSD prior to 4.5, although it can be used + * for non-keepalive HTTP connections. + */ + + +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]; +#if (NGX_HAVE_AIO_SENDFILE) + ngx_uint_t ebusy; + ngx_event_aio_t *aio; +#endif + + wev = c->write; + + if (!wev->ready) { + return in; + } + +#if (NGX_HAVE_KQUEUE) + + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) { + (void) ngx_connection_error(c, wev->kq_errno, + "kevent() reported about an closed connection"); + wev->error = 1; + return NGX_CHAIN_ERROR; + } + +#endif + + /* the maximum limit size is the maximum size_t value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) { + limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; + } + + send = 0; + 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; + + trailer.iovs = trailers; + trailer.nalloc = NGX_IOVS_PREALLOCATE; + + for ( ;; ) { + eintr = 0; +#if (NGX_HAVE_AIO_SENDFILE) + ebusy = 0; +#endif + prev_send = send; + + /* create the header iovec and coalesce the neighbouring bufs */ + + cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); + + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + + send += header.size; + + if (cl && cl->buf->in_file && send < limit) { + file = cl->buf; + + /* coalesce the neighbouring file bufs */ + + file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send); + + send += file_size; + + if (send < limit) { + + /* + * create the trailer iovec and coalesce the neighbouring bufs + */ + + cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send, + c->log); + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + + send += trailer.size; + + } else { + trailer.count = 0; + } + + if (ngx_freebsd_use_tcp_nopush + && c->tcp_nopush == NGX_TCP_NOPUSH_UNSET) + { + if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { + err = ngx_socket_errno; + + /* + * there is a tiny chance to be interrupted, however, + * we continue a processing without the TCP_NOPUSH + */ + + if (err != NGX_EINTR) { + wev->error = 1; + (void) ngx_connection_error(c, err, + ngx_tcp_nopush_n " failed"); + return NGX_CHAIN_ERROR; + } + + } else { + c->tcp_nopush = NGX_TCP_NOPUSH_SET; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "tcp_nopush"); + } + } + + /* + * sendfile() does unneeded work if sf_hdtr's count is 0, + * but corresponding pointer is not NULL + */ + + hdtr.headers = header.count ? header.iovs : NULL; + hdtr.hdr_cnt = header.count; + hdtr.trailers = trailer.count ? trailer.iovs : NULL; + hdtr.trl_cnt = trailer.count; + + /* + * the "nbytes bug" of the old sendfile() syscall: + * http://bugs.freebsd.org/33771 + */ + + if (!ngx_freebsd_sendfile_nbytes_bug) { + header.size = 0; + } + + sent = 0; + +#if (NGX_HAVE_AIO_SENDFILE) + aio = file->file->aio; + flags = (aio && aio->preload_handler) ? SF_NODISKIO : 0; +#endif + + rc = sendfile(file->file->fd, c->fd, file->file_pos, + file_size + header.size, &hdtr, &sent, flags); + + if (rc == -1) { + err = ngx_errno; + + switch (err) { + case NGX_EAGAIN: + eagain = 1; + break; + + case NGX_EINTR: + eintr = 1; + break; + +#if (NGX_HAVE_AIO_SENDFILE) + case NGX_EBUSY: + ebusy = 1; + break; +#endif + + default: + wev->error = 1; + (void) ngx_connection_error(c, err, "sendfile() failed"); + return NGX_CHAIN_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendfile() sent only %O bytes", sent); + + /* + * sendfile() in FreeBSD 3.x-4.x may return value >= 0 + * on success, although only 0 is documented + */ + + } else if (rc >= 0 && sent == 0) { + + /* + * if rc is OK and sent equal to zero, then someone + * has truncated the file, so the offset became beyond + * the end of the file + */ + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfile() reported that \"%s\" was truncated at %O", + file->file->name.data, file->file_pos); + + return NGX_CHAIN_ERROR; + } + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendfile: %d, @%O %O:%uz", + rc, file->file_pos, sent, file_size + header.size); + + } else { + n = ngx_writev(c, &header); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + sent = (n == NGX_AGAIN) ? 0 : n; + } + + c->sent += sent; + + in = ngx_chain_update_sent(in, sent); + +#if (NGX_HAVE_AIO_SENDFILE) + + if (ebusy) { + if (aio->event.active) { + /* + * tolerate duplicate calls; they can happen due to subrequests + * or multiple calls of the next body filter from a filter + */ + + if (sent) { + c->busy_count = 0; + } + + return in; + } + + 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; + } + + n = aio->preload_handler(file); + + if (n > 0) { + send = prev_send + sent; + continue; + } + + return in; + } + + if (flags == SF_NODISKIO) { + c->busy_count = 0; + } + +#endif + + if (eagain) { + + /* + * sendfile() may return EAGAIN, even if it has sent a whole file + * part, it indicates that the successive sendfile() call would + * return EAGAIN right away and would not send anything. + * We use it as a hint. + */ + + wev->ready = 0; + return in; + } + + if (eintr) { + send = prev_send + sent; + continue; + } + + if (send - prev_send != sent) { + wev->ready = 0; + return in; + } + + if (send >= limit || in == NULL) { + return in; + } + } +} diff --git a/app/nginx/src/os/unix/ngx_gcc_atomic_amd64.h b/app/nginx/src/os/unix/ngx_gcc_atomic_amd64.h new file mode 100644 index 0000000..159a297 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_gcc_atomic_amd64.h @@ -0,0 +1,82 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#if (NGX_SMP) +#define NGX_SMP_LOCK "lock;" +#else +#define NGX_SMP_LOCK +#endif + + +/* + * "cmpxchgq r, [m]": + * + * if (rax == [m]) { + * zf = 1; + * [m] = r; + * } else { + * zf = 0; + * rax = [m]; + * } + * + * + * The "r" is any register, %rax (%r0) - %r16. + * The "=a" and "a" are the %rax register. + * Although we can return result in any register, we use "a" because it is + * used in cmpxchgq anyway. The result is actually in %al but not in $rax, + * however as the code is inlined gcc can test %al as well as %rax. + * + * The "cc" means that flags were changed. + */ + +static ngx_inline ngx_atomic_uint_t +ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, + ngx_atomic_uint_t set) +{ + u_char res; + + __asm__ volatile ( + + NGX_SMP_LOCK + " cmpxchgq %3, %1; " + " sete %0; " + + : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory"); + + return res; +} + + +/* + * "xaddq r, [m]": + * + * temp = [m]; + * [m] += r; + * r = temp; + * + * + * The "+r" is any register, %rax (%r0) - %r16. + * The "cc" means that flags were changed. + */ + +static ngx_inline ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) +{ + __asm__ volatile ( + + NGX_SMP_LOCK + " xaddq %0, %1; " + + : "+r" (add) : "m" (*value) : "cc", "memory"); + + return add; +} + + +#define ngx_memory_barrier() __asm__ volatile ("" ::: "memory") + +#define ngx_cpu_pause() __asm__ ("pause") diff --git a/app/nginx/src/os/unix/ngx_gcc_atomic_ppc.h b/app/nginx/src/os/unix/ngx_gcc_atomic_ppc.h new file mode 100644 index 0000000..45afc4b --- /dev/null +++ b/app/nginx/src/os/unix/ngx_gcc_atomic_ppc.h @@ -0,0 +1,155 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +/* + * The ppc assembler treats ";" as comment, so we have to use "\n". + * The minus in "bne-" is a hint for the branch prediction unit that + * this branch is unlikely to be taken. + * The "1b" means the nearest backward label "1" and the "1f" means + * the nearest forward label "1". + * + * The "b" means that the base registers can be used only, i.e. + * any register except r0. The r0 register always has a zero value and + * could not be used in "addi r0, r0, 1". + * The "=&b" means that no input registers can be used. + * + * "sync" read and write barriers + * "isync" read barrier, is faster than "sync" + * "eieio" write barrier, is faster than "sync" + * "lwsync" write barrier, is faster than "eieio" on ppc64 + */ + +#if (NGX_PTR_SIZE == 8) + +static ngx_inline ngx_atomic_uint_t +ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, + ngx_atomic_uint_t set) +{ + ngx_atomic_uint_t res, temp; + + __asm__ volatile ( + + " li %0, 0 \n" /* preset "0" to "res" */ + " lwsync \n" /* write barrier */ + "1: \n" + " ldarx %1, 0, %2 \n" /* load from [lock] into "temp" */ + /* and store reservation */ + " cmpd %1, %3 \n" /* compare "temp" and "old" */ + " bne- 2f \n" /* not equal */ + " stdcx. %4, 0, %2 \n" /* store "set" into [lock] if reservation */ + /* is not cleared */ + " bne- 1b \n" /* the reservation was cleared */ + " isync \n" /* read barrier */ + " li %0, 1 \n" /* set "1" to "res" */ + "2: \n" + + : "=&b" (res), "=&b" (temp) + : "b" (lock), "b" (old), "b" (set) + : "cc", "memory"); + + return res; +} + + +static ngx_inline ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) +{ + ngx_atomic_uint_t res, temp; + + __asm__ volatile ( + + " lwsync \n" /* write barrier */ + "1: ldarx %0, 0, %2 \n" /* load from [value] into "res" */ + /* and store reservation */ + " add %1, %0, %3 \n" /* "res" + "add" store in "temp" */ + " stdcx. %1, 0, %2 \n" /* store "temp" into [value] if reservation */ + /* is not cleared */ + " bne- 1b \n" /* try again if reservation was cleared */ + " isync \n" /* read barrier */ + + : "=&b" (res), "=&b" (temp) + : "b" (value), "b" (add) + : "cc", "memory"); + + return res; +} + + +#if (NGX_SMP) +#define ngx_memory_barrier() \ + __asm__ volatile ("isync \n lwsync \n" ::: "memory") +#else +#define ngx_memory_barrier() __asm__ volatile ("" ::: "memory") +#endif + +#else + +static ngx_inline ngx_atomic_uint_t +ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, + ngx_atomic_uint_t set) +{ + ngx_atomic_uint_t res, temp; + + __asm__ volatile ( + + " li %0, 0 \n" /* preset "0" to "res" */ + " eieio \n" /* write barrier */ + "1: \n" + " lwarx %1, 0, %2 \n" /* load from [lock] into "temp" */ + /* and store reservation */ + " cmpw %1, %3 \n" /* compare "temp" and "old" */ + " bne- 2f \n" /* not equal */ + " stwcx. %4, 0, %2 \n" /* store "set" into [lock] if reservation */ + /* is not cleared */ + " bne- 1b \n" /* the reservation was cleared */ + " isync \n" /* read barrier */ + " li %0, 1 \n" /* set "1" to "res" */ + "2: \n" + + : "=&b" (res), "=&b" (temp) + : "b" (lock), "b" (old), "b" (set) + : "cc", "memory"); + + return res; +} + + +static ngx_inline ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) +{ + ngx_atomic_uint_t res, temp; + + __asm__ volatile ( + + " eieio \n" /* write barrier */ + "1: lwarx %0, 0, %2 \n" /* load from [value] into "res" */ + /* and store reservation */ + " add %1, %0, %3 \n" /* "res" + "add" store in "temp" */ + " stwcx. %1, 0, %2 \n" /* store "temp" into [value] if reservation */ + /* is not cleared */ + " bne- 1b \n" /* try again if reservation was cleared */ + " isync \n" /* read barrier */ + + : "=&b" (res), "=&b" (temp) + : "b" (value), "b" (add) + : "cc", "memory"); + + return res; +} + + +#if (NGX_SMP) +#define ngx_memory_barrier() \ + __asm__ volatile ("isync \n eieio \n" ::: "memory") +#else +#define ngx_memory_barrier() __asm__ volatile ("" ::: "memory") +#endif + +#endif + + +#define ngx_cpu_pause() diff --git a/app/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h b/app/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h new file mode 100644 index 0000000..a84db35 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h @@ -0,0 +1,82 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +/* + * "casa [r1] 0x80, r2, r0" and + * "casxa [r1] 0x80, r2, r0" do the following: + * + * if ([r1] == r2) { + * swap(r0, [r1]); + * } else { + * r0 = [r1]; + * } + * + * so "r0 == r2" means that the operation was successful. + * + * + * The "r" means the general register. + * The "+r" means the general register used for both input and output. + */ + + +#if (NGX_PTR_SIZE == 4) +#define NGX_CASA "casa" +#else +#define NGX_CASA "casxa" +#endif + + +static ngx_inline ngx_atomic_uint_t +ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, + ngx_atomic_uint_t set) +{ + __asm__ volatile ( + + NGX_CASA " [%1] 0x80, %2, %0" + + : "+r" (set) : "r" (lock), "r" (old) : "memory"); + + return (set == old); +} + + +static ngx_inline ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) +{ + ngx_atomic_uint_t old, res; + + old = *value; + + for ( ;; ) { + + res = old + add; + + __asm__ volatile ( + + NGX_CASA " [%1] 0x80, %2, %0" + + : "+r" (res) : "r" (value), "r" (old) : "memory"); + + if (res == old) { + return res; + } + + old = res; + } +} + + +#if (NGX_SMP) +#define ngx_memory_barrier() \ + __asm__ volatile ( \ + "membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad" \ + ::: "memory") +#else +#define ngx_memory_barrier() __asm__ volatile ("" ::: "memory") +#endif + +#define ngx_cpu_pause() diff --git a/app/nginx/src/os/unix/ngx_gcc_atomic_x86.h b/app/nginx/src/os/unix/ngx_gcc_atomic_x86.h new file mode 100644 index 0000000..54e01ae --- /dev/null +++ b/app/nginx/src/os/unix/ngx_gcc_atomic_x86.h @@ -0,0 +1,127 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#if (NGX_SMP) +#define NGX_SMP_LOCK "lock;" +#else +#define NGX_SMP_LOCK +#endif + + +/* + * "cmpxchgl r, [m]": + * + * if (eax == [m]) { + * zf = 1; + * [m] = r; + * } else { + * zf = 0; + * eax = [m]; + * } + * + * + * The "r" means the general register. + * The "=a" and "a" are the %eax register. + * Although we can return result in any register, we use "a" because it is + * used in cmpxchgl anyway. The result is actually in %al but not in %eax, + * however, as the code is inlined gcc can test %al as well as %eax, + * and icc adds "movzbl %al, %eax" by itself. + * + * The "cc" means that flags were changed. + */ + +static ngx_inline ngx_atomic_uint_t +ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, + ngx_atomic_uint_t set) +{ + u_char res; + + __asm__ volatile ( + + NGX_SMP_LOCK + " cmpxchgl %3, %1; " + " sete %0; " + + : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory"); + + return res; +} + + +/* + * "xaddl r, [m]": + * + * temp = [m]; + * [m] += r; + * r = temp; + * + * + * The "+r" means the general register. + * The "cc" means that flags were changed. + */ + + +#if !(( __GNUC__ == 2 && __GNUC_MINOR__ <= 7 ) || ( __INTEL_COMPILER >= 800 )) + +/* + * icc 8.1 and 9.0 compile broken code with -march=pentium4 option: + * ngx_atomic_fetch_add() always return the input "add" value, + * so we use the gcc 2.7 version. + * + * icc 8.1 and 9.0 with -march=pentiumpro option or icc 7.1 compile + * correct code. + */ + +static ngx_inline ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) +{ + __asm__ volatile ( + + NGX_SMP_LOCK + " xaddl %0, %1; " + + : "+r" (add) : "m" (*value) : "cc", "memory"); + + return add; +} + + +#else + +/* + * gcc 2.7 does not support "+r", so we have to use the fixed + * %eax ("=a" and "a") and this adds two superfluous instructions in the end + * of code, something like this: "mov %eax, %edx / mov %edx, %eax". + */ + +static ngx_inline ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) +{ + ngx_atomic_uint_t old; + + __asm__ volatile ( + + NGX_SMP_LOCK + " xaddl %2, %1; " + + : "=a" (old) : "m" (*value), "a" (add) : "cc", "memory"); + + return old; +} + +#endif + + +/* + * on x86 the write operations go in a program order, so we need only + * to disable the gcc reorder optimizations + */ + +#define ngx_memory_barrier() __asm__ volatile ("" ::: "memory") + +/* old "as" does not support "pause" opcode */ +#define ngx_cpu_pause() __asm__ (".byte 0xf3, 0x90") diff --git a/app/nginx/src/os/unix/ngx_linux.h b/app/nginx/src/os/unix/ngx_linux.h new file mode 100644 index 0000000..13d654e --- /dev/null +++ b/app/nginx/src/os/unix/ngx_linux.h @@ -0,0 +1,16 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_LINUX_H_INCLUDED_ +#define _NGX_LINUX_H_INCLUDED_ + + +ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + + +#endif /* _NGX_LINUX_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_linux_aio_read.c b/app/nginx/src/os/unix/ngx_linux_aio_read.c new file mode 100644 index 0000000..9f0a6c1 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_linux_aio_read.c @@ -0,0 +1,148 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +extern int ngx_eventfd; +extern aio_context_t ngx_aio_ctx; + + +static void ngx_file_aio_event_handler(ngx_event_t *ev); + + +static int +io_submit(aio_context_t ctx, long n, struct iocb **paiocb) +{ + return syscall(SYS_io_submit, ctx, n, 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) +{ + ngx_err_t err; + struct iocb *piocb[1]; + ngx_event_t *ev; + ngx_event_aio_t *aio; + + if (!ngx_file_aio) { + return ngx_read_file(file, buf, size, offset); + } + + if (file->aio == NULL && ngx_file_aio_init(file, pool) != NGX_OK) { + return NGX_ERROR; + } + + aio = file->aio; + ev = &aio->event; + + if (!ev->ready) { + ngx_log_error(NGX_LOG_ALERT, file->log, 0, + "second aio post for \"%V\"", &file->name); + return NGX_AGAIN; + } + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, + "aio complete:%d @%O:%uz %V", + ev->complete, offset, size, &file->name); + + if (ev->complete) { + ev->active = 0; + ev->complete = 0; + + if (aio->res >= 0) { + ngx_set_errno(0); + return aio->res; + } + + ngx_set_errno(-aio->res); + + ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, + "aio read \"%s\" failed", file->name.data); + + return NGX_ERROR; + } + + ngx_memzero(&aio->aiocb, sizeof(struct iocb)); + + aio->aiocb.aio_data = (uint64_t) (uintptr_t) ev; + aio->aiocb.aio_lio_opcode = IOCB_CMD_PREAD; + aio->aiocb.aio_fildes = file->fd; + aio->aiocb.aio_buf = (uint64_t) (uintptr_t) buf; + aio->aiocb.aio_nbytes = size; + aio->aiocb.aio_offset = offset; + aio->aiocb.aio_flags = IOCB_FLAG_RESFD; + aio->aiocb.aio_resfd = ngx_eventfd; + + ev->handler = ngx_file_aio_event_handler; + + piocb[0] = &aio->aiocb; + + if (io_submit(ngx_aio_ctx, 1, piocb) == 1) { + ev->active = 1; + ev->ready = 0; + ev->complete = 0; + + return NGX_AGAIN; + } + + err = ngx_errno; + + if (err == NGX_EAGAIN) { + return ngx_read_file(file, buf, size, offset); + } + + ngx_log_error(NGX_LOG_CRIT, file->log, err, + "io_submit(\"%V\") failed", &file->name); + + if (err == NGX_ENOSYS) { + ngx_file_aio = 0; + return ngx_read_file(file, buf, size, offset); + } + + return NGX_ERROR; +} + + +static void +ngx_file_aio_event_handler(ngx_event_t *ev) +{ + ngx_event_aio_t *aio; + + aio = ev->data; + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0, + "aio event handler fd:%d %V", aio->fd, &aio->file->name); + + aio->handler(ev); +} diff --git a/app/nginx/src/os/unix/ngx_linux_config.h b/app/nginx/src/os/unix/ngx_linux_config.h new file mode 100644 index 0000000..2f6129d --- /dev/null +++ b/app/nginx/src/os/unix/ngx_linux_config.h @@ -0,0 +1,123 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_LINUX_CONFIG_H_INCLUDED_ +#define _NGX_LINUX_CONFIG_H_INCLUDED_ + + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* pread(), pwrite(), gethostname() */ +#endif + +#define _FILE_OFFSET_BITS 64 + +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#include <stdarg.h> +#include <stddef.h> /* offsetof() */ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <pwd.h> +#include <grp.h> +#include <dirent.h> +#include <glob.h> +#include <sys/vfs.h> /* statfs() */ + +#include <sys/uio.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <sys/wait.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sched.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> /* TCP_NODELAY, TCP_CORK */ +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/un.h> + +#include <time.h> /* tzset() */ +#include <malloc.h> /* memalign() */ +#include <limits.h> /* IOV_MAX */ +#include <sys/ioctl.h> +#include <crypt.h> +#include <sys/utsname.h> /* uname() */ + +#include <dlfcn.h> + + +#include <ngx_auto_config.h> + + +#if (NGX_HAVE_POSIX_SEM) +#include <semaphore.h> +#endif + + +#if (NGX_HAVE_SYS_PRCTL_H) +#include <sys/prctl.h> +#endif + + +#if (NGX_HAVE_SENDFILE64) +#include <sys/sendfile.h> +#else +extern ssize_t sendfile(int s, int fd, int32_t *offset, size_t size); +#define NGX_SENDFILE_LIMIT 0x80000000 +#endif + + +#if (NGX_HAVE_POLL) +#include <poll.h> +#endif + + +#if (NGX_HAVE_EPOLL) +#include <sys/epoll.h> +#endif + + +#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 + + +#define NGX_LISTEN_BACKLOG 511 + + +#ifndef NGX_HAVE_SO_SNDLOWAT +/* setsockopt(SO_SNDLOWAT) returns ENOPROTOOPT */ +#define NGX_HAVE_SO_SNDLOWAT 0 +#endif + + +#ifndef NGX_HAVE_INHERITED_NONBLOCK +#define NGX_HAVE_INHERITED_NONBLOCK 0 +#endif + + +#define NGX_HAVE_OS_SPECIFIC_INIT 1 +#define ngx_debug_init() + + +extern char **environ; + + +#endif /* _NGX_LINUX_CONFIG_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_linux_init.c b/app/nginx/src/os/unix/ngx_linux_init.c new file mode 100644 index 0000000..a8cf6a0 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_linux_init.c @@ -0,0 +1,60 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +u_char ngx_linux_kern_ostype[50]; +u_char ngx_linux_kern_osrelease[50]; + + +static ngx_os_io_t ngx_linux_io = { + ngx_unix_recv, + ngx_readv_chain, + ngx_udp_unix_recv, + ngx_unix_send, + ngx_udp_unix_send, + ngx_udp_unix_sendmsg_chain, +#if (NGX_HAVE_SENDFILE) + ngx_linux_sendfile_chain, + NGX_IO_SENDFILE +#else + ngx_writev_chain, + 0 +#endif +}; + + +ngx_int_t +ngx_os_specific_init(ngx_log_t *log) +{ + struct utsname u; + + if (uname(&u) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "uname() failed"); + return NGX_ERROR; + } + + (void) ngx_cpystrn(ngx_linux_kern_ostype, (u_char *) u.sysname, + sizeof(ngx_linux_kern_ostype)); + + (void) ngx_cpystrn(ngx_linux_kern_osrelease, (u_char *) u.release, + sizeof(ngx_linux_kern_osrelease)); + + ngx_os_io = ngx_linux_io; + + return NGX_OK; +} + + +void +ngx_os_specific_status(ngx_log_t *log) +{ + ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s", + ngx_linux_kern_ostype, ngx_linux_kern_osrelease); +} diff --git a/app/nginx/src/os/unix/ngx_linux_sendfile_chain.c b/app/nginx/src/os/unix/ngx_linux_sendfile_chain.c new file mode 100644 index 0000000..b44724c --- /dev/null +++ b/app/nginx/src/os/unix/ngx_linux_sendfile_chain.c @@ -0,0 +1,442 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#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 ssize_t ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, + size_t size); +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, + * if off_t is 64 bit wide. So we use own sendfile() definition, where offset + * parameter is int32_t, and use sendfile() for the file parts below 2G only, + * see src/os/unix/ngx_linux_config.h + * + * Linux 2.4.21 has the new sendfile64() syscall #239. + * + * On Linux up to 2.6.16 sendfile() does not allow to pass the count parameter + * more than 2G-1 bytes even on 64-bit platforms: it returns EINVAL, + * so we limit it to 2G-1 bytes. + */ + +#define NGX_SENDFILE_MAXSIZE 2147483647L + + +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; + size_t file_size, sent; + ssize_t n; + ngx_err_t err; + ngx_buf_t *file; + ngx_event_t *wev; + ngx_chain_t *cl; + ngx_iovec_t header; + struct iovec headers[NGX_IOVS_PREALLOCATE]; + + wev = c->write; + + if (!wev->ready) { + return in; + } + + + /* the maximum limit size is 2G-1 - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_SENDFILE_MAXSIZE - ngx_pagesize)) { + limit = NGX_SENDFILE_MAXSIZE - ngx_pagesize; + } + + + send = 0; + + header.iovs = headers; + header.nalloc = NGX_IOVS_PREALLOCATE; + + for ( ;; ) { + prev_send = send; + + /* create the iovec and coalesce the neighbouring bufs */ + + cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); + + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + + send += header.size; + + /* set TCP_CORK if there is a header before a file */ + + if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET + && header.count != 0 + && cl + && cl->buf->in_file) + { + /* the TCP_CORK and TCP_NODELAY are mutually exclusive */ + + if (c->tcp_nodelay == NGX_TCP_NODELAY_SET) { + + tcp_nodelay = 0; + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) == -1) + { + err = ngx_socket_errno; + + /* + * there is a tiny chance to be interrupted, however, + * we continue a processing with the TCP_NODELAY + * and without the TCP_CORK + */ + + if (err != NGX_EINTR) { + wev->error = 1; + ngx_connection_error(c, err, + "setsockopt(TCP_NODELAY) failed"); + return NGX_CHAIN_ERROR; + } + + } else { + c->tcp_nodelay = NGX_TCP_NODELAY_UNSET; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "no tcp_nodelay"); + } + } + + if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + + if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { + err = ngx_socket_errno; + + /* + * there is a tiny chance to be interrupted, however, + * we continue a processing without the TCP_CORK + */ + + if (err != NGX_EINTR) { + wev->error = 1; + ngx_connection_error(c, err, + ngx_tcp_nopush_n " failed"); + return NGX_CHAIN_ERROR; + } + + } else { + c->tcp_nopush = NGX_TCP_NOPUSH_SET; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "tcp_nopush"); + } + } + } + + /* get the file buf */ + + if (header.count == 0 && cl && cl->buf->in_file && send < limit) { + file = cl->buf; + + /* coalesce the neighbouring file bufs */ + + file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send); + + send += file_size; +#if 1 + if (file_size == 0) { + ngx_debug_point(); + return NGX_CHAIN_ERROR; + } +#endif + + n = ngx_linux_sendfile(c, file, file_size); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (n == NGX_DONE) { + /* thread task posted */ + return in; + } + + sent = (n == NGX_AGAIN) ? 0 : n; + + } else { + n = ngx_writev(c, &header); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + sent = (n == NGX_AGAIN) ? 0 : n; + } + + c->sent += sent; + + in = ngx_chain_update_sent(in, sent); + + if (n == NGX_AGAIN) { + wev->ready = 0; + return in; + } + + if ((size_t) (send - prev_send) != sent) { + + /* + * sendfile() on Linux 4.3+ might be interrupted at any time, + * and provides no indication if it was interrupted or not, + * so we have to retry till an explicit EAGAIN + * + * sendfile() in threads can also report less bytes written + * than we are prepared to send now, since it was started in + * some point in the past, so we again have to retry + */ + + send = prev_send + sent; + continue; + } + + if (send >= limit || in == NULL) { + return in; + } + } +} + + +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_THREADS) + + if (file->file->thread_handler) { + return ngx_linux_sendfile_thread(c, file, size); + } + +#endif + +#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; + } + } + + if (n == 0) { + /* + * if sendfile returns zero, then someone has truncated the file, + * so the offset became beyond the end of the file + */ + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfile() reported that \"%s\" was truncated at %O", + file->file->name.data, file->file_pos); + + 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 ssize_t +ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size) +{ + 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 == NGX_EAGAIN) { + /* + * if wev->complete is set, this means that a write event + * happened while we were waiting for the thread task, so + * we have to retry sending even on EAGAIN + */ + + if (wev->complete) { + return 0; + } + + return NGX_AGAIN; + } + + if (ctx->err) { + wev->error = 1; + ngx_connection_error(c, ctx->err, "sendfile() failed"); + return NGX_ERROR; + } + + if (ctx->sent == 0) { + /* + * if sendfile returns zero, then someone has truncated the file, + * so the offset became beyond the end of the file + */ + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfile() reported that \"%s\" was truncated at %O", + file->file->name.data, file->file_pos); + + return NGX_ERROR; + } + + return ctx->sent; + } + + if (task->event.active && ctx->file == file) { + /* + * tolerate duplicate calls; they can happen due to subrequests + * or multiple calls of the next body filter from a filter + */ + + return NGX_DONE; + } + + ctx->file = file; + ctx->socket = c->fd; + ctx->size = size; + + wev->complete = 0; + + if (file->file->thread_handler(task, file->file) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_DONE; +} + + +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: %d) of %uz @%O", + n, ctx->err, ctx->size, file->file_pos); + + if (ctx->err == NGX_EINTR) { + goto again; + } +} + +#endif /* NGX_THREADS */ diff --git a/app/nginx/src/os/unix/ngx_os.h b/app/nginx/src/os/unix/ngx_os.h new file mode 100644 index 0000000..3b32819 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_os.h @@ -0,0 +1,102 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_OS_H_INCLUDED_ +#define _NGX_OS_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define NGX_IO_SENDFILE 1 + + +typedef ssize_t (*ngx_recv_pt)(ngx_connection_t *c, u_char *buf, size_t size); +typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); +typedef ssize_t (*ngx_send_pt)(ngx_connection_t *c, u_char *buf, size_t size); +typedef ngx_chain_t *(*ngx_send_chain_pt)(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + +typedef struct { + ngx_recv_pt recv; + ngx_recv_chain_pt recv_chain; + ngx_recv_pt udp_recv; + ngx_send_pt send; + ngx_send_pt udp_send; + ngx_send_chain_pt udp_send_chain; + ngx_send_chain_pt send_chain; + ngx_uint_t flags; +} ngx_os_io_t; + + +ngx_int_t ngx_os_init(ngx_log_t *log); +void ngx_os_status(ngx_log_t *log); +ngx_int_t ngx_os_specific_init(ngx_log_t *log); +void ngx_os_specific_status(ngx_log_t *log); +ngx_int_t ngx_daemon(ngx_log_t *log); +ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_pid_t pid); + + +ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry, off_t limit); +ssize_t ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size); +ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); +ssize_t ngx_udp_unix_send(ngx_connection_t *c, u_char *buf, size_t size); +ngx_chain_t *ngx_udp_unix_sendmsg_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + + +#if (IOV_MAX > 64) +#define NGX_IOVS_PREALLOCATE 64 +#else +#define NGX_IOVS_PREALLOCATE IOV_MAX +#endif + + +typedef struct { + struct iovec *iovs; + ngx_uint_t count; + size_t size; + ngx_uint_t nalloc; +} ngx_iovec_t; + +ngx_chain_t *ngx_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, + size_t limit, ngx_log_t *log); + + +ssize_t ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec); + + +extern ngx_os_io_t ngx_os_io; +extern ngx_int_t ngx_ncpu; +extern ngx_int_t ngx_max_sockets; +extern ngx_uint_t ngx_inherited_nonblocking; +extern ngx_uint_t ngx_tcp_nodelay_and_tcp_nopush; + + +#if (NGX_FREEBSD) +#include <ngx_freebsd.h> + + +#elif (NGX_LINUX) +#include <ngx_linux.h> + + +#elif (NGX_SOLARIS) +#include <ngx_solaris.h> + + +#elif (NGX_DARWIN) +#include <ngx_darwin.h> +#endif + + +#endif /* _NGX_OS_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_posix_config.h b/app/nginx/src/os/unix/ngx_posix_config.h new file mode 100644 index 0000000..5d1358e --- /dev/null +++ b/app/nginx/src/os/unix/ngx_posix_config.h @@ -0,0 +1,171 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_POSIX_CONFIG_H_INCLUDED_ +#define _NGX_POSIX_CONFIG_H_INCLUDED_ + + +#if (NGX_HPUX) +#define _XOPEN_SOURCE +#define _XOPEN_SOURCE_EXTENDED 1 +#define _HPUX_ALT_XOPEN_SOCKET_API +#endif + + +#if (NGX_TRU64) +#define _REENTRANT +#endif + + +#if (NGX_GNU_HURD) +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* accept4() */ +#endif +#define _FILE_OFFSET_BITS 64 +#endif + + +#ifdef __CYGWIN__ +#define timezonevar /* timezone is variable */ +#define NGX_BROKEN_SCM_RIGHTS 1 +#endif + + +#include <sys/types.h> +#include <sys/time.h> +#if (NGX_HAVE_UNISTD_H) +#include <unistd.h> +#endif +#if (NGX_HAVE_INTTYPES_H) +#include <inttypes.h> +#endif +#include <stdarg.h> +#include <stddef.h> /* offsetof() */ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <pwd.h> +#include <grp.h> +#include <dirent.h> +#include <glob.h> +#include <time.h> +#if (NGX_HAVE_SYS_PARAM_H) +#include <sys/param.h> /* statfs() */ +#endif +#if (NGX_HAVE_SYS_MOUNT_H) +#include <sys/mount.h> /* statfs() */ +#endif +#if (NGX_HAVE_SYS_STATVFS_H) +#include <sys/statvfs.h> /* statvfs() */ +#endif + +#if (NGX_HAVE_SYS_FILIO_H) +#include <sys/filio.h> /* FIONBIO */ +#endif +#include <sys/ioctl.h> /* FIONBIO */ + +#include <sys/uio.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <sys/wait.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sched.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> /* TCP_NODELAY */ +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/un.h> + +#if (NGX_HAVE_LIMITS_H) +#include <limits.h> /* IOV_MAX */ +#endif + +#ifdef __CYGWIN__ +#include <malloc.h> /* memalign() */ +#endif + +#if (NGX_HAVE_CRYPT_H) +#include <crypt.h> +#endif + + +#ifndef IOV_MAX +#define IOV_MAX 16 +#endif + + +#include <ngx_auto_config.h> + + +#if (NGX_HAVE_DLOPEN) +#include <dlfcn.h> +#endif + + +#if (NGX_HAVE_POSIX_SEM) +#include <semaphore.h> +#endif + + +#if (NGX_HAVE_POLL) +#include <poll.h> +#endif + + +#if (NGX_HAVE_KQUEUE) +#include <sys/event.h> +#endif + + +#if (NGX_HAVE_DEVPOLL) && !(NGX_TEST_BUILD_DEVPOLL) +#include <sys/ioctl.h> +#include <sys/devpoll.h> +#endif + + +#if (NGX_HAVE_FILE_AIO) +#include <aio.h> +typedef struct aiocb ngx_aiocb_t; +#endif + + +#define NGX_LISTEN_BACKLOG 511 + +#define ngx_debug_init() + + +#if (__FreeBSD__) && (__FreeBSD_version < 400017) + +#include <sys/param.h> /* ALIGN() */ + +/* + * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA() + */ + +#undef CMSG_SPACE +#define CMSG_SPACE(l) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l)) + +#undef CMSG_LEN +#define CMSG_LEN(l) (ALIGN(sizeof(struct cmsghdr)) + (l)) + +#undef CMSG_DATA +#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr))) + +#endif + + +extern char **environ; + + +#endif /* _NGX_POSIX_CONFIG_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_posix_init.c b/app/nginx/src/os/unix/ngx_posix_init.c new file mode 100644 index 0000000..583ea4f --- /dev/null +++ b/app/nginx/src/os/unix/ngx_posix_init.c @@ -0,0 +1,134 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <nginx.h> + + +ngx_int_t ngx_ncpu; +ngx_int_t ngx_max_sockets; +ngx_uint_t ngx_inherited_nonblocking; +ngx_uint_t ngx_tcp_nodelay_and_tcp_nopush; + + +struct rlimit rlmt; + + +ngx_os_io_t ngx_os_io = { + ngx_unix_recv, + ngx_readv_chain, + ngx_udp_unix_recv, + ngx_unix_send, + ngx_udp_unix_send, + ngx_udp_unix_sendmsg_chain, + ngx_writev_chain, + 0 +}; + + +ngx_int_t +ngx_os_init(ngx_log_t *log) +{ + ngx_time_t *tp; + ngx_uint_t n; + +#if (NGX_HAVE_OS_SPECIFIC_INIT) + if (ngx_os_specific_init(log) != NGX_OK) { + return NGX_ERROR; + } +#endif + + if (ngx_init_setproctitle(log) != NGX_OK) { + return NGX_ERROR; + } + + ngx_pagesize = getpagesize(); + ngx_cacheline_size = NGX_CPU_CACHE_LINE; + + for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ } + +#if (NGX_HAVE_SC_NPROCESSORS_ONLN) + if (ngx_ncpu == 0) { + ngx_ncpu = sysconf(_SC_NPROCESSORS_ONLN); + } +#endif + + if (ngx_ncpu < 1) { + ngx_ncpu = 1; + } + + ngx_cpuinfo(); + + if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, errno, + "getrlimit(RLIMIT_NOFILE) failed"); + return NGX_ERROR; + } + + ngx_max_sockets = (ngx_int_t) rlmt.rlim_cur; + +#if (NGX_HAVE_INHERITED_NONBLOCK || NGX_HAVE_ACCEPT4) + ngx_inherited_nonblocking = 1; +#else + ngx_inherited_nonblocking = 0; +#endif + + tp = ngx_timeofday(); + srandom(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec); + + return NGX_OK; +} + + +void +ngx_os_status(ngx_log_t *log) +{ + ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER_BUILD); + +#ifdef NGX_COMPILER + ngx_log_error(NGX_LOG_NOTICE, log, 0, "built by " NGX_COMPILER); +#endif + +#if (NGX_HAVE_OS_SPECIFIC_INIT) + ngx_os_specific_status(log); +#endif + + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "getrlimit(RLIMIT_NOFILE): %r:%r", + rlmt.rlim_cur, rlmt.rlim_max); +} + + +#if 0 + +ngx_int_t +ngx_posix_post_conf_init(ngx_log_t *log) +{ + ngx_fd_t pp[2]; + + if (pipe(pp) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "pipe() failed"); + return NGX_ERROR; + } + + if (dup2(pp[1], STDERR_FILENO) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, errno, "dup2(STDERR) failed"); + return NGX_ERROR; + } + + if (pp[1] > STDERR_FILENO) { + if (close(pp[1]) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, errno, "close() failed"); + return NGX_ERROR; + } + } + + return NGX_OK; +} + +#endif diff --git a/app/nginx/src/os/unix/ngx_process.c b/app/nginx/src/os/unix/ngx_process.c new file mode 100644 index 0000000..2d37e21 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_process.c @@ -0,0 +1,630 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> +#include <ngx_channel.h> + + +typedef struct { + int signo; + char *signame; + char *name; + void (*handler)(int signo); +} ngx_signal_t; + + + +static void ngx_execute_proc(ngx_cycle_t *cycle, void *data); +static void ngx_signal_handler(int signo); +static void ngx_process_get_status(void); +static void ngx_unlock_mutexes(ngx_pid_t pid); + + +int ngx_argc; +char **ngx_argv; +char **ngx_os_argv; + +ngx_int_t ngx_process_slot; +ngx_socket_t ngx_channel; +ngx_int_t ngx_last_process; +ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; + + +ngx_signal_t signals[] = { + { ngx_signal_value(NGX_RECONFIGURE_SIGNAL), + "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL), + "reload", + ngx_signal_handler }, + + { ngx_signal_value(NGX_REOPEN_SIGNAL), + "SIG" ngx_value(NGX_REOPEN_SIGNAL), + "reopen", + ngx_signal_handler }, + + { ngx_signal_value(NGX_NOACCEPT_SIGNAL), + "SIG" ngx_value(NGX_NOACCEPT_SIGNAL), + "", + ngx_signal_handler }, + + { ngx_signal_value(NGX_TERMINATE_SIGNAL), + "SIG" ngx_value(NGX_TERMINATE_SIGNAL), + "stop", + ngx_signal_handler }, + + { ngx_signal_value(NGX_SHUTDOWN_SIGNAL), + "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL), + "quit", + ngx_signal_handler }, + + { ngx_signal_value(NGX_CHANGEBIN_SIGNAL), + "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL), + "", + ngx_signal_handler }, + + { SIGALRM, "SIGALRM", "", ngx_signal_handler }, + + { SIGINT, "SIGINT", "", ngx_signal_handler }, + + { SIGIO, "SIGIO", "", ngx_signal_handler }, + + { SIGCHLD, "SIGCHLD", "", ngx_signal_handler }, + + { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN }, + + { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN }, + + { 0, NULL, "", NULL } +}; + + +ngx_pid_t +ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, + char *name, ngx_int_t respawn) +{ + u_long on; + ngx_pid_t pid; + ngx_int_t s; + + if (respawn >= 0) { + s = respawn; + + } else { + for (s = 0; s < ngx_last_process; s++) { + if (ngx_processes[s].pid == -1) { + break; + } + } + + if (s == NGX_MAX_PROCESSES) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "no more than %d processes can be spawned", + NGX_MAX_PROCESSES); + return NGX_INVALID_PID; + } + } + + + if (respawn != NGX_PROCESS_DETACHED) { + + /* Solaris 9 still has no AF_LOCAL */ + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "socketpair() failed while spawning \"%s\"", name); + return NGX_INVALID_PID; + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "channel %d:%d", + ngx_processes[s].channel[0], + ngx_processes[s].channel[1]); + + if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_nonblocking_n " failed while spawning \"%s\"", + name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_nonblocking_n " failed while spawning \"%s\"", + name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + on = 1; + if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "ioctl(FIOASYNC) failed while spawning \"%s\"", name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "fcntl(F_SETOWN) failed while spawning \"%s\"", name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "fcntl(FD_CLOEXEC) failed while spawning \"%s\"", + name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "fcntl(FD_CLOEXEC) failed while spawning \"%s\"", + name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + ngx_channel = ngx_processes[s].channel[1]; + + } else { + ngx_processes[s].channel[0] = -1; + ngx_processes[s].channel[1] = -1; + } + + ngx_process_slot = s; + + + pid = fork(); + + switch (pid) { + + case -1: + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "fork() failed while spawning \"%s\"", name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + + case 0: + ngx_pid = ngx_getpid(); + proc(cycle, data); + break; + + default: + break; + } + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid); + + ngx_processes[s].pid = pid; + ngx_processes[s].exited = 0; + + if (respawn >= 0) { + return pid; + } + + ngx_processes[s].proc = proc; + ngx_processes[s].data = data; + ngx_processes[s].name = name; + ngx_processes[s].exiting = 0; + + switch (respawn) { + + case NGX_PROCESS_NORESPAWN: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 0; + ngx_processes[s].detached = 0; + break; + + case NGX_PROCESS_JUST_SPAWN: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 1; + ngx_processes[s].detached = 0; + break; + + case NGX_PROCESS_RESPAWN: + ngx_processes[s].respawn = 1; + ngx_processes[s].just_spawn = 0; + ngx_processes[s].detached = 0; + break; + + case NGX_PROCESS_JUST_RESPAWN: + ngx_processes[s].respawn = 1; + ngx_processes[s].just_spawn = 1; + ngx_processes[s].detached = 0; + break; + + case NGX_PROCESS_DETACHED: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 0; + ngx_processes[s].detached = 1; + break; + } + + if (s == ngx_last_process) { + ngx_last_process++; + } + + return pid; +} + + +ngx_pid_t +ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx) +{ + return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name, + NGX_PROCESS_DETACHED); +} + + +static void +ngx_execute_proc(ngx_cycle_t *cycle, void *data) +{ + ngx_exec_ctx_t *ctx = data; + + if (execve(ctx->path, ctx->argv, ctx->envp) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "execve() failed while executing %s \"%s\"", + ctx->name, ctx->path); + } + + exit(1); +} + + +ngx_int_t +ngx_init_signals(ngx_log_t *log) +{ + ngx_signal_t *sig; + struct sigaction sa; + + for (sig = signals; sig->signo != 0; sig++) { + ngx_memzero(&sa, sizeof(struct sigaction)); + sa.sa_handler = sig->handler; + sigemptyset(&sa.sa_mask); + if (sigaction(sig->signo, &sa, NULL) == -1) { +#if (NGX_VALGRIND) + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sigaction(%s) failed, ignored", sig->signame); +#else + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "sigaction(%s) failed", sig->signame); + return NGX_ERROR; +#endif + } + } + + return NGX_OK; +} + + +static void +ngx_signal_handler(int signo) +{ + char *action; + ngx_int_t ignore; + ngx_err_t err; + ngx_signal_t *sig; + + ignore = 0; + + err = ngx_errno; + + for (sig = signals; sig->signo != 0; sig++) { + if (sig->signo == signo) { + break; + } + } + + ngx_time_sigsafe_update(); + + action = ""; + + switch (ngx_process) { + + case NGX_PROCESS_MASTER: + case NGX_PROCESS_SINGLE: + switch (signo) { + + case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): + ngx_quit = 1; + action = ", shutting down"; + break; + + case ngx_signal_value(NGX_TERMINATE_SIGNAL): + case SIGINT: + ngx_terminate = 1; + action = ", exiting"; + break; + + case ngx_signal_value(NGX_NOACCEPT_SIGNAL): + if (ngx_daemonized) { + ngx_noaccept = 1; + action = ", stop accepting connections"; + } + break; + + case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): + ngx_reconfigure = 1; + action = ", reconfiguring"; + break; + + case ngx_signal_value(NGX_REOPEN_SIGNAL): + ngx_reopen = 1; + action = ", reopening logs"; + break; + + case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): + if (getppid() > 1 || ngx_new_binary > 0) { + + /* + * Ignore the signal in the new binary if its parent is + * not the init process, i.e. the old binary's process + * is still running. Or ignore the signal in the old binary's + * process if the new binary's process is already running. + */ + + action = ", ignoring"; + ignore = 1; + break; + } + + ngx_change_binary = 1; + action = ", changing binary"; + break; + + case SIGALRM: + ngx_sigalrm = 1; + break; + + case SIGIO: + ngx_sigio = 1; + break; + + case SIGCHLD: + ngx_reap = 1; + break; + } + + break; + + case NGX_PROCESS_WORKER: + case NGX_PROCESS_HELPER: + switch (signo) { + + case ngx_signal_value(NGX_NOACCEPT_SIGNAL): + if (!ngx_daemonized) { + break; + } + ngx_debug_quit = 1; + case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): + ngx_quit = 1; + action = ", shutting down"; + break; + + case ngx_signal_value(NGX_TERMINATE_SIGNAL): + case SIGINT: + ngx_terminate = 1; + action = ", exiting"; + break; + + case ngx_signal_value(NGX_REOPEN_SIGNAL): + ngx_reopen = 1; + action = ", reopening logs"; + break; + + case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): + case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): + case SIGIO: + action = ", ignoring"; + break; + } + + break; + } + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "signal %d (%s) received%s", signo, sig->signame, action); + + if (ignore) { + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0, + "the changing binary signal is ignored: " + "you should shutdown or terminate " + "before either old or new binary's process"); + } + + if (signo == SIGCHLD) { + ngx_process_get_status(); + } + + ngx_set_errno(err); +} + + +static void +ngx_process_get_status(void) +{ + int status; + char *process; + ngx_pid_t pid; + ngx_err_t err; + ngx_int_t i; + ngx_uint_t one; + + one = 0; + + for ( ;; ) { + pid = waitpid(-1, &status, WNOHANG); + + if (pid == 0) { + return; + } + + if (pid == -1) { + err = ngx_errno; + + if (err == NGX_EINTR) { + continue; + } + + if (err == NGX_ECHILD && one) { + return; + } + + /* + * Solaris always calls the signal handler for each exited process + * despite waitpid() may be already called for this process. + * + * When several processes exit at the same time FreeBSD may + * erroneously call the signal handler for exited process + * despite waitpid() may be already called for this process. + */ + + if (err == NGX_ECHILD) { + ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, err, + "waitpid() failed"); + return; + } + + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err, + "waitpid() failed"); + return; + } + + + one = 1; + process = "unknown process"; + + for (i = 0; i < ngx_last_process; i++) { + if (ngx_processes[i].pid == pid) { + ngx_processes[i].status = status; + ngx_processes[i].exited = 1; + process = ngx_processes[i].name; + break; + } + } + + if (WTERMSIG(status)) { +#ifdef WCOREDUMP + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "%s %P exited on signal %d%s", + process, pid, WTERMSIG(status), + WCOREDUMP(status) ? " (core dumped)" : ""); +#else + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "%s %P exited on signal %d", + process, pid, WTERMSIG(status)); +#endif + + } else { + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "%s %P exited with code %d", + process, pid, WEXITSTATUS(status)); + } + + if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "%s %P exited with fatal code %d " + "and cannot be respawned", + process, pid, WEXITSTATUS(status)); + ngx_processes[i].respawn = 0; + } + + ngx_unlock_mutexes(pid); + } +} + + +static void +ngx_unlock_mutexes(ngx_pid_t pid) +{ + ngx_uint_t i; + ngx_shm_zone_t *shm_zone; + ngx_list_part_t *part; + ngx_slab_pool_t *sp; + + /* + * unlock the accept mutex if the abnormally exited process + * held it + */ + + if (ngx_accept_mutex_ptr) { + (void) ngx_shmtx_force_unlock(&ngx_accept_mutex, pid); + } + + /* + * unlock shared memory mutexes if held by the abnormally exited + * process + */ + + part = (ngx_list_part_t *) &ngx_cycle->shared_memory.part; + shm_zone = part->elts; + + for (i = 0; /* void */ ; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + part = part->next; + shm_zone = part->elts; + i = 0; + } + + sp = (ngx_slab_pool_t *) shm_zone[i].shm.addr; + + if (ngx_shmtx_force_unlock(&sp->mutex, pid)) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "shared memory zone \"%V\" was locked by %P", + &shm_zone[i].shm.name, pid); + } + } +} + + +void +ngx_debug_point(void) +{ + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + switch (ccf->debug_points) { + + case NGX_DEBUG_POINTS_STOP: + raise(SIGSTOP); + break; + + case NGX_DEBUG_POINTS_ABORT: + ngx_abort(); + } +} + + +ngx_int_t +ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_pid_t pid) +{ + ngx_signal_t *sig; + + for (sig = signals; sig->signo != 0; sig++) { + if (ngx_strcmp(name, sig->name) == 0) { + if (kill(pid, sig->signo) != -1) { + return 0; + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "kill(%P, %d) failed", pid, sig->signo); + } + } + + return 1; +} diff --git a/app/nginx/src/os/unix/ngx_process.h b/app/nginx/src/os/unix/ngx_process.h new file mode 100644 index 0000000..7b5e8c0 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_process.h @@ -0,0 +1,88 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_PROCESS_H_INCLUDED_ +#define _NGX_PROCESS_H_INCLUDED_ + + +#include <ngx_setaffinity.h> +#include <ngx_setproctitle.h> + + +typedef pid_t ngx_pid_t; + +#define NGX_INVALID_PID -1 + +typedef void (*ngx_spawn_proc_pt) (ngx_cycle_t *cycle, void *data); + +typedef struct { + ngx_pid_t pid; + int status; + ngx_socket_t channel[2]; + + ngx_spawn_proc_pt proc; + void *data; + char *name; + + unsigned respawn:1; + unsigned just_spawn:1; + unsigned detached:1; + unsigned exiting:1; + unsigned exited:1; +} ngx_process_t; + + +typedef struct { + char *path; + char *name; + char *const *argv; + char *const *envp; +} ngx_exec_ctx_t; + + +#define NGX_MAX_PROCESSES 1024 + +#define NGX_PROCESS_NORESPAWN -1 +#define NGX_PROCESS_JUST_SPAWN -2 +#define NGX_PROCESS_RESPAWN -3 +#define NGX_PROCESS_JUST_RESPAWN -4 +#define NGX_PROCESS_DETACHED -5 + + +#define ngx_getpid getpid + +#ifndef ngx_log_pid +#define ngx_log_pid ngx_pid +#endif + + +ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, + ngx_spawn_proc_pt proc, void *data, char *name, ngx_int_t respawn); +ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx); +ngx_int_t ngx_init_signals(ngx_log_t *log); +void ngx_debug_point(void); + + +#if (NGX_HAVE_SCHED_YIELD) +#define ngx_sched_yield() sched_yield() +#else +#define ngx_sched_yield() usleep(1) +#endif + + +extern int ngx_argc; +extern char **ngx_argv; +extern char **ngx_os_argv; + +extern ngx_pid_t ngx_pid; +extern ngx_socket_t ngx_channel; +extern ngx_int_t ngx_process_slot; +extern ngx_int_t ngx_last_process; +extern ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; + + +#endif /* _NGX_PROCESS_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_process_cycle.c b/app/nginx/src/os/unix/ngx_process_cycle.c new file mode 100644 index 0000000..1710ea8 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_process_cycle.c @@ -0,0 +1,1196 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> +#include <ngx_channel.h> + + +static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, + ngx_int_t type); +static void ngx_start_cache_manager_processes(ngx_cycle_t *cycle, + ngx_uint_t respawn); +static void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch); +static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo); +static ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle); +static void ngx_master_process_exit(ngx_cycle_t *cycle); +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); +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); + + +ngx_uint_t ngx_process; +ngx_uint_t ngx_worker; +ngx_pid_t ngx_pid; + +sig_atomic_t ngx_reap; +sig_atomic_t ngx_sigio; +sig_atomic_t ngx_sigalrm; +sig_atomic_t ngx_terminate; +sig_atomic_t ngx_quit; +sig_atomic_t ngx_debug_quit; +ngx_uint_t ngx_exiting; +sig_atomic_t ngx_reconfigure; +sig_atomic_t ngx_reopen; + +sig_atomic_t ngx_change_binary; +ngx_pid_t ngx_new_binary; +ngx_uint_t ngx_inherited; +ngx_uint_t ngx_daemonized; + +sig_atomic_t ngx_noaccept; +ngx_uint_t ngx_noaccepting; +ngx_uint_t ngx_restart; + + +static u_char master_process[] = "master process"; + + +static ngx_cache_manager_ctx_t ngx_cache_manager_ctx = { + ngx_cache_manager_process_handler, "cache manager process", 0 +}; + +static ngx_cache_manager_ctx_t ngx_cache_loader_ctx = { + ngx_cache_loader_process_handler, "cache loader process", 60000 +}; + + +static ngx_cycle_t ngx_exit_cycle; +static ngx_log_t ngx_exit_log; +static ngx_open_file_t ngx_exit_log_file; + + +void +ngx_master_process_cycle(ngx_cycle_t *cycle) +{ + char *title; + u_char *p; + size_t size; + ngx_int_t i; + ngx_uint_t n, sigio; + sigset_t set; + struct itimerval itv; + ngx_uint_t live; + ngx_msec_t delay; + ngx_listening_t *ls; + ngx_core_conf_t *ccf; + + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigaddset(&set, SIGALRM); + sigaddset(&set, SIGIO); + sigaddset(&set, SIGINT); + sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); + sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); + sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); + sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); + sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); + sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); + + if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "sigprocmask() failed"); + } + + sigemptyset(&set); + + + size = sizeof(master_process); + + for (i = 0; i < ngx_argc; i++) { + size += ngx_strlen(ngx_argv[i]) + 1; + } + + title = ngx_pnalloc(cycle->pool, size); + if (title == NULL) { + /* fatal */ + exit(2); + } + + p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); + for (i = 0; i < ngx_argc; i++) { + *p++ = ' '; + p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size); + } + + ngx_setproctitle(title); + + + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + ngx_start_worker_processes(cycle, ccf->worker_processes, + NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); + + ngx_new_binary = 0; + delay = 0; + sigio = 0; + live = 1; + + for ( ;; ) { + if (delay) { + if (ngx_sigalrm) { + sigio = 0; + delay *= 2; + ngx_sigalrm = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "termination cycle: %M", delay); + + itv.it_interval.tv_sec = 0; + itv.it_interval.tv_usec = 0; + itv.it_value.tv_sec = delay / 1000; + itv.it_value.tv_usec = (delay % 1000 ) * 1000; + + if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "setitimer() failed"); + } + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend"); + + sigsuspend(&set); + + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "wake up, sigio %i", sigio); + + if (ngx_reap) { + ngx_reap = 0; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); + + live = ngx_reap_children(cycle); + } + + if (!live && (ngx_terminate || ngx_quit)) { + ngx_master_process_exit(cycle); + } + + if (ngx_terminate) { + if (delay == 0) { + delay = 50; + } + + if (sigio) { + sigio--; + continue; + } + + sigio = ccf->worker_processes + 2 /* cache processes */; + + if (delay > 1000) { + ngx_signal_worker_processes(cycle, SIGKILL); + } else { + ngx_signal_worker_processes(cycle, + ngx_signal_value(NGX_TERMINATE_SIGNAL)); + } + + continue; + } + + if (ngx_quit) { + ngx_signal_worker_processes(cycle, + ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); + + ls = cycle->listening.elts; + for (n = 0; n < cycle->listening.nelts; n++) { + if (ngx_close_socket(ls[n].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_close_socket_n " %V failed", + &ls[n].addr_text); + } + } + cycle->listening.nelts = 0; + + continue; + } + + if (ngx_reconfigure) { + ngx_reconfigure = 0; + + if (ngx_new_binary) { + ngx_start_worker_processes(cycle, ccf->worker_processes, + NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); + ngx_noaccepting = 0; + + continue; + } + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); + + cycle = ngx_init_cycle(cycle); + if (cycle == NULL) { + cycle = (ngx_cycle_t *) ngx_cycle; + continue; + } + + ngx_cycle = cycle; + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, + ngx_core_module); + ngx_start_worker_processes(cycle, ccf->worker_processes, + NGX_PROCESS_JUST_RESPAWN); + ngx_start_cache_manager_processes(cycle, 1); + + /* allow new processes to start */ + ngx_msleep(100); + + live = 1; + ngx_signal_worker_processes(cycle, + ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); + } + + if (ngx_restart) { + ngx_restart = 0; + ngx_start_worker_processes(cycle, ccf->worker_processes, + NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); + live = 1; + } + + if (ngx_reopen) { + ngx_reopen = 0; + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); + ngx_reopen_files(cycle, ccf->user); + ngx_signal_worker_processes(cycle, + ngx_signal_value(NGX_REOPEN_SIGNAL)); + } + + if (ngx_change_binary) { + ngx_change_binary = 0; + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary"); + ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); + } + + if (ngx_noaccept) { + ngx_noaccept = 0; + ngx_noaccepting = 1; + ngx_signal_worker_processes(cycle, + ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); + } + } +} + + +void +ngx_single_process_cycle(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + + if (ngx_set_environment(cycle, NULL) == NULL) { + /* fatal */ + exit(2); + } + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->init_process) { + if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) { + /* fatal */ + exit(2); + } + } + } + + for ( ;; ) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); + + ngx_process_events_and_timers(cycle); + + if (ngx_terminate || ngx_quit) { + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->exit_process) { + cycle->modules[i]->exit_process(cycle); + } + } + + ngx_master_process_exit(cycle); + } + + if (ngx_reconfigure) { + ngx_reconfigure = 0; + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); + + cycle = ngx_init_cycle(cycle); + if (cycle == NULL) { + cycle = (ngx_cycle_t *) ngx_cycle; + continue; + } + + ngx_cycle = cycle; + } + + if (ngx_reopen) { + ngx_reopen = 0; + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); + ngx_reopen_files(cycle, (ngx_uid_t) -1); + } + } +} + + +static void +ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) +{ + ngx_int_t i; + ngx_channel_t ch; + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes"); + + ngx_memzero(&ch, sizeof(ngx_channel_t)); + + ch.command = NGX_CMD_OPEN_CHANNEL; + + for (i = 0; i < n; i++) { + + ngx_spawn_process(cycle, ngx_worker_process_cycle, + (void *) (intptr_t) i, "worker process", type); + + ch.pid = ngx_processes[ngx_process_slot].pid; + ch.slot = ngx_process_slot; + ch.fd = ngx_processes[ngx_process_slot].channel[0]; + + ngx_pass_open_channel(cycle, &ch); + } +} + + +static void +ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn) +{ + ngx_uint_t i, manager, loader; + ngx_path_t **path; + ngx_channel_t ch; + + manager = 0; + loader = 0; + + path = ngx_cycle->paths.elts; + for (i = 0; i < ngx_cycle->paths.nelts; i++) { + + if (path[i]->manager) { + manager = 1; + } + + if (path[i]->loader) { + loader = 1; + } + } + + if (manager == 0) { + return; + } + + ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, + &ngx_cache_manager_ctx, "cache manager process", + respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN); + + ngx_memzero(&ch, sizeof(ngx_channel_t)); + + ch.command = NGX_CMD_OPEN_CHANNEL; + ch.pid = ngx_processes[ngx_process_slot].pid; + ch.slot = ngx_process_slot; + ch.fd = ngx_processes[ngx_process_slot].channel[0]; + + ngx_pass_open_channel(cycle, &ch); + + if (loader == 0) { + return; + } + + ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, + &ngx_cache_loader_ctx, "cache loader process", + respawn ? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN); + + ch.command = NGX_CMD_OPEN_CHANNEL; + ch.pid = ngx_processes[ngx_process_slot].pid; + ch.slot = ngx_process_slot; + ch.fd = ngx_processes[ngx_process_slot].channel[0]; + + ngx_pass_open_channel(cycle, &ch); +} + + +static void +ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch) +{ + ngx_int_t i; + + for (i = 0; i < ngx_last_process; i++) { + + if (i == ngx_process_slot + || ngx_processes[i].pid == -1 + || ngx_processes[i].channel[0] == -1) + { + continue; + } + + ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "pass channel s:%i pid:%P fd:%d to s:%i pid:%P fd:%d", + ch->slot, ch->pid, ch->fd, + i, ngx_processes[i].pid, + ngx_processes[i].channel[0]); + + /* TODO: NGX_AGAIN */ + + ngx_write_channel(ngx_processes[i].channel[0], + ch, sizeof(ngx_channel_t), cycle->log); + } +} + + +static void +ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo) +{ + ngx_int_t i; + ngx_err_t err; + ngx_channel_t ch; + + ngx_memzero(&ch, sizeof(ngx_channel_t)); + +#if (NGX_BROKEN_SCM_RIGHTS) + + ch.command = 0; + +#else + + switch (signo) { + + case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): + ch.command = NGX_CMD_QUIT; + break; + + case ngx_signal_value(NGX_TERMINATE_SIGNAL): + ch.command = NGX_CMD_TERMINATE; + break; + + case ngx_signal_value(NGX_REOPEN_SIGNAL): + ch.command = NGX_CMD_REOPEN; + break; + + default: + ch.command = 0; + } + +#endif + + ch.fd = -1; + + + for (i = 0; i < ngx_last_process; i++) { + + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "child: %i %P e:%d t:%d d:%d r:%d j:%d", + i, + ngx_processes[i].pid, + ngx_processes[i].exiting, + ngx_processes[i].exited, + ngx_processes[i].detached, + ngx_processes[i].respawn, + ngx_processes[i].just_spawn); + + if (ngx_processes[i].detached || ngx_processes[i].pid == -1) { + continue; + } + + if (ngx_processes[i].just_spawn) { + ngx_processes[i].just_spawn = 0; + continue; + } + + if (ngx_processes[i].exiting + && signo == ngx_signal_value(NGX_SHUTDOWN_SIGNAL)) + { + continue; + } + + if (ch.command) { + if (ngx_write_channel(ngx_processes[i].channel[0], + &ch, sizeof(ngx_channel_t), cycle->log) + == NGX_OK) + { + if (signo != ngx_signal_value(NGX_REOPEN_SIGNAL)) { + ngx_processes[i].exiting = 1; + } + + continue; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "kill (%P, %d)", ngx_processes[i].pid, signo); + + if (kill(ngx_processes[i].pid, signo) == -1) { + err = ngx_errno; + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "kill(%P, %d) failed", ngx_processes[i].pid, signo); + + if (err == NGX_ESRCH) { + ngx_processes[i].exited = 1; + ngx_processes[i].exiting = 0; + ngx_reap = 1; + } + + continue; + } + + if (signo != ngx_signal_value(NGX_REOPEN_SIGNAL)) { + ngx_processes[i].exiting = 1; + } + } +} + + +static ngx_uint_t +ngx_reap_children(ngx_cycle_t *cycle) +{ + ngx_int_t i, n; + ngx_uint_t live; + ngx_channel_t ch; + ngx_core_conf_t *ccf; + + ngx_memzero(&ch, sizeof(ngx_channel_t)); + + ch.command = NGX_CMD_CLOSE_CHANNEL; + ch.fd = -1; + + live = 0; + for (i = 0; i < ngx_last_process; i++) { + + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "child: %i %P e:%d t:%d d:%d r:%d j:%d", + i, + ngx_processes[i].pid, + ngx_processes[i].exiting, + ngx_processes[i].exited, + ngx_processes[i].detached, + ngx_processes[i].respawn, + ngx_processes[i].just_spawn); + + if (ngx_processes[i].pid == -1) { + continue; + } + + if (ngx_processes[i].exited) { + + if (!ngx_processes[i].detached) { + ngx_close_channel(ngx_processes[i].channel, cycle->log); + + ngx_processes[i].channel[0] = -1; + ngx_processes[i].channel[1] = -1; + + ch.pid = ngx_processes[i].pid; + ch.slot = i; + + for (n = 0; n < ngx_last_process; n++) { + if (ngx_processes[n].exited + || ngx_processes[n].pid == -1 + || ngx_processes[n].channel[0] == -1) + { + continue; + } + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "pass close channel s:%i pid:%P to:%P", + ch.slot, ch.pid, ngx_processes[n].pid); + + /* TODO: NGX_AGAIN */ + + ngx_write_channel(ngx_processes[n].channel[0], + &ch, sizeof(ngx_channel_t), cycle->log); + } + } + + if (ngx_processes[i].respawn + && !ngx_processes[i].exiting + && !ngx_terminate + && !ngx_quit) + { + if (ngx_spawn_process(cycle, ngx_processes[i].proc, + ngx_processes[i].data, + ngx_processes[i].name, i) + == NGX_INVALID_PID) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "could not respawn %s", + ngx_processes[i].name); + continue; + } + + + ch.command = NGX_CMD_OPEN_CHANNEL; + ch.pid = ngx_processes[ngx_process_slot].pid; + ch.slot = ngx_process_slot; + ch.fd = ngx_processes[ngx_process_slot].channel[0]; + + ngx_pass_open_channel(cycle, &ch); + + live = 1; + + continue; + } + + if (ngx_processes[i].pid == ngx_new_binary) { + + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, + ngx_core_module); + + if (ngx_rename_file((char *) ccf->oldpid.data, + (char *) ccf->pid.data) + == NGX_FILE_ERROR) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_rename_file_n " %s back to %s failed " + "after the new binary process \"%s\" exited", + ccf->oldpid.data, ccf->pid.data, ngx_argv[0]); + } + + ngx_new_binary = 0; + if (ngx_noaccepting) { + ngx_restart = 1; + ngx_noaccepting = 0; + } + } + + if (i == ngx_last_process - 1) { + ngx_last_process--; + + } else { + ngx_processes[i].pid = -1; + } + + } else if (ngx_processes[i].exiting || !ngx_processes[i].detached) { + live = 1; + } + } + + return live; +} + + +static void +ngx_master_process_exit(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + + ngx_delete_pidfile(cycle); + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit"); + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->exit_master) { + cycle->modules[i]->exit_master(cycle); + } + } + + ngx_close_listening_sockets(cycle); + + /* + * Copy ngx_cycle->log related data to the special static exit cycle, + * log, and log file structures enough to allow a signal handler to log. + * The handler may be called when standard ngx_cycle->log allocated from + * ngx_cycle->pool is already destroyed. + */ + + + ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log); + + ngx_exit_log_file.fd = ngx_exit_log.file->fd; + ngx_exit_log.file = &ngx_exit_log_file; + ngx_exit_log.next = NULL; + ngx_exit_log.writer = NULL; + + ngx_exit_cycle.log = &ngx_exit_log; + ngx_exit_cycle.files = ngx_cycle->files; + ngx_exit_cycle.files_n = ngx_cycle->files_n; + ngx_cycle = &ngx_exit_cycle; + + ngx_destroy_pool(cycle->pool); + + exit(0); +} + + +static void +ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) +{ + ngx_int_t worker = (intptr_t) data; + + ngx_process = NGX_PROCESS_WORKER; + ngx_worker = worker; + + ngx_worker_process_init(cycle, worker); + + ngx_setproctitle("worker process"); + + for ( ;; ) { + + if (ngx_exiting) { + if (ngx_event_no_timers_left() == NGX_OK) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + ngx_worker_process_exit(cycle); + } + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); + + ngx_process_events_and_timers(cycle); + + if (ngx_terminate) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + ngx_worker_process_exit(cycle); + } + + if (ngx_quit) { + ngx_quit = 0; + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, + "gracefully shutting down"); + ngx_setproctitle("worker process is shutting down"); + + if (!ngx_exiting) { + ngx_exiting = 1; + ngx_set_shutdown_timer(cycle); + ngx_close_listening_sockets(cycle); + ngx_close_idle_connections(cycle); + } + } + + if (ngx_reopen) { + ngx_reopen = 0; + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); + ngx_reopen_files(cycle, -1); + } + } +} + + +static void +ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) +{ + sigset_t set; + ngx_int_t n; + ngx_time_t *tp; + ngx_uint_t i; + ngx_cpuset_t *cpu_affinity; + struct rlimit rlmt; + ngx_core_conf_t *ccf; + ngx_listening_t *ls; + + if (ngx_set_environment(cycle, NULL) == NULL) { + /* fatal */ + exit(2); + } + + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + if (worker >= 0 && ccf->priority != 0) { + if (setpriority(PRIO_PROCESS, 0, ccf->priority) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "setpriority(%d) failed", ccf->priority); + } + } + + if (ccf->rlimit_nofile != NGX_CONF_UNSET) { + rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile; + rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile; + + if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "setrlimit(RLIMIT_NOFILE, %i) failed", + ccf->rlimit_nofile); + } + } + + if (ccf->rlimit_core != NGX_CONF_UNSET) { + rlmt.rlim_cur = (rlim_t) ccf->rlimit_core; + rlmt.rlim_max = (rlim_t) ccf->rlimit_core; + + if (setrlimit(RLIMIT_CORE, &rlmt) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "setrlimit(RLIMIT_CORE, %O) failed", + ccf->rlimit_core); + } + } + + if (geteuid() == 0) { + if (setgid(ccf->group) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "setgid(%d) failed", ccf->group); + /* fatal */ + exit(2); + } + + if (initgroups(ccf->username, ccf->group) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "initgroups(%s, %d) failed", + ccf->username, ccf->group); + } + + if (setuid(ccf->user) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "setuid(%d) failed", ccf->user); + /* fatal */ + exit(2); + } + } + + if (worker >= 0) { + cpu_affinity = ngx_get_cpu_affinity(worker); + + if (cpu_affinity) { + ngx_setaffinity(cpu_affinity, cycle->log); + } + } + +#if (NGX_HAVE_PR_SET_DUMPABLE) + + /* allow coredump after setuid() in Linux 2.4.x */ + + if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "prctl(PR_SET_DUMPABLE) failed"); + } + +#endif + + if (ccf->working_directory.len) { + if (chdir((char *) ccf->working_directory.data) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "chdir(\"%s\") failed", ccf->working_directory.data); + /* fatal */ + exit(2); + } + } + + sigemptyset(&set); + + if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "sigprocmask() failed"); + } + + tp = ngx_timeofday(); + srandom(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec); + + /* + * disable deleting previous events for the listening sockets because + * in the worker processes there are no events at all at this point + */ + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + ls[i].previous = NULL; + } + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->init_process) { + if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) { + /* fatal */ + exit(2); + } + } + } + + for (n = 0; n < ngx_last_process; n++) { + + if (ngx_processes[n].pid == -1) { + continue; + } + + if (n == ngx_process_slot) { + continue; + } + + if (ngx_processes[n].channel[1] == -1) { + continue; + } + + if (close(ngx_processes[n].channel[1]) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "close() channel failed"); + } + } + + if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "close() channel failed"); + } + +#if 0 + ngx_last_process = 0; +#endif + + if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT, + ngx_channel_handler) + == NGX_ERROR) + { + /* fatal */ + exit(2); + } +} + + +static void +ngx_worker_process_exit(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + ngx_connection_t *c; + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->exit_process) { + cycle->modules[i]->exit_process(cycle); + } + } + + if (ngx_exiting) { + c = cycle->connections; + for (i = 0; i < cycle->connection_n; i++) { + if (c[i].fd != -1 + && c[i].read + && !c[i].read->accept + && !c[i].read->channel + && !c[i].read->resolver) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "*%uA open socket #%d left in connection %ui", + c[i].number, c[i].fd, i); + ngx_debug_quit = 1; + } + } + + if (ngx_debug_quit) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting"); + ngx_debug_point(); + } + } + + /* + * Copy ngx_cycle->log related data to the special static exit cycle, + * log, and log file structures enough to allow a signal handler to log. + * The handler may be called when standard ngx_cycle->log allocated from + * ngx_cycle->pool is already destroyed. + */ + + ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log); + + ngx_exit_log_file.fd = ngx_exit_log.file->fd; + ngx_exit_log.file = &ngx_exit_log_file; + ngx_exit_log.next = NULL; + ngx_exit_log.writer = NULL; + + ngx_exit_cycle.log = &ngx_exit_log; + ngx_exit_cycle.files = ngx_cycle->files; + ngx_exit_cycle.files_n = ngx_cycle->files_n; + ngx_cycle = &ngx_exit_cycle; + + ngx_destroy_pool(cycle->pool); + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, "exit"); + + exit(0); +} + + +static void +ngx_channel_handler(ngx_event_t *ev) +{ + ngx_int_t n; + ngx_channel_t ch; + ngx_connection_t *c; + + if (ev->timedout) { + ev->timedout = 0; + return; + } + + c = ev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler"); + + for ( ;; ) { + + n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n); + + if (n == NGX_ERROR) { + + if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + ngx_del_conn(c, 0); + } + + ngx_close_connection(c); + return; + } + + if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) { + if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) { + return; + } + } + + if (n == NGX_AGAIN) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, + "channel command: %ui", ch.command); + + switch (ch.command) { + + case NGX_CMD_QUIT: + ngx_quit = 1; + break; + + case NGX_CMD_TERMINATE: + ngx_terminate = 1; + break; + + case NGX_CMD_REOPEN: + ngx_reopen = 1; + break; + + case NGX_CMD_OPEN_CHANNEL: + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0, + "get channel s:%i pid:%P fd:%d", + ch.slot, ch.pid, ch.fd); + + ngx_processes[ch.slot].pid = ch.pid; + ngx_processes[ch.slot].channel[0] = ch.fd; + break; + + case NGX_CMD_CLOSE_CHANNEL: + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0, + "close channel s:%i pid:%P our:%P fd:%d", + ch.slot, ch.pid, ngx_processes[ch.slot].pid, + ngx_processes[ch.slot].channel[0]); + + if (close(ngx_processes[ch.slot].channel[0]) == -1) { + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, + "close() channel failed"); + } + + ngx_processes[ch.slot].channel[0] = -1; + break; + } + } +} + + +static void +ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) +{ + ngx_cache_manager_ctx_t *ctx = data; + + void *ident[4]; + ngx_event_t ev; + + /* + * Set correct process type since closing listening Unix domain socket + * in a master process also removes the Unix domain socket file. + */ + ngx_process = NGX_PROCESS_HELPER; + + ngx_close_listening_sockets(cycle); + + /* Set a moderate number of connections for a helper process. */ + cycle->connection_n = 512; + + ngx_worker_process_init(cycle, -1); + + ngx_memzero(&ev, sizeof(ngx_event_t)); + ev.handler = ctx->handler; + ev.data = ident; + ev.log = cycle->log; + ident[3] = (void *) -1; + + ngx_use_accept_mutex = 0; + + ngx_setproctitle(ctx->name); + + ngx_add_timer(&ev, ctx->delay); + + for ( ;; ) { + + if (ngx_terminate || ngx_quit) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + exit(0); + } + + if (ngx_reopen) { + ngx_reopen = 0; + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); + ngx_reopen_files(cycle, -1); + } + + ngx_process_events_and_timers(cycle); + } +} + + +static void +ngx_cache_manager_process_handler(ngx_event_t *ev) +{ + ngx_uint_t i; + ngx_msec_t next, n; + ngx_path_t **path; + + next = 60 * 60 * 1000; + + path = ngx_cycle->paths.elts; + for (i = 0; i < ngx_cycle->paths.nelts; i++) { + + if (path[i]->manager) { + n = path[i]->manager(path[i]->data); + + next = (n <= next) ? n : next; + + ngx_time_update(); + } + } + + if (next == 0) { + next = 1; + } + + ngx_add_timer(ev, next); +} + + +static void +ngx_cache_loader_process_handler(ngx_event_t *ev) +{ + ngx_uint_t i; + ngx_path_t **path; + ngx_cycle_t *cycle; + + cycle = (ngx_cycle_t *) ngx_cycle; + + path = cycle->paths.elts; + for (i = 0; i < cycle->paths.nelts; i++) { + + if (ngx_terminate || ngx_quit) { + break; + } + + if (path[i]->loader) { + path[i]->loader(path[i]->data); + ngx_time_update(); + } + } + + exit(0); +} diff --git a/app/nginx/src/os/unix/ngx_process_cycle.h b/app/nginx/src/os/unix/ngx_process_cycle.h new file mode 100644 index 0000000..69495d5 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_process_cycle.h @@ -0,0 +1,61 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_PROCESS_CYCLE_H_INCLUDED_ +#define _NGX_PROCESS_CYCLE_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define NGX_CMD_OPEN_CHANNEL 1 +#define NGX_CMD_CLOSE_CHANNEL 2 +#define NGX_CMD_QUIT 3 +#define NGX_CMD_TERMINATE 4 +#define NGX_CMD_REOPEN 5 + + +#define NGX_PROCESS_SINGLE 0 +#define NGX_PROCESS_MASTER 1 +#define NGX_PROCESS_SIGNALLER 2 +#define NGX_PROCESS_WORKER 3 +#define NGX_PROCESS_HELPER 4 + + +typedef struct { + ngx_event_handler_pt handler; + char *name; + ngx_msec_t delay; +} ngx_cache_manager_ctx_t; + + +void ngx_master_process_cycle(ngx_cycle_t *cycle); +void ngx_single_process_cycle(ngx_cycle_t *cycle); + + +extern ngx_uint_t ngx_process; +extern ngx_uint_t ngx_worker; +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_exiting; + +extern sig_atomic_t ngx_reap; +extern sig_atomic_t ngx_sigio; +extern sig_atomic_t ngx_sigalrm; +extern sig_atomic_t ngx_quit; +extern sig_atomic_t ngx_debug_quit; +extern sig_atomic_t ngx_terminate; +extern sig_atomic_t ngx_noaccept; +extern sig_atomic_t ngx_reconfigure; +extern sig_atomic_t ngx_reopen; +extern sig_atomic_t ngx_change_binary; + + +#endif /* _NGX_PROCESS_CYCLE_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_readv_chain.c b/app/nginx/src/os/unix/ngx_readv_chain.c new file mode 100644 index 0000000..454cfdc --- /dev/null +++ b/app/nginx/src/os/unix/ngx_readv_chain.c @@ -0,0 +1,214 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +ssize_t +ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) +{ + u_char *prev; + ssize_t n, size; + ngx_err_t err; + ngx_array_t vec; + ngx_event_t *rev; + struct iovec *iov, iovs[NGX_IOVS_PREALLOCATE]; + + rev = c->read; + +#if (NGX_HAVE_KQUEUE) + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "readv: eof:%d, avail:%d, err:%d", + rev->pending_eof, rev->available, rev->kq_errno); + + if (rev->available == 0) { + if (rev->pending_eof) { + rev->ready = 0; + rev->eof = 1; + + ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno, + "kevent() reported about an closed connection"); + + if (rev->kq_errno) { + rev->error = 1; + ngx_set_socket_errno(rev->kq_errno); + return NGX_ERROR; + } + + return 0; + + } else { + return NGX_AGAIN; + } + } + } + +#endif + +#if (NGX_HAVE_EPOLLRDHUP) + + if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "readv: eof:%d, avail:%d", + rev->pending_eof, rev->available); + + if (!rev->available && !rev->pending_eof) { + return NGX_AGAIN; + } + } + +#endif + + prev = NULL; + iov = NULL; + size = 0; + + vec.elts = iovs; + vec.nelts = 0; + vec.size = sizeof(struct iovec); + vec.nalloc = NGX_IOVS_PREALLOCATE; + vec.pool = c->pool; + + /* coalesce the neighbouring bufs */ + + while (chain) { + n = chain->buf->end - chain->buf->last; + + if (limit) { + if (size >= limit) { + break; + } + + if (size + n > limit) { + n = (ssize_t) (limit - size); + } + } + + if (prev == chain->buf->last) { + iov->iov_len += n; + + } else { + if (vec.nelts >= IOV_MAX) { + break; + } + + iov = ngx_array_push(&vec); + if (iov == NULL) { + return NGX_ERROR; + } + + iov->iov_base = (void *) chain->buf->last; + iov->iov_len = n; + } + + size += n; + prev = chain->buf->end; + chain = chain->next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "readv: %ui, last:%uz", vec.nelts, iov->iov_len); + + do { + n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts); + + if (n == 0) { + rev->ready = 0; + rev->eof = 1; + +#if (NGX_HAVE_KQUEUE) + + /* + * on FreeBSD readv() may return 0 on closed socket + * even if kqueue reported about available data + */ + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + rev->available = 0; + } + +#endif + + return 0; + } + + if (n > 0) { + +#if (NGX_HAVE_KQUEUE) + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + rev->available -= n; + + /* + * rev->available may be negative here because some additional + * bytes may be received between kevent() and readv() + */ + + if (rev->available <= 0) { + if (!rev->pending_eof) { + rev->ready = 0; + } + + rev->available = 0; + } + + return n; + } + +#endif + +#if (NGX_HAVE_EPOLLRDHUP) + + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) + && ngx_use_epoll_rdhup) + { + if (n < size) { + if (!rev->pending_eof) { + rev->ready = 0; + } + + rev->available = 0; + } + + return n; + } + +#endif + + if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) { + rev->ready = 0; + } + + return n; + } + + err = ngx_socket_errno; + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "readv() not ready"); + n = NGX_AGAIN; + + } else { + n = ngx_connection_error(c, err, "readv() failed"); + break; + } + + } while (err == NGX_EINTR); + + rev->ready = 0; + + if (n == NGX_ERROR) { + c->read->error = 1; + } + + return n; +} diff --git a/app/nginx/src/os/unix/ngx_recv.c b/app/nginx/src/os/unix/ngx_recv.c new file mode 100644 index 0000000..c85fd45 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_recv.c @@ -0,0 +1,167 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +ssize_t +ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *rev; + + rev = c->read; + +#if (NGX_HAVE_KQUEUE) + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "recv: eof:%d, avail:%d, err:%d", + rev->pending_eof, rev->available, rev->kq_errno); + + if (rev->available == 0) { + if (rev->pending_eof) { + rev->ready = 0; + rev->eof = 1; + + if (rev->kq_errno) { + rev->error = 1; + ngx_set_socket_errno(rev->kq_errno); + + return ngx_connection_error(c, rev->kq_errno, + "kevent() reported about an closed connection"); + } + + return 0; + + } else { + rev->ready = 0; + return NGX_AGAIN; + } + } + } + +#endif + +#if (NGX_HAVE_EPOLLRDHUP) + + if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "recv: eof:%d, avail:%d", + rev->pending_eof, rev->available); + + if (!rev->available && !rev->pending_eof) { + rev->ready = 0; + return NGX_AGAIN; + } + } + +#endif + + do { + n = recv(c->fd, buf, size, 0); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "recv: fd:%d %z of %uz", c->fd, n, size); + + if (n == 0) { + rev->ready = 0; + rev->eof = 1; + +#if (NGX_HAVE_KQUEUE) + + /* + * on FreeBSD recv() may return 0 on closed socket + * even if kqueue reported about available data + */ + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + rev->available = 0; + } + +#endif + + return 0; + } + + if (n > 0) { + +#if (NGX_HAVE_KQUEUE) + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + rev->available -= n; + + /* + * rev->available may be negative here because some additional + * bytes may be received between kevent() and recv() + */ + + if (rev->available <= 0) { + if (!rev->pending_eof) { + rev->ready = 0; + } + + rev->available = 0; + } + + return n; + } + +#endif + +#if (NGX_HAVE_EPOLLRDHUP) + + if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) + && ngx_use_epoll_rdhup) + { + if ((size_t) n < size) { + if (!rev->pending_eof) { + rev->ready = 0; + } + + rev->available = 0; + } + + return n; + } + +#endif + + if ((size_t) n < size + && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) + { + rev->ready = 0; + } + + return n; + } + + err = ngx_socket_errno; + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "recv() not ready"); + n = NGX_AGAIN; + + } else { + n = ngx_connection_error(c, err, "recv() failed"); + break; + } + + } while (err == NGX_EINTR); + + rev->ready = 0; + + if (n == NGX_ERROR) { + rev->error = 1; + } + + return n; +} diff --git a/app/nginx/src/os/unix/ngx_send.c b/app/nginx/src/os/unix/ngx_send.c new file mode 100644 index 0000000..61ea202 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_send.c @@ -0,0 +1,73 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +ssize_t +ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *wev; + + wev = c->write; + +#if (NGX_HAVE_KQUEUE) + + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) { + (void) ngx_connection_error(c, wev->kq_errno, + "kevent() reported about an closed connection"); + wev->error = 1; + return NGX_ERROR; + } + +#endif + + for ( ;; ) { + n = send(c->fd, buf, size, 0); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "send: fd:%d %z of %uz", c->fd, n, size); + + if (n > 0) { + if (n < (ssize_t) size) { + wev->ready = 0; + } + + c->sent += n; + + return n; + } + + err = ngx_socket_errno; + + if (n == 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, err, "send() returned zero"); + wev->ready = 0; + return n; + } + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + wev->ready = 0; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "send() not ready"); + + if (err == NGX_EAGAIN) { + return NGX_AGAIN; + } + + } else { + wev->error = 1; + (void) ngx_connection_error(c, err, "send() failed"); + return NGX_ERROR; + } + } +} diff --git a/app/nginx/src/os/unix/ngx_setaffinity.c b/app/nginx/src/os/unix/ngx_setaffinity.c new file mode 100644 index 0000000..34ec390 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_setaffinity.c @@ -0,0 +1,53 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#if (NGX_HAVE_CPUSET_SETAFFINITY) + +void +ngx_setaffinity(ngx_cpuset_t *cpu_affinity, ngx_log_t *log) +{ + ngx_uint_t i; + + for (i = 0; i < CPU_SETSIZE; i++) { + if (CPU_ISSET(i, cpu_affinity)) { + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "cpuset_setaffinity(): using cpu #%ui", i); + } + } + + if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, + sizeof(cpuset_t), cpu_affinity) == -1) + { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "cpuset_setaffinity() failed"); + } +} + +#elif (NGX_HAVE_SCHED_SETAFFINITY) + +void +ngx_setaffinity(ngx_cpuset_t *cpu_affinity, ngx_log_t *log) +{ + ngx_uint_t i; + + for (i = 0; i < CPU_SETSIZE; i++) { + if (CPU_ISSET(i, cpu_affinity)) { + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "sched_setaffinity(): using cpu #%ui", i); + } + } + + if (sched_setaffinity(0, sizeof(cpu_set_t), cpu_affinity) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sched_setaffinity() failed"); + } +} + +#endif diff --git a/app/nginx/src/os/unix/ngx_setaffinity.h b/app/nginx/src/os/unix/ngx_setaffinity.h new file mode 100644 index 0000000..a4139ed --- /dev/null +++ b/app/nginx/src/os/unix/ngx_setaffinity.h @@ -0,0 +1,37 @@ + +/* + * Copyright (C) Nginx, Inc. + */ + +#ifndef _NGX_SETAFFINITY_H_INCLUDED_ +#define _NGX_SETAFFINITY_H_INCLUDED_ + + +#if (NGX_HAVE_SCHED_SETAFFINITY || NGX_HAVE_CPUSET_SETAFFINITY) + +#define NGX_HAVE_CPU_AFFINITY 1 + +#if (NGX_HAVE_SCHED_SETAFFINITY) + +typedef cpu_set_t ngx_cpuset_t; + +#elif (NGX_HAVE_CPUSET_SETAFFINITY) + +#include <sys/cpuset.h> + +typedef cpuset_t ngx_cpuset_t; + +#endif + +void ngx_setaffinity(ngx_cpuset_t *cpu_affinity, ngx_log_t *log); + +#else + +#define ngx_setaffinity(cpu_affinity, log) + +typedef uint64_t ngx_cpuset_t; + +#endif + + +#endif /* _NGX_SETAFFINITY_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_setproctitle.c b/app/nginx/src/os/unix/ngx_setproctitle.c new file mode 100644 index 0000000..91afa51 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_setproctitle.c @@ -0,0 +1,135 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#if (NGX_SETPROCTITLE_USES_ENV) + +/* + * To change the process title in Linux and Solaris we have to set argv[1] + * to NULL and to copy the title to the same place where the argv[0] points to. + * However, argv[0] may be too small to hold a new title. Fortunately, Linux + * and Solaris store argv[] and environ[] one after another. So we should + * ensure that is the continuous memory and then we allocate the new memory + * for environ[] and copy it. After this we could use the memory starting + * from argv[0] for our process title. + * + * The Solaris's standard /bin/ps does not show the changed process title. + * You have to use "/usr/ucb/ps -w" instead. Besides, the UCB ps does not + * show a new title if its length less than the origin command line length. + * To avoid it we append to a new title the origin command line in the + * parenthesis. + */ + +extern char **environ; + +static char *ngx_os_argv_last; + +ngx_int_t +ngx_init_setproctitle(ngx_log_t *log) +{ + u_char *p; + size_t size; + ngx_uint_t i; + + size = 0; + + for (i = 0; environ[i]; i++) { + size += ngx_strlen(environ[i]) + 1; + } + + p = ngx_alloc(size, log); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_os_argv_last = ngx_os_argv[0]; + + for (i = 0; ngx_os_argv[i]; i++) { + if (ngx_os_argv_last == ngx_os_argv[i]) { + ngx_os_argv_last = ngx_os_argv[i] + ngx_strlen(ngx_os_argv[i]) + 1; + } + } + + for (i = 0; environ[i]; i++) { + if (ngx_os_argv_last == environ[i]) { + + size = ngx_strlen(environ[i]) + 1; + ngx_os_argv_last = environ[i] + size; + + ngx_cpystrn(p, (u_char *) environ[i], size); + environ[i] = (char *) p; + p += size; + } + } + + ngx_os_argv_last--; + + return NGX_OK; +} + + +void +ngx_setproctitle(char *title) +{ + u_char *p; + +#if (NGX_SOLARIS) + + ngx_int_t i; + size_t size; + +#endif + + ngx_os_argv[1] = NULL; + + p = ngx_cpystrn((u_char *) ngx_os_argv[0], (u_char *) "nginx: ", + ngx_os_argv_last - ngx_os_argv[0]); + + p = ngx_cpystrn(p, (u_char *) title, ngx_os_argv_last - (char *) p); + +#if (NGX_SOLARIS) + + size = 0; + + for (i = 0; i < ngx_argc; i++) { + size += ngx_strlen(ngx_argv[i]) + 1; + } + + if (size > (size_t) ((char *) p - ngx_os_argv[0])) { + + /* + * ngx_setproctitle() is too rare operation so we use + * the non-optimized copies + */ + + p = ngx_cpystrn(p, (u_char *) " (", ngx_os_argv_last - (char *) p); + + for (i = 0; i < ngx_argc; i++) { + p = ngx_cpystrn(p, (u_char *) ngx_argv[i], + ngx_os_argv_last - (char *) p); + p = ngx_cpystrn(p, (u_char *) " ", ngx_os_argv_last - (char *) p); + } + + if (*(p - 1) == ' ') { + *(p - 1) = ')'; + } + } + +#endif + + if (ngx_os_argv_last - (char *) p) { + ngx_memset(p, NGX_SETPROCTITLE_PAD, ngx_os_argv_last - (char *) p); + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, + "setproctitle: \"%s\"", ngx_os_argv[0]); +} + +#endif /* NGX_SETPROCTITLE_USES_ENV */ diff --git a/app/nginx/src/os/unix/ngx_setproctitle.h b/app/nginx/src/os/unix/ngx_setproctitle.h new file mode 100644 index 0000000..c363662 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_setproctitle.h @@ -0,0 +1,52 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SETPROCTITLE_H_INCLUDED_ +#define _NGX_SETPROCTITLE_H_INCLUDED_ + + +#if (NGX_HAVE_SETPROCTITLE) + +/* FreeBSD, NetBSD, OpenBSD */ + +#define ngx_init_setproctitle(log) NGX_OK +#define ngx_setproctitle(title) setproctitle("%s", title) + + +#else /* !NGX_HAVE_SETPROCTITLE */ + +#if !defined NGX_SETPROCTITLE_USES_ENV + +#if (NGX_SOLARIS) + +#define NGX_SETPROCTITLE_USES_ENV 1 +#define NGX_SETPROCTITLE_PAD ' ' + +ngx_int_t ngx_init_setproctitle(ngx_log_t *log); +void ngx_setproctitle(char *title); + +#elif (NGX_LINUX) || (NGX_DARWIN) + +#define NGX_SETPROCTITLE_USES_ENV 1 +#define NGX_SETPROCTITLE_PAD '\0' + +ngx_int_t ngx_init_setproctitle(ngx_log_t *log); +void ngx_setproctitle(char *title); + +#else + +#define ngx_init_setproctitle(log) NGX_OK +#define ngx_setproctitle(title) + +#endif /* OSes */ + +#endif /* NGX_SETPROCTITLE_USES_ENV */ + +#endif /* NGX_HAVE_SETPROCTITLE */ + + +#endif /* _NGX_SETPROCTITLE_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_shmem.c b/app/nginx/src/os/unix/ngx_shmem.c new file mode 100644 index 0000000..3ec7cbf --- /dev/null +++ b/app/nginx/src/os/unix/ngx_shmem.c @@ -0,0 +1,126 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#if (NGX_HAVE_MAP_ANON) + +ngx_int_t +ngx_shm_alloc(ngx_shm_t *shm) +{ + shm->addr = (u_char *) mmap(NULL, shm->size, + PROT_READ|PROT_WRITE, + MAP_ANON|MAP_SHARED, -1, 0); + + if (shm->addr == MAP_FAILED) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size); + return NGX_ERROR; + } + + return NGX_OK; +} + + +void +ngx_shm_free(ngx_shm_t *shm) +{ + if (munmap((void *) shm->addr, shm->size) == -1) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "munmap(%p, %uz) failed", shm->addr, shm->size); + } +} + +#elif (NGX_HAVE_MAP_DEVZERO) + +ngx_int_t +ngx_shm_alloc(ngx_shm_t *shm) +{ + ngx_fd_t fd; + + fd = open("/dev/zero", O_RDWR); + + if (fd == -1) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "open(\"/dev/zero\") failed"); + return NGX_ERROR; + } + + shm->addr = (u_char *) mmap(NULL, shm->size, PROT_READ|PROT_WRITE, + MAP_SHARED, fd, 0); + + if (shm->addr == MAP_FAILED) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "mmap(/dev/zero, MAP_SHARED, %uz) failed", shm->size); + } + + if (close(fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "close(\"/dev/zero\") failed"); + } + + return (shm->addr == MAP_FAILED) ? NGX_ERROR : NGX_OK; +} + + +void +ngx_shm_free(ngx_shm_t *shm) +{ + if (munmap((void *) shm->addr, shm->size) == -1) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "munmap(%p, %uz) failed", shm->addr, shm->size); + } +} + +#elif (NGX_HAVE_SYSVSHM) + +#include <sys/ipc.h> +#include <sys/shm.h> + + +ngx_int_t +ngx_shm_alloc(ngx_shm_t *shm) +{ + int id; + + id = shmget(IPC_PRIVATE, shm->size, (SHM_R|SHM_W|IPC_CREAT)); + + if (id == -1) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "shmget(%uz) failed", shm->size); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, shm->log, 0, "shmget id: %d", id); + + shm->addr = shmat(id, NULL, 0); + + if (shm->addr == (void *) -1) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "shmat() failed"); + } + + if (shmctl(id, IPC_RMID, NULL) == -1) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "shmctl(IPC_RMID) failed"); + } + + return (shm->addr == (void *) -1) ? NGX_ERROR : NGX_OK; +} + + +void +ngx_shm_free(ngx_shm_t *shm) +{ + if (shmdt(shm->addr) == -1) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "shmdt(%p) failed", shm->addr); + } +} + +#endif diff --git a/app/nginx/src/os/unix/ngx_shmem.h b/app/nginx/src/os/unix/ngx_shmem.h new file mode 100644 index 0000000..566a7d3 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_shmem.h @@ -0,0 +1,29 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SHMEM_H_INCLUDED_ +#define _NGX_SHMEM_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +typedef struct { + u_char *addr; + size_t size; + ngx_str_t name; + ngx_log_t *log; + ngx_uint_t exists; /* unsigned exists:1; */ +} ngx_shm_t; + + +ngx_int_t ngx_shm_alloc(ngx_shm_t *shm); +void ngx_shm_free(ngx_shm_t *shm); + + +#endif /* _NGX_SHMEM_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_socket.c b/app/nginx/src/os/unix/ngx_socket.c new file mode 100644 index 0000000..3978f65 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_socket.c @@ -0,0 +1,116 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +/* + * ioctl(FIONBIO) sets a non-blocking mode with the single syscall + * while fcntl(F_SETFL, O_NONBLOCK) needs to learn the current state + * using fcntl(F_GETFL). + * + * ioctl() and fcntl() are syscalls at least in FreeBSD 2.x, Linux 2.2 + * and Solaris 7. + * + * ioctl() in Linux 2.4 and 2.6 uses BKL, however, fcntl(F_SETFL) uses it too. + */ + + +#if (NGX_HAVE_FIONBIO) + +int +ngx_nonblocking(ngx_socket_t s) +{ + int nb; + + nb = 1; + + return ioctl(s, FIONBIO, &nb); +} + + +int +ngx_blocking(ngx_socket_t s) +{ + int nb; + + nb = 0; + + return ioctl(s, FIONBIO, &nb); +} + +#endif + + +#if (NGX_FREEBSD) + +int +ngx_tcp_nopush(ngx_socket_t s) +{ + int tcp_nopush; + + tcp_nopush = 1; + + return setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, + (const void *) &tcp_nopush, sizeof(int)); +} + + +int +ngx_tcp_push(ngx_socket_t s) +{ + int tcp_nopush; + + tcp_nopush = 0; + + return setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, + (const void *) &tcp_nopush, sizeof(int)); +} + +#elif (NGX_LINUX) + + +int +ngx_tcp_nopush(ngx_socket_t s) +{ + int cork; + + cork = 1; + + return setsockopt(s, IPPROTO_TCP, TCP_CORK, + (const void *) &cork, sizeof(int)); +} + + +int +ngx_tcp_push(ngx_socket_t s) +{ + int cork; + + cork = 0; + + return setsockopt(s, IPPROTO_TCP, TCP_CORK, + (const void *) &cork, sizeof(int)); +} + +#else + +int +ngx_tcp_nopush(ngx_socket_t s) +{ + return 0; +} + + +int +ngx_tcp_push(ngx_socket_t s) +{ + return 0; +} + +#endif diff --git a/app/nginx/src/os/unix/ngx_socket.h b/app/nginx/src/os/unix/ngx_socket.h new file mode 100644 index 0000000..fcc5153 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_socket.h @@ -0,0 +1,64 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SOCKET_H_INCLUDED_ +#define _NGX_SOCKET_H_INCLUDED_ + + +#include <ngx_config.h> + + +#define NGX_WRITE_SHUTDOWN SHUT_WR + +typedef int ngx_socket_t; + +#define ngx_socket socket +#define ngx_socket_n "socket()" + + +#if (NGX_HAVE_FIONBIO) + +int ngx_nonblocking(ngx_socket_t s); +int ngx_blocking(ngx_socket_t s); + +#define ngx_nonblocking_n "ioctl(FIONBIO)" +#define ngx_blocking_n "ioctl(!FIONBIO)" + +#else + +#define ngx_nonblocking(s) fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK) +#define ngx_nonblocking_n "fcntl(O_NONBLOCK)" + +#define ngx_blocking(s) fcntl(s, F_SETFL, fcntl(s, F_GETFL) & ~O_NONBLOCK) +#define ngx_blocking_n "fcntl(!O_NONBLOCK)" + +#endif + +int ngx_tcp_nopush(ngx_socket_t s); +int ngx_tcp_push(ngx_socket_t s); + +#if (NGX_LINUX) + +#define ngx_tcp_nopush_n "setsockopt(TCP_CORK)" +#define ngx_tcp_push_n "setsockopt(!TCP_CORK)" + +#else + +#define ngx_tcp_nopush_n "setsockopt(TCP_NOPUSH)" +#define ngx_tcp_push_n "setsockopt(!TCP_NOPUSH)" + +#endif + + +#define ngx_shutdown_socket shutdown +#define ngx_shutdown_socket_n "shutdown()" + +#define ngx_close_socket close +#define ngx_close_socket_n "close() socket" + + +#endif /* _NGX_SOCKET_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_solaris.h b/app/nginx/src/os/unix/ngx_solaris.h new file mode 100644 index 0000000..7b167d8 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_solaris.h @@ -0,0 +1,16 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SOLARIS_H_INCLUDED_ +#define _NGX_SOLARIS_H_INCLUDED_ + + +ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + + +#endif /* _NGX_SOLARIS_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_solaris_config.h b/app/nginx/src/os/unix/ngx_solaris_config.h new file mode 100644 index 0000000..ffa01c8 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_solaris_config.h @@ -0,0 +1,112 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SOLARIS_CONFIG_H_INCLUDED_ +#define _NGX_SOLARIS_CONFIG_H_INCLUDED_ + + +#ifndef _REENTRANT +#define _REENTRANT +#endif + +#define _FILE_OFFSET_BITS 64 /* must be before <sys/types.h> */ + +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#include <stdarg.h> +#include <stddef.h> /* offsetof() */ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <signal.h> +#include <pwd.h> +#include <grp.h> +#include <dirent.h> +#include <glob.h> +#include <time.h> +#include <sys/statvfs.h> /* statvfs() */ + +#include <sys/filio.h> /* FIONBIO */ +#include <sys/uio.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <sys/wait.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sched.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> /* TCP_NODELAY */ +#include <arpa/inet.h> +#include <netdb.h> +#include <sys/un.h> + +#include <sys/systeminfo.h> +#include <limits.h> /* IOV_MAX */ +#include <inttypes.h> +#include <crypt.h> + +#include <dlfcn.h> + +#define NGX_ALIGNMENT _MAX_ALIGNMENT + +#include <ngx_auto_config.h> + + +#if (NGX_HAVE_POSIX_SEM) +#include <semaphore.h> +#endif + + +#if (NGX_HAVE_POLL) +#include <poll.h> +#endif + + +#if (NGX_HAVE_DEVPOLL) +#include <sys/ioctl.h> +#include <sys/devpoll.h> +#endif + + +#if (NGX_HAVE_EVENTPORT) +#include <port.h> +#endif + + +#if (NGX_HAVE_SENDFILE) +#include <sys/sendfile.h> +#endif + + +#define NGX_LISTEN_BACKLOG 511 + + +#ifndef NGX_HAVE_INHERITED_NONBLOCK +#define NGX_HAVE_INHERITED_NONBLOCK 1 +#endif + + +#ifndef NGX_HAVE_SO_SNDLOWAT +/* setsockopt(SO_SNDLOWAT) returns ENOPROTOOPT */ +#define NGX_HAVE_SO_SNDLOWAT 0 +#endif + + +#define NGX_HAVE_OS_SPECIFIC_INIT 1 +#define ngx_debug_init() + + +extern char **environ; + + +#endif /* _NGX_SOLARIS_CONFIG_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_solaris_init.c b/app/nginx/src/os/unix/ngx_solaris_init.c new file mode 100644 index 0000000..65d7875 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_solaris_init.c @@ -0,0 +1,77 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +char ngx_solaris_sysname[20]; +char ngx_solaris_release[10]; +char ngx_solaris_version[50]; + + +static ngx_os_io_t ngx_solaris_io = { + ngx_unix_recv, + ngx_readv_chain, + ngx_udp_unix_recv, + ngx_unix_send, + ngx_udp_unix_send, + ngx_udp_unix_sendmsg_chain, +#if (NGX_HAVE_SENDFILE) + ngx_solaris_sendfilev_chain, + NGX_IO_SENDFILE +#else + ngx_writev_chain, + 0 +#endif +}; + + +ngx_int_t +ngx_os_specific_init(ngx_log_t *log) +{ + if (sysinfo(SI_SYSNAME, ngx_solaris_sysname, sizeof(ngx_solaris_sysname)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sysinfo(SI_SYSNAME) failed"); + return NGX_ERROR; + } + + if (sysinfo(SI_RELEASE, ngx_solaris_release, sizeof(ngx_solaris_release)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sysinfo(SI_RELEASE) failed"); + return NGX_ERROR; + } + + if (sysinfo(SI_VERSION, ngx_solaris_version, sizeof(ngx_solaris_version)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sysinfo(SI_SYSNAME) failed"); + return NGX_ERROR; + } + + + ngx_os_io = ngx_solaris_io; + + return NGX_OK; +} + + +void +ngx_os_specific_status(ngx_log_t *log) +{ + + ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s", + ngx_solaris_sysname, ngx_solaris_release); + + ngx_log_error(NGX_LOG_NOTICE, log, 0, "version: %s", + ngx_solaris_version); +} diff --git a/app/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c b/app/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c new file mode 100644 index 0000000..39bcafa --- /dev/null +++ b/app/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c @@ -0,0 +1,228 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +#if (NGX_TEST_BUILD_SOLARIS_SENDFILEV) + +/* Solaris declarations */ + +typedef struct sendfilevec { + int sfv_fd; + u_int sfv_flag; + off_t sfv_off; + size_t sfv_len; +} sendfilevec_t; + +#define SFV_FD_SELF -2 + +static ssize_t sendfilev(int fd, const struct sendfilevec *vec, + int sfvcnt, size_t *xferred) +{ + return -1; +} + +ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + +#endif + + +#define NGX_SENDFILEVECS NGX_IOVS_PREALLOCATE + + +ngx_chain_t * +ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + int fd; + u_char *prev; + off_t size, send, prev_send, aligned, fprev; + size_t sent; + ssize_t n; + ngx_int_t eintr; + ngx_err_t err; + ngx_buf_t *file; + ngx_uint_t nsfv; + sendfilevec_t *sfv, sfvs[NGX_SENDFILEVECS]; + ngx_event_t *wev; + ngx_chain_t *cl; + + wev = c->write; + + if (!wev->ready) { + return in; + } + + if (!c->sendfile) { + return ngx_writev_chain(c, in, limit); + } + + + /* the maximum limit size is the maximum size_t value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) { + limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; + } + + + send = 0; + + for ( ;; ) { + fd = SFV_FD_SELF; + prev = NULL; + fprev = 0; + file = NULL; + sfv = NULL; + eintr = 0; + sent = 0; + prev_send = send; + + nsfv = 0; + + /* create the sendfilevec and coalesce the neighbouring bufs */ + + for (cl = in; cl && send < limit; cl = cl->next) { + + if (ngx_buf_special(cl->buf)) { + continue; + } + + if (ngx_buf_in_memory_only(cl->buf)) { + fd = SFV_FD_SELF; + + size = cl->buf->last - cl->buf->pos; + + if (send + size > limit) { + size = limit - send; + } + + if (prev == cl->buf->pos) { + sfv->sfv_len += (size_t) size; + + } else { + if (nsfv == NGX_SENDFILEVECS) { + break; + } + + sfv = &sfvs[nsfv++]; + + sfv->sfv_fd = SFV_FD_SELF; + sfv->sfv_flag = 0; + sfv->sfv_off = (off_t) (uintptr_t) cl->buf->pos; + sfv->sfv_len = (size_t) size; + } + + prev = cl->buf->pos + (size_t) size; + send += size; + + } else { + prev = NULL; + + size = cl->buf->file_last - cl->buf->file_pos; + + if (send + size > limit) { + size = limit - send; + + aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) + & ~((off_t) ngx_pagesize - 1); + + if (aligned <= cl->buf->file_last) { + size = aligned - cl->buf->file_pos; + } + } + + if (fd == cl->buf->file->fd && fprev == cl->buf->file_pos) { + sfv->sfv_len += (size_t) size; + + } else { + if (nsfv == NGX_SENDFILEVECS) { + break; + } + + sfv = &sfvs[nsfv++]; + + fd = cl->buf->file->fd; + sfv->sfv_fd = fd; + sfv->sfv_flag = 0; + sfv->sfv_off = cl->buf->file_pos; + sfv->sfv_len = (size_t) size; + } + + file = cl->buf; + fprev = cl->buf->file_pos + size; + send += size; + } + } + + n = sendfilev(c->fd, sfvs, nsfv, &sent); + + if (n == -1) { + err = ngx_errno; + + switch (err) { + case NGX_EAGAIN: + break; + + case NGX_EINTR: + eintr = 1; + break; + + default: + wev->error = 1; + ngx_connection_error(c, err, "sendfilev() failed"); + return NGX_CHAIN_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendfilev() sent only %uz bytes", sent); + + } else if (n == 0 && sent == 0) { + + /* + * sendfilev() is documented to return -1 with errno + * set to EINVAL if svf_len is greater than the file size, + * but at least Solaris 11 returns 0 instead + */ + + if (file) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfilev() reported that \"%s\" was truncated at %O", + file->file->name.data, file->file_pos); + + } else { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "sendfilev() returned 0 with memory buffers"); + } + + return NGX_CHAIN_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendfilev: %z %z", n, sent); + + c->sent += sent; + + in = ngx_chain_update_sent(in, sent); + + if (eintr) { + send = prev_send + sent; + continue; + } + + if (send - prev_send != (off_t) sent) { + wev->ready = 0; + return in; + } + + if (send >= limit || in == NULL) { + return in; + } + } +} diff --git a/app/nginx/src/os/unix/ngx_sunpro_amd64.il b/app/nginx/src/os/unix/ngx_sunpro_amd64.il new file mode 100644 index 0000000..07f3210 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_sunpro_amd64.il @@ -0,0 +1,43 @@ +/ +/ Copyright (C) Igor Sysoev +/ Copyright (C) Nginx, Inc. +/ + +/ ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock, +/ ngx_atomic_uint_t old, ngx_atomic_uint_t set); +/ +/ the arguments are passed in %rdi, %rsi, %rdx +/ the result is returned in the %rax + + .inline ngx_atomic_cmp_set,0 + movq %rsi, %rax + lock + cmpxchgq %rdx, (%rdi) + setz %al + movzbq %al, %rax + .end + + +/ ngx_atomic_int_t ngx_atomic_fetch_add(ngx_atomic_t *value, +/ ngx_atomic_int_t add); +/ +/ the arguments are passed in %rdi, %rsi +/ the result is returned in the %rax + + .inline ngx_atomic_fetch_add,0 + movq %rsi, %rax + lock + xaddq %rax, (%rdi) + .end + + +/ ngx_cpu_pause() +/ +/ the "rep; nop" is used instead of "pause" to avoid the "[ PAUSE ]" hardware +/ capability added by linker because Solaris/amd64 does not know about it: +/ +/ ld.so.1: nginx: fatal: hardware capability unsupported: 0x2000 [ PAUSE ] + + .inline ngx_cpu_pause,0 + rep; nop + .end diff --git a/app/nginx/src/os/unix/ngx_sunpro_atomic_sparc64.h b/app/nginx/src/os/unix/ngx_sunpro_atomic_sparc64.h new file mode 100644 index 0000000..5f28055 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_sunpro_atomic_sparc64.h @@ -0,0 +1,61 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#if (NGX_PTR_SIZE == 4) +#define NGX_CASA ngx_casa +#else +#define NGX_CASA ngx_casxa +#endif + + +ngx_atomic_uint_t +ngx_casa(ngx_atomic_uint_t set, ngx_atomic_uint_t old, ngx_atomic_t *lock); + +ngx_atomic_uint_t +ngx_casxa(ngx_atomic_uint_t set, ngx_atomic_uint_t old, ngx_atomic_t *lock); + +/* the code in src/os/unix/ngx_sunpro_sparc64.il */ + + +static ngx_inline ngx_atomic_uint_t +ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, + ngx_atomic_uint_t set) +{ + set = NGX_CASA(set, old, lock); + + return (set == old); +} + + +static ngx_inline ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) +{ + ngx_atomic_uint_t old, res; + + old = *value; + + for ( ;; ) { + + res = old + add; + + res = NGX_CASA(res, old, value); + + if (res == old) { + return res; + } + + old = res; + } +} + + +#define ngx_memory_barrier() \ + __asm (".volatile"); \ + __asm ("membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad"); \ + __asm (".nonvolatile") + +#define ngx_cpu_pause() diff --git a/app/nginx/src/os/unix/ngx_sunpro_sparc64.il b/app/nginx/src/os/unix/ngx_sunpro_sparc64.il new file mode 100644 index 0000000..bdeef61 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_sunpro_sparc64.il @@ -0,0 +1,36 @@ +/ +/ Copyright (C) Igor Sysoev +/ Copyright (C) Nginx, Inc. +/ + + +/ "casa [%o2] 0x80, %o1, %o0" and +/ "casxa [%o2] 0x80, %o1, %o0" do the following: +/ +/ if ([%o2] == %o1) { +/ swap(%o0, [%o2]); +/ } else { +/ %o0 = [%o2]; +/ } + + +/ ngx_atomic_uint_t ngx_casa(ngx_atomic_uint_t set, ngx_atomic_uint_t old, +/ ngx_atomic_t *lock); +/ +/ the arguments are passed in the %o0, %o1, %o2 +/ the result is returned in the %o0 + + .inline ngx_casa,0 + casa [%o2] 0x80, %o1, %o0 + .end + + +/ ngx_atomic_uint_t ngx_casxa(ngx_atomic_uint_t set, ngx_atomic_uint_t old, +/ ngx_atomic_t *lock); +/ +/ the arguments are passed in the %o0, %o1, %o2 +/ the result is returned in the %o0 + + .inline ngx_casxa,0 + casxa [%o2] 0x80, %o1, %o0 + .end diff --git a/app/nginx/src/os/unix/ngx_sunpro_x86.il b/app/nginx/src/os/unix/ngx_sunpro_x86.il new file mode 100644 index 0000000..d7e127c --- /dev/null +++ b/app/nginx/src/os/unix/ngx_sunpro_x86.il @@ -0,0 +1,44 @@ +/ +/ Copyright (C) Igor Sysoev +/ Copyright (C) Nginx, Inc. +/ + +/ ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock, +/ ngx_atomic_uint_t old, ngx_atomic_uint_t set); +/ +/ the arguments are passed on stack (%esp), 4(%esp), 8(%esp) + + .inline ngx_atomic_cmp_set,0 + movl (%esp), %ecx + movl 4(%esp), %eax + movl 8(%esp), %edx + lock + cmpxchgl %edx, (%ecx) + setz %al + movzbl %al, %eax + .end + + +/ ngx_atomic_int_t ngx_atomic_fetch_add(ngx_atomic_t *value, +/ ngx_atomic_int_t add); +/ +/ the arguments are passed on stack (%esp), 4(%esp) + + .inline ngx_atomic_fetch_add,0 + movl (%esp), %ecx + movl 4(%esp), %eax + lock + xaddl %eax, (%ecx) + .end + + +/ ngx_cpu_pause() +/ +/ the "rep; nop" is used instead of "pause" to avoid the "[ PAUSE ]" hardware +/ capability added by linker because Solaris/i386 does not know about it: +/ +/ ld.so.1: nginx: fatal: hardware capability unsupported: 0x2000 [ PAUSE ] + + .inline ngx_cpu_pause,0 + rep; nop + .end diff --git a/app/nginx/src/os/unix/ngx_thread.h b/app/nginx/src/os/unix/ngx_thread.h new file mode 100644 index 0000000..1b52dd7 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_thread.h @@ -0,0 +1,71 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_THREAD_H_INCLUDED_ +#define _NGX_THREAD_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + +#if (NGX_THREADS) + +#include <pthread.h> + + +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_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); + + +#if (NGX_LINUX) + +typedef pid_t ngx_tid_t; +#define NGX_TID_T_FMT "%P" + +#elif (NGX_FREEBSD) + +typedef uint32_t ngx_tid_t; +#define NGX_TID_T_FMT "%uD" + +#elif (NGX_DARWIN) + +typedef uint64_t ngx_tid_t; +#define NGX_TID_T_FMT "%uA" + +#else + +typedef uint64_t ngx_tid_t; +#define NGX_TID_T_FMT "%uA" + +#endif + +ngx_tid_t ngx_thread_tid(void); + +#define ngx_log_tid ngx_thread_tid() + +#else + +#define ngx_log_tid 0 +#define NGX_TID_T_FMT "%d" + +#endif + + +#endif /* _NGX_THREAD_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_thread_cond.c b/app/nginx/src/os/unix/ngx_thread_cond.c new file mode 100644 index 0000000..2ad51b8 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_thread_cond.c @@ -0,0 +1,76 @@ + +/* + * 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) { + 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) { + 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) { + 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; + + err = pthread_cond_wait(cond, mtx); + +#if 0 + ngx_time_update(); +#endif + + if (err == 0) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_cond_wait() failed"); + + return NGX_ERROR; +} diff --git a/app/nginx/src/os/unix/ngx_thread_id.c b/app/nginx/src/os/unix/ngx_thread_id.c new file mode 100644 index 0000000..5174f1a --- /dev/null +++ b/app/nginx/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/app/nginx/src/os/unix/ngx_thread_mutex.c b/app/nginx/src/os/unix/ngx_thread_mutex.c new file mode 100644 index 0000000..4886f49 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_thread_mutex.c @@ -0,0 +1,165 @@ + +/* + * 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 overridden 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"); + } + + 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; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_thread_mutex_lock(ngx_thread_mutex_t *mtx, ngx_log_t *log) +{ + ngx_err_t err; + + 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) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_mutex_unlock() failed"); + + return NGX_ERROR; +} diff --git a/app/nginx/src/os/unix/ngx_time.c b/app/nginx/src/os/unix/ngx_time.c new file mode 100644 index 0000000..cc760b2 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_time.c @@ -0,0 +1,104 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +/* + * FreeBSD does not test /etc/localtime change, however, we can workaround it + * by calling tzset() with TZ and then without TZ to update timezone. + * The trick should work since FreeBSD 2.1.0. + * + * Linux does not test /etc/localtime change in localtime(), + * but may stat("/etc/localtime") several times in every strftime(), + * therefore we use it to update timezone. + * + * Solaris does not test /etc/TIMEZONE change too and no workaround available. + */ + +void +ngx_timezone_update(void) +{ +#if (NGX_FREEBSD) + + if (getenv("TZ")) { + return; + } + + putenv("TZ=UTC"); + + tzset(); + + unsetenv("TZ"); + + tzset(); + +#elif (NGX_LINUX) + time_t s; + struct tm *t; + char buf[4]; + + s = time(0); + + t = localtime(&s); + + strftime(buf, 4, "%H", t); + +#endif +} + + +void +ngx_localtime(time_t s, ngx_tm_t *tm) +{ +#if (NGX_HAVE_LOCALTIME_R) + (void) localtime_r(&s, tm); + +#else + ngx_tm_t *t; + + t = localtime(&s); + *tm = *t; + +#endif + + tm->ngx_tm_mon++; + tm->ngx_tm_year += 1900; +} + + +void +ngx_libc_localtime(time_t s, struct tm *tm) +{ +#if (NGX_HAVE_LOCALTIME_R) + (void) localtime_r(&s, tm); + +#else + struct tm *t; + + t = localtime(&s); + *tm = *t; + +#endif +} + + +void +ngx_libc_gmtime(time_t s, struct tm *tm) +{ +#if (NGX_HAVE_LOCALTIME_R) + (void) gmtime_r(&s, tm); + +#else + struct tm *t; + + t = gmtime(&s); + *tm = *t; + +#endif +} diff --git a/app/nginx/src/os/unix/ngx_time.h b/app/nginx/src/os/unix/ngx_time.h new file mode 100644 index 0000000..c128c9a --- /dev/null +++ b/app/nginx/src/os/unix/ngx_time.h @@ -0,0 +1,66 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_TIME_H_INCLUDED_ +#define _NGX_TIME_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +typedef ngx_rbtree_key_t ngx_msec_t; +typedef ngx_rbtree_key_int_t ngx_msec_int_t; + +typedef struct tm ngx_tm_t; + +#define ngx_tm_sec tm_sec +#define ngx_tm_min tm_min +#define ngx_tm_hour tm_hour +#define ngx_tm_mday tm_mday +#define ngx_tm_mon tm_mon +#define ngx_tm_year tm_year +#define ngx_tm_wday tm_wday +#define ngx_tm_isdst tm_isdst + +#define ngx_tm_sec_t int +#define ngx_tm_min_t int +#define ngx_tm_hour_t int +#define ngx_tm_mday_t int +#define ngx_tm_mon_t int +#define ngx_tm_year_t int +#define ngx_tm_wday_t int + + +#if (NGX_HAVE_GMTOFF) +#define ngx_tm_gmtoff tm_gmtoff +#define ngx_tm_zone tm_zone +#endif + + +#if (NGX_SOLARIS) + +#define ngx_timezone(isdst) (- (isdst ? altzone : timezone) / 60) + +#else + +#define ngx_timezone(isdst) (- (isdst ? timezone + 3600 : timezone) / 60) + +#endif + + +void ngx_timezone_update(void); +void ngx_localtime(time_t s, ngx_tm_t *tm); +void ngx_libc_localtime(time_t s, struct tm *tm); +void ngx_libc_gmtime(time_t s, struct tm *tm); + +#define ngx_gettimeofday(tp) (void) gettimeofday(tp, NULL); +#define ngx_msleep(ms) (void) usleep(ms * 1000) +#define ngx_sleep(s) (void) sleep(s) + + +#endif /* _NGX_TIME_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_udp_recv.c b/app/nginx/src/os/unix/ngx_udp_recv.c new file mode 100644 index 0000000..6d544c2 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_udp_recv.c @@ -0,0 +1,72 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +ssize_t +ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *rev; + + rev = c->read; + + do { + n = recv(c->fd, buf, size, 0); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "recv: fd:%d %z of %uz", c->fd, n, size); + + if (n >= 0) { + +#if (NGX_HAVE_KQUEUE) + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + rev->available -= n; + + /* + * rev->available may be negative here because some additional + * bytes may be received between kevent() and recv() + */ + + if (rev->available <= 0) { + rev->ready = 0; + rev->available = 0; + } + } + +#endif + + return n; + } + + err = ngx_socket_errno; + + if (err == NGX_EAGAIN || err == NGX_EINTR) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "recv() not ready"); + n = NGX_AGAIN; + + } else { + n = ngx_connection_error(c, err, "recv() failed"); + break; + } + + } while (err == NGX_EINTR); + + rev->ready = 0; + + if (n == NGX_ERROR) { + rev->error = 1; + } + + return n; +} diff --git a/app/nginx/src/os/unix/ngx_udp_send.c b/app/nginx/src/os/unix/ngx_udp_send.c new file mode 100644 index 0000000..aabbc8e --- /dev/null +++ b/app/nginx/src/os/unix/ngx_udp_send.c @@ -0,0 +1,56 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +ssize_t +ngx_udp_unix_send(ngx_connection_t *c, u_char *buf, size_t size) +{ + ssize_t n; + ngx_err_t err; + ngx_event_t *wev; + + wev = c->write; + + for ( ;; ) { + n = sendto(c->fd, buf, size, 0, c->sockaddr, c->socklen); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendto: fd:%d %z of %uz to \"%V\"", + c->fd, n, size, &c->addr_text); + + if (n >= 0) { + if ((size_t) n != size) { + wev->error = 1; + (void) ngx_connection_error(c, 0, "sendto() incomplete"); + return NGX_ERROR; + } + + c->sent += n; + + return n; + } + + err = ngx_socket_errno; + + if (err == NGX_EAGAIN) { + wev->ready = 0; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, NGX_EAGAIN, + "sendto() not ready"); + return NGX_AGAIN; + } + + if (err != NGX_EINTR) { + wev->error = 1; + (void) ngx_connection_error(c, err, "sendto() failed"); + return NGX_ERROR; + } + } +} diff --git a/app/nginx/src/os/unix/ngx_udp_sendmsg_chain.c b/app/nginx/src/os/unix/ngx_udp_sendmsg_chain.c new file mode 100644 index 0000000..65bde6f --- /dev/null +++ b/app/nginx/src/os/unix/ngx_udp_sendmsg_chain.c @@ -0,0 +1,245 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +static ngx_chain_t *ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, + ngx_chain_t *in, ngx_log_t *log); +static ssize_t ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec); + + +ngx_chain_t * +ngx_udp_unix_sendmsg_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + ssize_t n; + off_t send; + ngx_chain_t *cl; + ngx_event_t *wev; + ngx_iovec_t vec; + struct iovec iovs[NGX_IOVS_PREALLOCATE]; + + wev = c->write; + + if (!wev->ready) { + return in; + } + +#if (NGX_HAVE_KQUEUE) + + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) { + (void) ngx_connection_error(c, wev->kq_errno, + "kevent() reported about an closed connection"); + wev->error = 1; + return NGX_CHAIN_ERROR; + } + +#endif + + /* the maximum limit size is the maximum size_t value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) { + limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; + } + + send = 0; + + vec.iovs = iovs; + vec.nalloc = NGX_IOVS_PREALLOCATE; + + for ( ;; ) { + + /* create the iovec and coalesce the neighbouring bufs */ + + cl = ngx_udp_output_chain_to_iovec(&vec, in, c->log); + + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (cl && cl->buf->in_file) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "file buf in sendmsg " + "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(); + + return NGX_CHAIN_ERROR; + } + + if (cl == in) { + return in; + } + + send += vec.size; + + n = ngx_sendmsg(c, &vec); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (n == NGX_AGAIN) { + wev->ready = 0; + return in; + } + + c->sent += n; + + in = ngx_chain_update_sent(in, n); + + if (send >= limit || in == NULL) { + return in; + } + } +} + + +static ngx_chain_t * +ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log) +{ + size_t total, size; + u_char *prev; + ngx_uint_t n, flush; + ngx_chain_t *cl; + struct iovec *iov; + + cl = in; + iov = NULL; + prev = NULL; + total = 0; + n = 0; + flush = 0; + + for ( /* void */ ; in && !flush; in = in->next) { + + if (in->buf->flush || in->buf->last_buf) { + flush = 1; + } + + if (ngx_buf_special(in->buf)) { + continue; + } + + if (in->buf->in_file) { + break; + } + + if (!ngx_buf_in_memory(in->buf)) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "bad buf in output chain " + "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(); + + return NGX_CHAIN_ERROR; + } + + size = in->buf->last - in->buf->pos; + + if (prev == in->buf->pos) { + iov->iov_len += size; + + } else { + if (n == vec->nalloc) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "too many parts in a datagram"); + return NGX_CHAIN_ERROR; + } + + iov = &vec->iovs[n++]; + + iov->iov_base = (void *) in->buf->pos; + iov->iov_len = size; + } + + prev = in->buf->pos + size; + total += size; + } + + if (!flush) { +#if (NGX_SUPPRESS_WARN) + vec->size = 0; + vec->count = 0; +#endif + return cl; + } + + vec->count = n; + vec->size = total; + + return in; +} + + +static ssize_t +ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec) +{ + ssize_t n; + ngx_err_t err; + struct msghdr msg; + + ngx_memzero(&msg, sizeof(struct msghdr)); + + if (c->socklen) { + msg.msg_name = c->sockaddr; + msg.msg_namelen = c->socklen; + } + + msg.msg_iov = vec->iovs; + msg.msg_iovlen = vec->count; + +eintr: + + n = sendmsg(c->fd, &msg, 0); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendmsg: %z of %uz", n, vec->size); + + if (n == -1) { + err = ngx_errno; + + switch (err) { + case NGX_EAGAIN: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendmsg() not ready"); + return NGX_AGAIN; + + case NGX_EINTR: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "sendmsg() was interrupted"); + goto eintr; + + default: + c->write->error = 1; + ngx_connection_error(c, err, "sendmsg() failed"); + return NGX_ERROR; + } + } + + return n; +} diff --git a/app/nginx/src/os/unix/ngx_user.c b/app/nginx/src/os/unix/ngx_user.c new file mode 100644 index 0000000..27c76ef --- /dev/null +++ b/app/nginx/src/os/unix/ngx_user.c @@ -0,0 +1,90 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +/* + * Solaris has thread-safe crypt() + * Linux has crypt_r(); "struct crypt_data" is more than 128K + * FreeBSD needs the mutex to protect crypt() + * + * TODO: + * ngx_crypt_init() to init mutex + */ + + +#if (NGX_CRYPT) + +#if (NGX_HAVE_GNU_CRYPT_R) + +ngx_int_t +ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) +{ + char *value; + size_t len; + struct crypt_data cd; + + cd.initialized = 0; +#ifdef __GLIBC__ + /* work around the glibc bug */ + cd.current_salt[0] = ~salt[0]; +#endif + + value = crypt_r((char *) key, (char *) salt, &cd); + + if (value) { + len = ngx_strlen(value) + 1; + + *encrypted = ngx_pnalloc(pool, len); + if (*encrypted == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(*encrypted, value, len); + return NGX_OK; + } + + ngx_log_error(NGX_LOG_CRIT, pool->log, ngx_errno, "crypt_r() failed"); + + return NGX_ERROR; +} + +#else + +ngx_int_t +ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) +{ + char *value; + size_t len; + ngx_err_t err; + + value = crypt((char *) key, (char *) salt); + + if (value) { + len = ngx_strlen(value) + 1; + + *encrypted = ngx_pnalloc(pool, len); + if (*encrypted == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(*encrypted, value, len); + return NGX_OK; + } + + err = ngx_errno; + + ngx_log_error(NGX_LOG_CRIT, pool->log, err, "crypt() failed"); + + return NGX_ERROR; +} + +#endif + +#endif /* NGX_CRYPT */ diff --git a/app/nginx/src/os/unix/ngx_user.h b/app/nginx/src/os/unix/ngx_user.h new file mode 100644 index 0000000..6e82204 --- /dev/null +++ b/app/nginx/src/os/unix/ngx_user.h @@ -0,0 +1,24 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_USER_H_INCLUDED_ +#define _NGX_USER_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +typedef uid_t ngx_uid_t; +typedef gid_t ngx_gid_t; + + +ngx_int_t ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, + u_char **encrypted); + + +#endif /* _NGX_USER_H_INCLUDED_ */ diff --git a/app/nginx/src/os/unix/ngx_writev_chain.c b/app/nginx/src/os/unix/ngx_writev_chain.c new file mode 100644 index 0000000..e38a3aa --- /dev/null +++ b/app/nginx/src/os/unix/ngx_writev_chain.c @@ -0,0 +1,216 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +ngx_chain_t * +ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + ssize_t n, sent; + off_t send, prev_send; + ngx_chain_t *cl; + ngx_event_t *wev; + ngx_iovec_t vec; + struct iovec iovs[NGX_IOVS_PREALLOCATE]; + + wev = c->write; + + if (!wev->ready) { + return in; + } + +#if (NGX_HAVE_KQUEUE) + + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) { + (void) ngx_connection_error(c, wev->kq_errno, + "kevent() reported about an closed connection"); + wev->error = 1; + return NGX_CHAIN_ERROR; + } + +#endif + + /* the maximum limit size is the maximum size_t value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) { + limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; + } + + send = 0; + + vec.iovs = iovs; + vec.nalloc = NGX_IOVS_PREALLOCATE; + + for ( ;; ) { + prev_send = send; + + /* create the iovec and coalesce the neighbouring bufs */ + + cl = ngx_output_chain_to_iovec(&vec, in, limit - send, c->log); + + if (cl == NGX_CHAIN_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (cl && cl->buf->in_file) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "file buf in writev " + "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(); + + return NGX_CHAIN_ERROR; + } + + send += vec.size; + + n = ngx_writev(c, &vec); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + sent = (n == NGX_AGAIN) ? 0 : n; + + c->sent += sent; + + in = ngx_chain_update_sent(in, sent); + + if (send - prev_send != sent) { + wev->ready = 0; + return in; + } + + if (send >= limit || in == NULL) { + return in; + } + } +} + + +ngx_chain_t * +ngx_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, size_t limit, + ngx_log_t *log) +{ + size_t total, size; + u_char *prev; + ngx_uint_t n; + struct iovec *iov; + + iov = NULL; + prev = NULL; + total = 0; + n = 0; + + for ( /* void */ ; in && total < limit; in = in->next) { + + if (ngx_buf_special(in->buf)) { + continue; + } + + if (in->buf->in_file) { + break; + } + + if (!ngx_buf_in_memory(in->buf)) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "bad buf in output chain " + "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(); + + return NGX_CHAIN_ERROR; + } + + size = in->buf->last - in->buf->pos; + + if (size > limit - total) { + size = limit - total; + } + + if (prev == in->buf->pos) { + iov->iov_len += size; + + } else { + if (n == vec->nalloc) { + break; + } + + iov = &vec->iovs[n++]; + + iov->iov_base = (void *) in->buf->pos; + iov->iov_len = size; + } + + prev = in->buf->pos + size; + total += size; + } + + vec->count = n; + vec->size = total; + + return in; +} + + +ssize_t +ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec) +{ + ssize_t n; + ngx_err_t err; + +eintr: + + n = writev(c->fd, vec->iovs, vec->count); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "writev: %z of %uz", n, vec->size); + + if (n == -1) { + err = ngx_errno; + + switch (err) { + case NGX_EAGAIN: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "writev() not ready"); + return NGX_AGAIN; + + case NGX_EINTR: + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "writev() was interrupted"); + goto eintr; + + default: + c->write->error = 1; + ngx_connection_error(c, err, "writev() failed"); + return NGX_ERROR; + } + } + + return n; +} diff --git a/app/nginx/src/os/win32/nginx.ico b/app/nginx/src/os/win32/nginx.ico Binary files differnew file mode 100644 index 0000000..70f79db --- /dev/null +++ b/app/nginx/src/os/win32/nginx.ico diff --git a/app/nginx/src/os/win32/nginx.rc b/app/nginx/src/os/win32/nginx.rc new file mode 100644 index 0000000..dc8b7ab --- /dev/null +++ b/app/nginx/src/os/win32/nginx.rc @@ -0,0 +1,6 @@ + +// Copyright (C) Igor Sysoev +// Copyright (C) Nginx, Inc. + + +nginx icon discardable "src\\os\\win32\\nginx.ico" diff --git a/app/nginx/src/os/win32/nginx_icon16.xpm b/app/nginx/src/os/win32/nginx_icon16.xpm new file mode 100644 index 0000000..45e4bad --- /dev/null +++ b/app/nginx/src/os/win32/nginx_icon16.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char * nginx_xpm[] = { +"16 16 2 2", +/* colors */ +" c none", +"GG c #009900", +/* pixels */ +" ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGG ", +" GGGGGG GGGGGG ", +" GGGGGG GGGGGG ", +" GGGGGG ", +" GGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGG GGGGGGGGGGGGGGGGGG ", +" GGGGGG GGGGGGGGGGGGGG ", +" GGGGGG GGGGGG ", +" GGGGGG GGGGGG ", +" GGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" " +}; diff --git a/app/nginx/src/os/win32/nginx_icon32.xpm b/app/nginx/src/os/win32/nginx_icon32.xpm new file mode 100644 index 0000000..eb26638 --- /dev/null +++ b/app/nginx/src/os/win32/nginx_icon32.xpm @@ -0,0 +1,39 @@ +/* XPM */ +static char * nginx_xpm[] = { +"32 32 2 2", +/* colors */ +" c none", +"GG c #009900", +/* pixels */ +" ", +" ", +" ", +" ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG ", +" GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGG GGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" ", +" ", +" ", +" " diff --git a/app/nginx/src/os/win32/nginx_icon48.xpm b/app/nginx/src/os/win32/nginx_icon48.xpm new file mode 100644 index 0000000..c25ba0f --- /dev/null +++ b/app/nginx/src/os/win32/nginx_icon48.xpm @@ -0,0 +1,55 @@ +/* XPM */ +static char * nginx_xpm[] = { +"48 48 2 2", +/* colors */ +" c none", +"GG c #009900", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG ", +" ", +" ", +" ", +" ", +" ", diff --git a/app/nginx/src/os/win32/ngx_alloc.c b/app/nginx/src/os/win32/ngx_alloc.c new file mode 100644 index 0000000..0c0ef30 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_alloc.c @@ -0,0 +1,44 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +ngx_uint_t ngx_pagesize; +ngx_uint_t ngx_pagesize_shift; +ngx_uint_t ngx_cacheline_size; + + +void *ngx_alloc(size_t size, ngx_log_t *log) +{ + void *p; + + p = malloc(size); + if (p == NULL) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "malloc(%uz) failed", size); + } + + ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size); + + return p; +} + + +void *ngx_calloc(size_t size, ngx_log_t *log) +{ + void *p; + + p = ngx_alloc(size, log); + + if (p) { + ngx_memzero(p, size); + } + + return p; +} diff --git a/app/nginx/src/os/win32/ngx_alloc.h b/app/nginx/src/os/win32/ngx_alloc.h new file mode 100644 index 0000000..5a0fa3f --- /dev/null +++ b/app/nginx/src/os/win32/ngx_alloc.h @@ -0,0 +1,27 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_ALLOC_H_INCLUDED_ +#define _NGX_ALLOC_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +void *ngx_alloc(size_t size, ngx_log_t *log); +void *ngx_calloc(size_t size, ngx_log_t *log); + +#define ngx_free free +#define ngx_memalign(alignment, size, log) ngx_alloc(size, log) + +extern ngx_uint_t ngx_pagesize; +extern ngx_uint_t ngx_pagesize_shift; +extern ngx_uint_t ngx_cacheline_size; + + +#endif /* _NGX_ALLOC_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_atomic.h b/app/nginx/src/os/win32/ngx_atomic.h new file mode 100644 index 0000000..113f561 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_atomic.h @@ -0,0 +1,69 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_ATOMIC_H_INCLUDED_ +#define _NGX_ATOMIC_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define NGX_HAVE_ATOMIC_OPS 1 + +typedef int32_t ngx_atomic_int_t; +typedef uint32_t ngx_atomic_uint_t; +typedef volatile ngx_atomic_uint_t ngx_atomic_t; +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) + + +#if defined( __WATCOMC__ ) || defined( __BORLANDC__ ) || defined(__GNUC__) \ + || ( _MSC_VER >= 1300 ) + +/* the new SDK headers */ + +#define ngx_atomic_cmp_set(lock, old, set) \ + ((ngx_atomic_uint_t) InterlockedCompareExchange((long *) lock, set, old) \ + == old) + +#else + +/* the old MS VC6.0SP2 SDK headers */ + +#define ngx_atomic_cmp_set(lock, old, set) \ + (InterlockedCompareExchange((void **) lock, (void *) set, (void *) old) \ + == (void *) old) + +#endif + + +#define ngx_atomic_fetch_add(p, add) InterlockedExchangeAdd((long *) p, add) + + +#define ngx_memory_barrier() + + +#if defined( __BORLANDC__ ) || ( __WATCOMC__ < 1230 ) + +/* + * Borland C++ 5.5 (tasm32) and Open Watcom C prior to 1.3 + * do not understand the "pause" instruction + */ + +#define ngx_cpu_pause() +#else +#define ngx_cpu_pause() __asm { pause } +#endif + + +void ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin); + +#define ngx_trylock(lock) (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1)) +#define ngx_unlock(lock) *(lock) = 0 + + +#endif /* _NGX_ATOMIC_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_dlopen.c b/app/nginx/src/os/win32/ngx_dlopen.c new file mode 100644 index 0000000..804f49d --- /dev/null +++ b/app/nginx/src/os/win32/ngx_dlopen.c @@ -0,0 +1,22 @@ + +/* + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +char * +ngx_dlerror(void) +{ + u_char *p; + static u_char errstr[NGX_MAX_ERROR_STR]; + + p = ngx_strerror(ngx_errno, errstr, NGX_MAX_ERROR_STR); + *p = '\0'; + + return (char *) errstr; +} diff --git a/app/nginx/src/os/win32/ngx_dlopen.h b/app/nginx/src/os/win32/ngx_dlopen.h new file mode 100644 index 0000000..0d6b405 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_dlopen.h @@ -0,0 +1,32 @@ + +/* + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_DLOPEN_H_INCLUDED_ +#define _NGX_DLOPEN_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define NGX_HAVE_DLOPEN 1 + + +#define ngx_dlopen(path) LoadLibrary((char *) path) +#define ngx_dlopen_n "LoadLibrary()" + +#define ngx_dlsym(handle, symbol) (void *) GetProcAddress(handle, symbol) +#define ngx_dlsym_n "GetProcAddress()" + +#define ngx_dlclose(handle) (FreeLibrary(handle) ? 0 : -1) +#define ngx_dlclose_n "FreeLibrary()" + + +char *ngx_dlerror(void); + + +#endif /* _NGX_DLOPEN_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_errno.c b/app/nginx/src/os/win32/ngx_errno.c new file mode 100644 index 0000000..b732bf4 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_errno.c @@ -0,0 +1,60 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +u_char * +ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) +{ + u_int len; + static u_long lang = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); + + if (size == 0) { + return errstr; + } + + len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, lang, (char *) errstr, size, NULL); + + if (len == 0 && lang && GetLastError() == ERROR_RESOURCE_LANG_NOT_FOUND) { + + /* + * Try to use English messages first and fallback to a language, + * based on locale: non-English Windows have no English messages + * at all. This way allows to use English messages at least on + * Windows with MUI. + */ + + lang = 0; + + len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, lang, (char *) errstr, size, NULL); + } + + if (len == 0) { + return ngx_snprintf(errstr, size, + "FormatMessage() error:(%d)", GetLastError()); + } + + /* remove ".\r\n\0" */ + while (errstr[len] == '\0' || errstr[len] == CR + || errstr[len] == LF || errstr[len] == '.') + { + --len; + } + + return &errstr[++len]; +} + + +ngx_int_t +ngx_strerror_init(void) +{ + return NGX_OK; +} diff --git a/app/nginx/src/os/win32/ngx_errno.h b/app/nginx/src/os/win32/ngx_errno.h new file mode 100644 index 0000000..255a39d --- /dev/null +++ b/app/nginx/src/os/win32/ngx_errno.h @@ -0,0 +1,71 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_ERRNO_H_INCLUDED_ +#define _NGX_ERRNO_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +typedef DWORD ngx_err_t; + +#define ngx_errno GetLastError() +#define ngx_set_errno(err) SetLastError(err) +#define ngx_socket_errno WSAGetLastError() +#define ngx_set_socket_errno(err) WSASetLastError(err) + +#define NGX_EPERM ERROR_ACCESS_DENIED +#define NGX_ENOENT ERROR_FILE_NOT_FOUND +#define NGX_ENOPATH ERROR_PATH_NOT_FOUND +#define NGX_ENOMEM ERROR_NOT_ENOUGH_MEMORY +#define NGX_EACCES ERROR_ACCESS_DENIED +/* + * there are two EEXIST error codes: + * ERROR_FILE_EXISTS used by CreateFile(CREATE_NEW), + * and ERROR_ALREADY_EXISTS used by CreateDirectory(); + * MoveFile() uses both + */ +#define NGX_EEXIST ERROR_ALREADY_EXISTS +#define NGX_EEXIST_FILE ERROR_FILE_EXISTS +#define NGX_EXDEV ERROR_NOT_SAME_DEVICE +#define NGX_ENOTDIR ERROR_PATH_NOT_FOUND +#define NGX_EISDIR ERROR_CANNOT_MAKE +#define NGX_ENOSPC ERROR_DISK_FULL +#define NGX_EPIPE EPIPE +#define NGX_EAGAIN WSAEWOULDBLOCK +#define NGX_EINPROGRESS WSAEINPROGRESS +#define NGX_ENOPROTOOPT WSAENOPROTOOPT +#define NGX_EOPNOTSUPP WSAEOPNOTSUPP +#define NGX_EADDRINUSE WSAEADDRINUSE +#define NGX_ECONNABORTED WSAECONNABORTED +#define NGX_ECONNRESET WSAECONNRESET +#define NGX_ENOTCONN WSAENOTCONN +#define NGX_ETIMEDOUT WSAETIMEDOUT +#define NGX_ECONNREFUSED WSAECONNREFUSED +#define NGX_ENAMETOOLONG ERROR_BAD_PATHNAME +#define NGX_ENETDOWN WSAENETDOWN +#define NGX_ENETUNREACH WSAENETUNREACH +#define NGX_EHOSTDOWN WSAEHOSTDOWN +#define NGX_EHOSTUNREACH WSAEHOSTUNREACH +#define NGX_ENOMOREFILES ERROR_NO_MORE_FILES +#define NGX_EILSEQ ERROR_NO_UNICODE_TRANSLATION +#define NGX_ELOOP 0 +#define NGX_EBADF WSAEBADF + +#define NGX_EALREADY WSAEALREADY +#define NGX_EINVAL WSAEINVAL +#define NGX_EMFILE WSAEMFILE +#define NGX_ENFILE WSAEMFILE + + +u_char *ngx_strerror(ngx_err_t err, u_char *errstr, size_t size); +ngx_int_t ngx_strerror_init(void); + + +#endif /* _NGX_ERRNO_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_event_log.c b/app/nginx/src/os/win32/ngx_event_log.c new file mode 100644 index 0000000..e11ed1e --- /dev/null +++ b/app/nginx/src/os/win32/ngx_event_log.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define NGX_MAX_ERROR_STR 2048 + + +void ngx_cdecl +ngx_event_log(ngx_err_t err, const char *fmt, ...) +{ + u_char *p, *last; + long types; + HKEY key; + HANDLE ev; + va_list args; + u_char text[NGX_MAX_ERROR_STR]; + const char *msgarg[9]; + static u_char netmsg[] = "%SystemRoot%\\System32\\netmsg.dll"; + + last = text + NGX_MAX_ERROR_STR; + p = text + GetModuleFileName(NULL, (char *) text, NGX_MAX_ERROR_STR - 50); + + *p++ = ':'; + ngx_linefeed(p); + + va_start(args, fmt); + p = ngx_vslprintf(p, last, fmt, args); + va_end(args); + + if (err) { + p = ngx_log_errno(p, last, err); + } + + if (p > last - NGX_LINEFEED_SIZE - 1) { + p = last - NGX_LINEFEED_SIZE - 1; + } + + ngx_linefeed(p); + + *p = '\0'; + + /* + * we do not log errors here since we use + * Event Log only to log our own logs open errors + */ + + if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\nginx", + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &key, NULL) + != 0) + { + return; + } + + if (RegSetValueEx(key, "EventMessageFile", 0, REG_EXPAND_SZ, + netmsg, sizeof(netmsg) - 1) + != 0) + { + return; + } + + types = EVENTLOG_ERROR_TYPE; + + if (RegSetValueEx(key, "TypesSupported", 0, REG_DWORD, + (u_char *) &types, sizeof(long)) + != 0) + { + return; + } + + RegCloseKey(key); + + ev = RegisterEventSource(NULL, "nginx"); + + msgarg[0] = (char *) text; + msgarg[1] = NULL; + msgarg[2] = NULL; + msgarg[3] = NULL; + msgarg[4] = NULL; + msgarg[5] = NULL; + msgarg[6] = NULL; + msgarg[7] = NULL; + msgarg[8] = NULL; + + /* + * the 3299 event id in netmsg.dll has the generic message format: + * "%1 %2 %3 %4 %5 %6 %7 %8 %9" + */ + + ReportEvent(ev, EVENTLOG_ERROR_TYPE, 0, 3299, NULL, 9, 0, msgarg, NULL); + + DeregisterEventSource(ev); +} diff --git a/app/nginx/src/os/win32/ngx_files.c b/app/nginx/src/os/win32/ngx_files.c new file mode 100644 index 0000000..9ef22a5 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_files.c @@ -0,0 +1,883 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define NGX_UTF16_BUFLEN 256 + +static ngx_int_t ngx_win32_check_filename(u_char *name, u_short *u, + size_t len); +static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len); + + +/* FILE_FLAG_BACKUP_SEMANTICS allows to obtain a handle to a directory */ + +ngx_fd_t +ngx_open_file(u_char *name, u_long mode, u_long create, u_long access) +{ + size_t len; + u_short *u; + ngx_fd_t fd; + ngx_err_t err; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + u = ngx_utf8_to_utf16(utf16, name, &len); + + if (u == NULL) { + return INVALID_HANDLE_VALUE; + } + + fd = INVALID_HANDLE_VALUE; + + if (create == NGX_FILE_OPEN + && ngx_win32_check_filename(name, u, len) != NGX_OK) + { + goto failed; + } + + fd = CreateFileW(u, mode, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + NULL, create, FILE_FLAG_BACKUP_SEMANTICS, NULL); + +failed: + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return fd; +} + + +ssize_t +ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) +{ + u_long n; + ngx_err_t err; + OVERLAPPED ovlp, *povlp; + + ovlp.Internal = 0; + ovlp.InternalHigh = 0; + ovlp.Offset = (u_long) offset; + ovlp.OffsetHigh = (u_long) (offset >> 32); + ovlp.hEvent = NULL; + + povlp = &ovlp; + + if (ReadFile(file->fd, buf, size, &n, povlp) == 0) { + err = ngx_errno; + + if (err == ERROR_HANDLE_EOF) { + return 0; + } + + ngx_log_error(NGX_LOG_ERR, file->log, err, + "ReadFile() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + file->offset += n; + + return n; +} + + +ssize_t +ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) +{ + u_long n; + OVERLAPPED ovlp, *povlp; + + ovlp.Internal = 0; + ovlp.InternalHigh = 0; + ovlp.Offset = (u_long) offset; + ovlp.OffsetHigh = (u_long) (offset >> 32); + ovlp.hEvent = NULL; + + povlp = &ovlp; + + if (WriteFile(file->fd, buf, size, &n, povlp) == 0) { + ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, + "WriteFile() \"%s\" failed", file->name.data); + return NGX_ERROR; + } + + if (n != size) { + ngx_log_error(NGX_LOG_CRIT, file->log, 0, + "WriteFile() \"%s\" has written only %ul of %uz", + file->name.data, n, size); + return NGX_ERROR; + } + + file->offset += n; + + return n; +} + + +ssize_t +ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, + ngx_pool_t *pool) +{ + u_char *buf, *prev; + size_t size; + ssize_t total, n; + + total = 0; + + while (cl) { + buf = cl->buf->pos; + prev = buf; + size = 0; + + /* coalesce the neighbouring bufs */ + + while (cl && prev == cl->buf->pos) { + size += cl->buf->last - cl->buf->pos; + prev = cl->buf->last; + cl = cl->next; + } + + n = ngx_write_file(file, buf, size, offset); + + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + total += n; + offset += n; + } + + return total; +} + + +ssize_t +ngx_read_fd(ngx_fd_t fd, void *buf, size_t size) +{ + u_long n; + + if (ReadFile(fd, buf, size, &n, NULL) != 0) { + return (size_t) n; + } + + return -1; +} + + +ssize_t +ngx_write_fd(ngx_fd_t fd, void *buf, size_t size) +{ + u_long n; + + if (WriteFile(fd, buf, size, &n, NULL) != 0) { + return (size_t) n; + } + + return -1; +} + + +ssize_t +ngx_write_console(ngx_fd_t fd, void *buf, size_t size) +{ + u_long n; + + (void) CharToOemBuff(buf, buf, size); + + if (WriteFile(fd, buf, size, &n, NULL) != 0) { + return (size_t) n; + } + + return -1; +} + + +ngx_err_t +ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log) +{ + u_char *name; + ngx_err_t err; + ngx_uint_t collision; + ngx_atomic_uint_t num; + + name = ngx_alloc(to->len + 1 + NGX_ATOMIC_T_LEN + 1 + sizeof("DELETE"), + log); + if (name == NULL) { + return NGX_ENOMEM; + } + + ngx_memcpy(name, to->data, to->len); + + collision = 0; + + /* mutex_lock() (per cache or single ?) */ + + for ( ;; ) { + num = ngx_next_temp_number(collision); + + ngx_sprintf(name + to->len, ".%0muA.DELETE%Z", num); + + if (MoveFile((const char *) to->data, (const char *) name) != 0) { + break; + } + + collision = 1; + + ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, + "MoveFile() \"%s\" to \"%s\" failed", to->data, name); + } + + if (MoveFile((const char *) from->data, (const char *) to->data) == 0) { + err = ngx_errno; + + } else { + err = 0; + } + + if (DeleteFile((const char *) name) == 0) { + ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, + "DeleteFile() \"%s\" failed", name); + } + + /* mutex_unlock() */ + + ngx_free(name); + + return err; +} + + +ngx_int_t +ngx_file_info(u_char *file, ngx_file_info_t *sb) +{ + size_t len; + long rc; + u_short *u; + ngx_err_t err; + WIN32_FILE_ATTRIBUTE_DATA fa; + u_short utf16[NGX_UTF16_BUFLEN]; + + len = NGX_UTF16_BUFLEN; + + u = ngx_utf8_to_utf16(utf16, file, &len); + + if (u == NULL) { + return NGX_FILE_ERROR; + } + + rc = NGX_FILE_ERROR; + + if (ngx_win32_check_filename(file, u, len) != NGX_OK) { + goto failed; + } + + rc = GetFileAttributesExW(u, GetFileExInfoStandard, &fa); + + sb->dwFileAttributes = fa.dwFileAttributes; + sb->ftCreationTime = fa.ftCreationTime; + sb->ftLastAccessTime = fa.ftLastAccessTime; + sb->ftLastWriteTime = fa.ftLastWriteTime; + sb->nFileSizeHigh = fa.nFileSizeHigh; + sb->nFileSizeLow = fa.nFileSizeLow; + +failed: + + if (u != utf16) { + err = ngx_errno; + ngx_free(u); + ngx_set_errno(err); + } + + return rc; +} + + +ngx_int_t +ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s) +{ + uint64_t intervals; + FILETIME ft; + + /* 116444736000000000 is commented in src/os/win32/ngx_time.c */ + + intervals = s * 10000000 + 116444736000000000; + + ft.dwLowDateTime = (DWORD) intervals; + ft.dwHighDateTime = (DWORD) (intervals >> 32); + + if (SetFileTime(fd, NULL, NULL, &ft) != 0) { + return NGX_OK; + } + + return NGX_ERROR; +} + + +ngx_int_t +ngx_create_file_mapping(ngx_file_mapping_t *fm) +{ + LARGE_INTEGER size; + + fm->fd = ngx_open_file(fm->name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, + NGX_FILE_DEFAULT_ACCESS); + if (fm->fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", fm->name); + return NGX_ERROR; + } + + fm->handle = NULL; + + size.QuadPart = fm->size; + + if (SetFilePointerEx(fm->fd, size, NULL, FILE_BEGIN) == 0) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "SetFilePointerEx(\"%s\", %uz) failed", + fm->name, fm->size); + goto failed; + } + + if (SetEndOfFile(fm->fd) == 0) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "SetEndOfFile() \"%s\" failed", fm->name); + goto failed; + } + + fm->handle = CreateFileMapping(fm->fd, NULL, PAGE_READWRITE, + (u_long) ((off_t) fm->size >> 32), + (u_long) ((off_t) fm->size & 0xffffffff), + NULL); + if (fm->handle == NULL) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "CreateFileMapping(%s, %uz) failed", + fm->name, fm->size); + goto failed; + } + + fm->addr = MapViewOfFile(fm->handle, FILE_MAP_WRITE, 0, 0, 0); + + if (fm->addr != NULL) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "MapViewOfFile(%uz) of file mapping \"%s\" failed", + fm->size, fm->name); + +failed: + + if (fm->handle) { + if (CloseHandle(fm->handle) == 0) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + "CloseHandle() of file mapping \"%s\" failed", + fm->name); + } + } + + if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", fm->name); + } + + return NGX_ERROR; +} + + +void +ngx_close_file_mapping(ngx_file_mapping_t *fm) +{ + if (UnmapViewOfFile(fm->addr) == 0) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + "UnmapViewOfFile(%p) of file mapping \"%s\" failed", + fm->addr, &fm->name); + } + + if (CloseHandle(fm->handle) == 0) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + "CloseHandle() of file mapping \"%s\" failed", + &fm->name); + } + + if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", fm->name); + } +} + + +u_char * +ngx_realpath(u_char *path, u_char *resolved) +{ + /* STUB */ + return path; +} + + +ngx_int_t +ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir) +{ + ngx_cpystrn(name->data + name->len, NGX_DIR_MASK, NGX_DIR_MASK_LEN + 1); + + dir->dir = FindFirstFile((const char *) name->data, &dir->finddata); + + name->data[name->len] = '\0'; + + if (dir->dir == INVALID_HANDLE_VALUE) { + return NGX_ERROR; + } + + dir->valid_info = 1; + dir->ready = 1; + + return NGX_OK; +} + + +ngx_int_t +ngx_read_dir(ngx_dir_t *dir) +{ + if (dir->ready) { + dir->ready = 0; + return NGX_OK; + } + + if (FindNextFile(dir->dir, &dir->finddata) != 0) { + dir->type = 1; + return NGX_OK; + } + + return NGX_ERROR; +} + + +ngx_int_t +ngx_close_dir(ngx_dir_t *dir) +{ + if (FindClose(dir->dir) == 0) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_open_glob(ngx_glob_t *gl) +{ + u_char *p; + size_t len; + ngx_err_t err; + + gl->dir = FindFirstFile((const char *) gl->pattern, &gl->finddata); + + if (gl->dir == INVALID_HANDLE_VALUE) { + + err = ngx_errno; + + if ((err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) + && gl->test) + { + gl->no_match = 1; + return NGX_OK; + } + + return NGX_ERROR; + } + + for (p = gl->pattern; *p; p++) { + if (*p == '/') { + gl->last = p + 1 - gl->pattern; + } + } + + len = ngx_strlen(gl->finddata.cFileName); + gl->name.len = gl->last + len; + + gl->name.data = ngx_alloc(gl->name.len + 1, gl->log); + if (gl->name.data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(gl->name.data, gl->pattern, gl->last); + ngx_cpystrn(gl->name.data + gl->last, (u_char *) gl->finddata.cFileName, + len + 1); + + gl->ready = 1; + + return NGX_OK; +} + + +ngx_int_t +ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name) +{ + size_t len; + ngx_err_t err; + + if (gl->no_match) { + return NGX_DONE; + } + + if (gl->ready) { + *name = gl->name; + + gl->ready = 0; + return NGX_OK; + } + + ngx_free(gl->name.data); + gl->name.data = NULL; + + if (FindNextFile(gl->dir, &gl->finddata) != 0) { + + len = ngx_strlen(gl->finddata.cFileName); + gl->name.len = gl->last + len; + + gl->name.data = ngx_alloc(gl->name.len + 1, gl->log); + if (gl->name.data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(gl->name.data, gl->pattern, gl->last); + ngx_cpystrn(gl->name.data + gl->last, (u_char *) gl->finddata.cFileName, + len + 1); + + *name = gl->name; + + return NGX_OK; + } + + err = ngx_errno; + + if (err == NGX_ENOMOREFILES) { + return NGX_DONE; + } + + ngx_log_error(NGX_LOG_ALERT, gl->log, err, + "FindNextFile(%s) failed", gl->pattern); + + return NGX_ERROR; +} + + +void +ngx_close_glob(ngx_glob_t *gl) +{ + if (gl->name.data) { + ngx_free(gl->name.data); + } + + if (gl->dir == INVALID_HANDLE_VALUE) { + return; + } + + if (FindClose(gl->dir) == 0) { + ngx_log_error(NGX_LOG_ALERT, gl->log, ngx_errno, + "FindClose(%s) failed", gl->pattern); + } +} + + +ngx_int_t +ngx_de_info(u_char *name, ngx_dir_t *dir) +{ + return NGX_OK; +} + + +ngx_int_t +ngx_de_link_info(u_char *name, ngx_dir_t *dir) +{ + return NGX_OK; +} + + +ngx_int_t +ngx_read_ahead(ngx_fd_t fd, size_t n) +{ + return ~NGX_FILE_ERROR; +} + + +ngx_int_t +ngx_directio_on(ngx_fd_t fd) +{ + return ~NGX_FILE_ERROR; +} + + +ngx_int_t +ngx_directio_off(ngx_fd_t fd) +{ + return ~NGX_FILE_ERROR; +} + + +size_t +ngx_fs_bsize(u_char *name) +{ + u_char root[4]; + u_long sc, bs, nfree, ncl; + + if (name[2] == ':') { + ngx_cpystrn(root, name, 4); + name = root; + } + + if (GetDiskFreeSpace((const char *) name, &sc, &bs, &nfree, &ncl) == 0) { + return 512; + } + + return sc * bs; +} + + +static ngx_int_t +ngx_win32_check_filename(u_char *name, u_short *u, size_t len) +{ + u_char *p, ch; + u_long n; + u_short *lu; + ngx_err_t err; + enum { + sw_start = 0, + sw_normal, + sw_after_slash, + sw_after_colon, + sw_after_dot + } state; + + /* check for NTFS streams (":"), trailing dots and spaces */ + + lu = NULL; + state = sw_start; + + for (p = name; *p; p++) { + ch = *p; + + switch (state) { + + case sw_start: + + /* + * skip till first "/" to allow paths starting with drive and + * relative path, like "c:html/" + */ + + if (ch == '/' || ch == '\\') { + state = sw_after_slash; + } + + break; + + case sw_normal: + + if (ch == ':') { + state = sw_after_colon; + break; + } + + if (ch == '.' || ch == ' ') { + state = sw_after_dot; + break; + } + + if (ch == '/' || ch == '\\') { + state = sw_after_slash; + break; + } + + break; + + case sw_after_slash: + + if (ch == '/' || ch == '\\') { + break; + } + + if (ch == '.') { + break; + } + + if (ch == ':') { + state = sw_after_colon; + break; + } + + state = sw_normal; + break; + + case sw_after_colon: + + if (ch == '/' || ch == '\\') { + state = sw_after_slash; + break; + } + + goto invalid; + + case sw_after_dot: + + if (ch == '/' || ch == '\\') { + goto invalid; + } + + if (ch == ':') { + goto invalid; + } + + if (ch == '.' || ch == ' ') { + break; + } + + state = sw_normal; + break; + } + } + + if (state == sw_after_dot) { + goto invalid; + } + + /* check if long name match */ + + lu = malloc(len * 2); + if (lu == NULL) { + return NGX_ERROR; + } + + n = GetLongPathNameW(u, lu, len); + + if (n == 0) { + goto failed; + } + + if (n != len - 1 || _wcsicmp(u, lu) != 0) { + goto invalid; + } + + ngx_free(lu); + + return NGX_OK; + +invalid: + + ngx_set_errno(NGX_ENOENT); + +failed: + + if (lu) { + err = ngx_errno; + ngx_free(lu); + ngx_set_errno(err); + } + + return NGX_ERROR; +} + + +static u_short * +ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len) +{ + u_char *p; + u_short *u, *last; + uint32_t n; + + p = utf8; + u = utf16; + last = utf16 + *len; + + while (u < last) { + + if (*p < 0x80) { + *u++ = (u_short) *p; + + if (*p == 0) { + *len = u - utf16; + return utf16; + } + + p++; + + continue; + } + + if (u + 1 == last) { + *len = u - utf16; + break; + } + + n = ngx_utf8_decode(&p, 4); + + if (n > 0x10ffff) { + ngx_set_errno(NGX_EILSEQ); + return NULL; + } + + if (n > 0xffff) { + n -= 0x10000; + *u++ = (u_short) (0xd800 + (n >> 10)); + *u++ = (u_short) (0xdc00 + (n & 0x03ff)); + continue; + } + + *u++ = (u_short) n; + } + + /* the given buffer is not enough, allocate a new one */ + + u = malloc(((p - utf8) + ngx_strlen(p) + 1) * sizeof(u_short)); + if (u == NULL) { + return NULL; + } + + ngx_memcpy(u, utf16, *len * 2); + + utf16 = u; + u += *len; + + for ( ;; ) { + + if (*p < 0x80) { + *u++ = (u_short) *p; + + if (*p == 0) { + *len = u - utf16; + return utf16; + } + + p++; + + continue; + } + + n = ngx_utf8_decode(&p, 4); + + if (n > 0x10ffff) { + ngx_free(utf16); + ngx_set_errno(NGX_EILSEQ); + return NULL; + } + + if (n > 0xffff) { + n -= 0x10000; + *u++ = (u_short) (0xd800 + (n >> 10)); + *u++ = (u_short) (0xdc00 + (n & 0x03ff)); + continue; + } + + *u++ = (u_short) n; + } + + /* unreachable */ +} diff --git a/app/nginx/src/os/win32/ngx_files.h b/app/nginx/src/os/win32/ngx_files.h new file mode 100644 index 0000000..895daea --- /dev/null +++ b/app/nginx/src/os/win32/ngx_files.h @@ -0,0 +1,273 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_FILES_H_INCLUDED_ +#define _NGX_FILES_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +typedef HANDLE ngx_fd_t; +typedef BY_HANDLE_FILE_INFORMATION ngx_file_info_t; +typedef uint64_t ngx_file_uniq_t; + + +typedef struct { + u_char *name; + size_t size; + void *addr; + ngx_fd_t fd; + HANDLE handle; + ngx_log_t *log; +} ngx_file_mapping_t; + + +typedef struct { + HANDLE dir; + WIN32_FIND_DATA finddata; + + unsigned valid_info:1; + unsigned type:1; + unsigned ready:1; +} ngx_dir_t; + + +typedef struct { + HANDLE dir; + WIN32_FIND_DATA finddata; + + unsigned ready:1; + unsigned test:1; + unsigned no_match:1; + + u_char *pattern; + ngx_str_t name; + size_t last; + ngx_log_t *log; +} ngx_glob_t; + + + +/* INVALID_FILE_ATTRIBUTES is specified but not defined at least in MSVC6SP2 */ +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES 0xffffffff +#endif + +/* INVALID_SET_FILE_POINTER is not defined at least in MSVC6SP2 */ +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER 0xffffffff +#endif + + +#define NGX_INVALID_FILE INVALID_HANDLE_VALUE +#define NGX_FILE_ERROR 0 + + +ngx_fd_t ngx_open_file(u_char *name, u_long mode, u_long create, u_long access); +#define ngx_open_file_n "CreateFile()" + +#define NGX_FILE_RDONLY GENERIC_READ +#define NGX_FILE_WRONLY GENERIC_WRITE +#define NGX_FILE_RDWR GENERIC_READ|GENERIC_WRITE +#define NGX_FILE_APPEND FILE_APPEND_DATA|SYNCHRONIZE +#define NGX_FILE_NONBLOCK 0 + +#define NGX_FILE_CREATE_OR_OPEN OPEN_ALWAYS +#define NGX_FILE_OPEN OPEN_EXISTING +#define NGX_FILE_TRUNCATE CREATE_ALWAYS + +#define NGX_FILE_DEFAULT_ACCESS 0 +#define NGX_FILE_OWNER_ACCESS 0 + + +#define ngx_open_tempfile(name, persistent, access) \ + CreateFile((const char *) name, \ + GENERIC_READ|GENERIC_WRITE, \ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, \ + NULL, \ + CREATE_NEW, \ + persistent ? 0: \ + FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, \ + NULL); + +#define ngx_open_tempfile_n "CreateFile()" + + +#define ngx_close_file CloseHandle +#define ngx_close_file_n "CloseHandle()" + + +ssize_t ngx_read_fd(ngx_fd_t fd, void *buf, size_t size); +#define ngx_read_fd_n "ReadFile()" + + +ssize_t ngx_write_fd(ngx_fd_t fd, void *buf, size_t size); +#define ngx_write_fd_n "WriteFile()" + + +ssize_t ngx_write_console(ngx_fd_t fd, void *buf, size_t size); + + +#define ngx_linefeed(p) *p++ = CR; *p++ = LF; +#define NGX_LINEFEED_SIZE 2 +#define NGX_LINEFEED CRLF + + +#define ngx_delete_file(name) DeleteFile((const char *) name) +#define ngx_delete_file_n "DeleteFile()" + + +#define ngx_rename_file(o, n) MoveFile((const char *) o, (const char *) n) +#define ngx_rename_file_n "MoveFile()" +ngx_err_t ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log); + + + +ngx_int_t ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s); +#define ngx_set_file_time_n "SetFileTime()" + + +ngx_int_t ngx_file_info(u_char *filename, ngx_file_info_t *fi); +#define ngx_file_info_n "GetFileAttributesEx()" + + +#define ngx_fd_info(fd, fi) GetFileInformationByHandle(fd, fi) +#define ngx_fd_info_n "GetFileInformationByHandle()" + + +#define ngx_link_info(name, fi) ngx_file_info(name, fi) +#define ngx_link_info_n "GetFileAttributesEx()" + + +#define ngx_is_dir(fi) \ + (((fi)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) +#define ngx_is_file(fi) \ + (((fi)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) +#define ngx_is_link(fi) 0 +#define ngx_is_exec(fi) 0 + +#define ngx_file_access(fi) 0 + +#define ngx_file_size(fi) \ + (((off_t) (fi)->nFileSizeHigh << 32) | (fi)->nFileSizeLow) +#define ngx_file_fs_size(fi) ngx_file_size(fi) + +#define ngx_file_uniq(fi) (*(ngx_file_uniq_t *) &(fi)->nFileIndexHigh) + + +/* 116444736000000000 is commented in src/os/win32/ngx_time.c */ + +#define ngx_file_mtime(fi) \ + (time_t) (((((unsigned __int64) (fi)->ftLastWriteTime.dwHighDateTime << 32) \ + | (fi)->ftLastWriteTime.dwLowDateTime) \ + - 116444736000000000) / 10000000) + +ngx_int_t ngx_create_file_mapping(ngx_file_mapping_t *fm); +void ngx_close_file_mapping(ngx_file_mapping_t *fm); + + +u_char *ngx_realpath(u_char *path, u_char *resolved); +#define ngx_realpath_n "" +#define ngx_getcwd(buf, size) GetCurrentDirectory(size, (char *) buf) +#define ngx_getcwd_n "GetCurrentDirectory()" +#define ngx_path_separator(c) ((c) == '/' || (c) == '\\') + +#define NGX_HAVE_MAX_PATH 1 +#define NGX_MAX_PATH MAX_PATH + +#define NGX_DIR_MASK (u_char *) "/*" +#define NGX_DIR_MASK_LEN 2 + + +ngx_int_t ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir); +#define ngx_open_dir_n "FindFirstFile()" + + +ngx_int_t ngx_read_dir(ngx_dir_t *dir); +#define ngx_read_dir_n "FindNextFile()" + + +ngx_int_t ngx_close_dir(ngx_dir_t *dir); +#define ngx_close_dir_n "FindClose()" + + +#define ngx_create_dir(name, access) CreateDirectory((const char *) name, NULL) +#define ngx_create_dir_n "CreateDirectory()" + + +#define ngx_delete_dir(name) RemoveDirectory((const char *) name) +#define ngx_delete_dir_n "RemoveDirectory()" + + +#define ngx_dir_access(a) (a) + + +#define ngx_de_name(dir) ((u_char *) (dir)->finddata.cFileName) +#define ngx_de_namelen(dir) ngx_strlen((dir)->finddata.cFileName) + +ngx_int_t ngx_de_info(u_char *name, ngx_dir_t *dir); +#define ngx_de_info_n "dummy()" + +ngx_int_t ngx_de_link_info(u_char *name, ngx_dir_t *dir); +#define ngx_de_link_info_n "dummy()" + +#define ngx_de_is_dir(dir) \ + (((dir)->finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) +#define ngx_de_is_file(dir) \ + (((dir)->finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) +#define ngx_de_is_link(dir) 0 +#define ngx_de_access(dir) 0 +#define ngx_de_size(dir) \ + (((off_t) (dir)->finddata.nFileSizeHigh << 32) | (dir)->finddata.nFileSizeLow) +#define ngx_de_fs_size(dir) ngx_de_size(dir) + +/* 116444736000000000 is commented in src/os/win32/ngx_time.c */ + +#define ngx_de_mtime(dir) \ + (time_t) (((((unsigned __int64) \ + (dir)->finddata.ftLastWriteTime.dwHighDateTime << 32) \ + | (dir)->finddata.ftLastWriteTime.dwLowDateTime) \ + - 116444736000000000) / 10000000) + + +ngx_int_t ngx_open_glob(ngx_glob_t *gl); +#define ngx_open_glob_n "FindFirstFile()" + +ngx_int_t ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name); +void ngx_close_glob(ngx_glob_t *gl); + + +ssize_t ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset); +#define ngx_read_file_n "ReadFile()" + +ssize_t ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, + off_t offset); + +ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *ce, + off_t offset, ngx_pool_t *pool); + +ngx_int_t ngx_read_ahead(ngx_fd_t fd, size_t n); +#define ngx_read_ahead_n "ngx_read_ahead_n" + +ngx_int_t ngx_directio_on(ngx_fd_t fd); +#define ngx_directio_on_n "ngx_directio_on_n" + +ngx_int_t ngx_directio_off(ngx_fd_t fd); +#define ngx_directio_off_n "ngx_directio_off_n" + +size_t ngx_fs_bsize(u_char *name); + + +#define ngx_stdout GetStdHandle(STD_OUTPUT_HANDLE) +#define ngx_stderr GetStdHandle(STD_ERROR_HANDLE) +#define ngx_set_stderr(fd) SetStdHandle(STD_ERROR_HANDLE, fd) +#define ngx_set_stderr_n "SetStdHandle(STD_ERROR_HANDLE)" + + +#endif /* _NGX_FILES_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_os.h b/app/nginx/src/os/win32/ngx_os.h new file mode 100644 index 0000000..15f5aa0 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_os.h @@ -0,0 +1,68 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_OS_H_INCLUDED_ +#define _NGX_OS_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define NGX_IO_SENDFILE 1 + + +typedef ssize_t (*ngx_recv_pt)(ngx_connection_t *c, u_char *buf, size_t size); +typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); +typedef ssize_t (*ngx_send_pt)(ngx_connection_t *c, u_char *buf, size_t size); +typedef ngx_chain_t *(*ngx_send_chain_pt)(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + +typedef struct { + ngx_recv_pt recv; + ngx_recv_chain_pt recv_chain; + ngx_recv_pt udp_recv; + ngx_send_pt send; + ngx_send_pt udp_send; + ngx_send_chain_pt udp_send_chain; + ngx_send_chain_pt send_chain; + ngx_uint_t flags; +} ngx_os_io_t; + + +ngx_int_t ngx_os_init(ngx_log_t *log); +void ngx_os_status(ngx_log_t *log); +ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_pid_t pid); + +ssize_t ngx_wsarecv(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_udp_wsarecv(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_udp_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, + size_t size); +ssize_t ngx_wsarecv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit); +ssize_t ngx_wsasend(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_overlapped_wsasend(ngx_connection_t *c, u_char *buf, size_t size); +ngx_chain_t *ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); +ngx_chain_t *ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, + off_t limit); + +void ngx_cdecl ngx_event_log(ngx_err_t err, const char *fmt, ...); + + +extern ngx_os_io_t ngx_os_io; +extern ngx_uint_t ngx_ncpu; +extern ngx_uint_t ngx_max_wsabufs; +extern ngx_int_t ngx_max_sockets; +extern ngx_uint_t ngx_inherited_nonblocking; +extern ngx_uint_t ngx_tcp_nodelay_and_tcp_nopush; +extern ngx_uint_t ngx_win32_version; +extern char ngx_unique[]; + + +#endif /* _NGX_OS_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_process.c b/app/nginx/src/os/win32/ngx_process.c new file mode 100644 index 0000000..57b1ae9 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_process.c @@ -0,0 +1,238 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +int ngx_argc; +char **ngx_argv; +char **ngx_os_argv; + +ngx_int_t ngx_last_process; +ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; + + +ngx_pid_t +ngx_spawn_process(ngx_cycle_t *cycle, char *name, ngx_int_t respawn) +{ + u_long rc, n, code; + ngx_int_t s; + ngx_pid_t pid; + ngx_exec_ctx_t ctx; + HANDLE events[2]; + char file[MAX_PATH + 1]; + + if (respawn >= 0) { + s = respawn; + + } else { + for (s = 0; s < ngx_last_process; s++) { + if (ngx_processes[s].handle == NULL) { + break; + } + } + + if (s == NGX_MAX_PROCESSES) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "no more than %d processes can be spawned", + NGX_MAX_PROCESSES); + return NGX_INVALID_PID; + } + } + + n = GetModuleFileName(NULL, file, MAX_PATH); + + if (n == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "GetModuleFileName() failed"); + return NGX_INVALID_PID; + } + + file[n] = '\0'; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "GetModuleFileName: \"%s\"", file); + + ctx.path = file; + ctx.name = name; + ctx.args = GetCommandLine(); + ctx.argv = NULL; + ctx.envp = NULL; + + pid = ngx_execute(cycle, &ctx); + + if (pid == NGX_INVALID_PID) { + return pid; + } + + ngx_memzero(&ngx_processes[s], sizeof(ngx_process_t)); + + ngx_processes[s].handle = ctx.child; + ngx_processes[s].pid = pid; + ngx_processes[s].name = name; + + ngx_sprintf(ngx_processes[s].term_event, "ngx_%s_term_%P%Z", name, pid); + ngx_sprintf(ngx_processes[s].quit_event, "ngx_%s_quit_%P%Z", name, pid); + ngx_sprintf(ngx_processes[s].reopen_event, "ngx_%s_reopen_%P%Z", + name, pid); + + events[0] = ngx_master_process_event; + events[1] = ctx.child; + + rc = WaitForMultipleObjects(2, events, 0, 5000); + + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "WaitForMultipleObjects: %ul", rc); + + switch (rc) { + + case WAIT_OBJECT_0: + + ngx_processes[s].term = OpenEvent(EVENT_MODIFY_STATE, 0, + (char *) ngx_processes[s].term_event); + if (ngx_processes[s].term == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "OpenEvent(\"%s\") failed", + ngx_processes[s].term_event); + goto failed; + } + + ngx_processes[s].quit = OpenEvent(EVENT_MODIFY_STATE, 0, + (char *) ngx_processes[s].quit_event); + if (ngx_processes[s].quit == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "OpenEvent(\"%s\") failed", + ngx_processes[s].quit_event); + goto failed; + } + + ngx_processes[s].reopen = OpenEvent(EVENT_MODIFY_STATE, 0, + (char *) ngx_processes[s].reopen_event); + if (ngx_processes[s].reopen == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "OpenEvent(\"%s\") failed", + ngx_processes[s].reopen_event); + goto failed; + } + + if (ResetEvent(ngx_master_process_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "ResetEvent(\"%s\") failed", + ngx_master_process_event_name); + goto failed; + } + + break; + + case WAIT_OBJECT_0 + 1: + if (GetExitCodeProcess(ctx.child, &code) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "GetExitCodeProcess(%P) failed", pid); + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "%s process %P exited with code %Xl", + name, pid, code); + + goto failed; + + case WAIT_TIMEOUT: + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "the event \"%s\" was not signaled for 5s", + ngx_master_process_event_name); + goto failed; + + case WAIT_FAILED: + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "WaitForSingleObject(\"%s\") failed", + ngx_master_process_event_name); + + goto failed; + } + + if (respawn >= 0) { + return pid; + } + + switch (respawn) { + + case NGX_PROCESS_RESPAWN: + ngx_processes[s].just_spawn = 0; + break; + + case NGX_PROCESS_JUST_RESPAWN: + ngx_processes[s].just_spawn = 1; + break; + } + + if (s == ngx_last_process) { + ngx_last_process++; + } + + return pid; + +failed: + + if (ngx_processes[s].reopen) { + ngx_close_handle(ngx_processes[s].reopen); + } + + if (ngx_processes[s].quit) { + ngx_close_handle(ngx_processes[s].quit); + } + + if (ngx_processes[s].term) { + ngx_close_handle(ngx_processes[s].term); + } + + TerminateProcess(ngx_processes[s].handle, 2); + + if (ngx_processes[s].handle) { + ngx_close_handle(ngx_processes[s].handle); + ngx_processes[s].handle = NULL; + } + + return NGX_INVALID_PID; +} + + +ngx_pid_t +ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx) +{ + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ngx_memzero(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + + ngx_memzero(&pi, sizeof(PROCESS_INFORMATION)); + + if (CreateProcess(ctx->path, ctx->args, + NULL, NULL, 0, CREATE_NO_WINDOW, NULL, NULL, &si, &pi) + == 0) + { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_errno, + "CreateProcess(\"%s\") failed", ngx_argv[0]); + + return 0; + } + + ctx->child = pi.hProcess; + + if (CloseHandle(pi.hThread) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CloseHandle(pi.hThread) failed"); + } + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, + "start %s process %P", ctx->name, pi.dwProcessId); + + return pi.dwProcessId; +} diff --git a/app/nginx/src/os/win32/ngx_process.h b/app/nginx/src/os/win32/ngx_process.h new file mode 100644 index 0000000..a6a5aa2 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_process.h @@ -0,0 +1,78 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_PROCESS_H_INCLUDED_ +#define _NGX_PROCESS_H_INCLUDED_ + + +typedef DWORD ngx_pid_t; +#define NGX_INVALID_PID 0 + + +#define ngx_getpid GetCurrentProcessId +#define ngx_log_pid ngx_pid + + +#define NGX_PROCESS_SYNC_NAME \ + (sizeof("ngx_cache_manager_mutex_") + NGX_INT32_LEN) + + +typedef uint64_t ngx_cpuset_t; + + +typedef struct { + HANDLE handle; + ngx_pid_t pid; + char *name; + + HANDLE term; + HANDLE quit; + HANDLE reopen; + + u_char term_event[NGX_PROCESS_SYNC_NAME]; + u_char quit_event[NGX_PROCESS_SYNC_NAME]; + u_char reopen_event[NGX_PROCESS_SYNC_NAME]; + + unsigned just_spawn:1; + unsigned exiting:1; +} ngx_process_t; + + +typedef struct { + char *path; + char *name; + char *args; + char *const *argv; + char *const *envp; + HANDLE child; +} ngx_exec_ctx_t; + + +ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, char *name, ngx_int_t respawn); +ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx); + +#define ngx_debug_point() +#define ngx_sched_yield() SwitchToThread() + + +#define NGX_MAX_PROCESSES (MAXIMUM_WAIT_OBJECTS - 4) + +#define NGX_PROCESS_RESPAWN -2 +#define NGX_PROCESS_JUST_RESPAWN -3 + + +extern int ngx_argc; +extern char **ngx_argv; +extern char **ngx_os_argv; + +extern ngx_int_t ngx_last_process; +extern ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; + +extern ngx_pid_t ngx_pid; + + +#endif /* _NGX_PROCESS_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_process_cycle.c b/app/nginx/src/os/win32/ngx_process_cycle.c new file mode 100644 index 0000000..293b967 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_process_cycle.c @@ -0,0 +1,1042 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> +#include <nginx.h> + + +static void ngx_console_init(ngx_cycle_t *cycle); +static int __stdcall ngx_console_handler(u_long type); +static ngx_int_t ngx_create_signal_events(ngx_cycle_t *cycle); +static ngx_int_t ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t type); +static void ngx_reopen_worker_processes(ngx_cycle_t *cycle); +static void ngx_quit_worker_processes(ngx_cycle_t *cycle, ngx_uint_t old); +static void ngx_terminate_worker_processes(ngx_cycle_t *cycle); +static ngx_uint_t ngx_reap_worker(ngx_cycle_t *cycle, HANDLE h); +static void ngx_master_process_exit(ngx_cycle_t *cycle); +static void ngx_worker_process_cycle(ngx_cycle_t *cycle, char *mevn); +static void ngx_worker_process_exit(ngx_cycle_t *cycle); +static ngx_thread_value_t __stdcall ngx_worker_thread(void *data); +static ngx_thread_value_t __stdcall ngx_cache_manager_thread(void *data); +static void ngx_cache_manager_process_handler(void); +static ngx_thread_value_t __stdcall ngx_cache_loader_thread(void *data); + + +ngx_uint_t ngx_process; +ngx_uint_t ngx_worker; +ngx_pid_t ngx_pid; + +ngx_uint_t ngx_inherited; +ngx_pid_t ngx_new_binary; + +sig_atomic_t ngx_terminate; +sig_atomic_t ngx_quit; +sig_atomic_t ngx_reopen; +sig_atomic_t ngx_reconfigure; +ngx_uint_t ngx_exiting; + + +HANDLE ngx_master_process_event; +char ngx_master_process_event_name[NGX_PROCESS_SYNC_NAME]; + +static HANDLE ngx_stop_event; +static char ngx_stop_event_name[NGX_PROCESS_SYNC_NAME]; +static HANDLE ngx_quit_event; +static char ngx_quit_event_name[NGX_PROCESS_SYNC_NAME]; +static HANDLE ngx_reopen_event; +static char ngx_reopen_event_name[NGX_PROCESS_SYNC_NAME]; +static HANDLE ngx_reload_event; +static char ngx_reload_event_name[NGX_PROCESS_SYNC_NAME]; + +HANDLE ngx_cache_manager_mutex; +char ngx_cache_manager_mutex_name[NGX_PROCESS_SYNC_NAME]; +HANDLE ngx_cache_manager_event; + + +void +ngx_master_process_cycle(ngx_cycle_t *cycle) +{ + u_long nev, ev, timeout; + ngx_err_t err; + ngx_int_t n; + ngx_msec_t timer; + ngx_uint_t live; + HANDLE events[MAXIMUM_WAIT_OBJECTS]; + + ngx_sprintf((u_char *) ngx_master_process_event_name, + "ngx_master_%s%Z", ngx_unique); + + if (ngx_process == NGX_PROCESS_WORKER) { + ngx_worker_process_cycle(cycle, ngx_master_process_event_name); + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "master started"); + + ngx_console_init(cycle); + + SetEnvironmentVariable("ngx_unique", ngx_unique); + + ngx_master_process_event = CreateEvent(NULL, 1, 0, + ngx_master_process_event_name); + if (ngx_master_process_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"%s\") failed", + ngx_master_process_event_name); + exit(2); + } + + if (ngx_create_signal_events(cycle) != NGX_OK) { + exit(2); + } + + ngx_sprintf((u_char *) ngx_cache_manager_mutex_name, + "ngx_cache_manager_mutex_%s%Z", ngx_unique); + + ngx_cache_manager_mutex = CreateMutex(NULL, 0, + ngx_cache_manager_mutex_name); + if (ngx_cache_manager_mutex == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateMutex(\"%s\") failed", ngx_cache_manager_mutex_name); + exit(2); + } + + + events[0] = ngx_stop_event; + events[1] = ngx_quit_event; + events[2] = ngx_reopen_event; + events[3] = ngx_reload_event; + + ngx_close_listening_sockets(cycle); + + if (ngx_start_worker_processes(cycle, NGX_PROCESS_RESPAWN) == 0) { + exit(2); + } + + timer = 0; + timeout = INFINITE; + + for ( ;; ) { + + nev = 4; + for (n = 0; n < ngx_last_process; n++) { + if (ngx_processes[n].handle) { + events[nev++] = ngx_processes[n].handle; + } + } + + if (timer) { + timeout = timer > ngx_current_msec ? timer - ngx_current_msec : 0; + } + + ev = WaitForMultipleObjects(nev, events, 0, timeout); + + err = ngx_errno; + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "master WaitForMultipleObjects: %ul", ev); + + if (ev == WAIT_OBJECT_0) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + + if (ResetEvent(ngx_stop_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "ResetEvent(\"%s\") failed", ngx_stop_event_name); + } + + if (timer == 0) { + timer = ngx_current_msec + 5000; + } + + ngx_terminate = 1; + ngx_quit_worker_processes(cycle, 0); + + continue; + } + + if (ev == WAIT_OBJECT_0 + 1) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "shutting down"); + + if (ResetEvent(ngx_quit_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "ResetEvent(\"%s\") failed", ngx_quit_event_name); + } + + ngx_quit = 1; + ngx_quit_worker_processes(cycle, 0); + + continue; + } + + if (ev == WAIT_OBJECT_0 + 2) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); + + if (ResetEvent(ngx_reopen_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "ResetEvent(\"%s\") failed", + ngx_reopen_event_name); + } + + ngx_reopen_files(cycle, -1); + ngx_reopen_worker_processes(cycle); + + continue; + } + + if (ev == WAIT_OBJECT_0 + 3) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); + + if (ResetEvent(ngx_reload_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "ResetEvent(\"%s\") failed", + ngx_reload_event_name); + } + + cycle = ngx_init_cycle(cycle); + if (cycle == NULL) { + cycle = (ngx_cycle_t *) ngx_cycle; + continue; + } + + ngx_cycle = cycle; + + ngx_close_listening_sockets(cycle); + + if (ngx_start_worker_processes(cycle, NGX_PROCESS_JUST_RESPAWN)) { + ngx_quit_worker_processes(cycle, 1); + } + + continue; + } + + if (ev > WAIT_OBJECT_0 + 3 && ev < WAIT_OBJECT_0 + nev) { + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "reap worker"); + + live = ngx_reap_worker(cycle, events[ev]); + + if (!live && (ngx_terminate || ngx_quit)) { + ngx_master_process_exit(cycle); + } + + continue; + } + + if (ev == WAIT_TIMEOUT) { + ngx_terminate_worker_processes(cycle); + + ngx_master_process_exit(cycle); + } + + if (ev == WAIT_FAILED) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "WaitForMultipleObjects() failed"); + + continue; + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "WaitForMultipleObjects() returned unexpected value %ul", ev); + } +} + + +static void +ngx_console_init(ngx_cycle_t *cycle) +{ + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + if (ccf->daemon) { + if (FreeConsole() == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "FreeConsole() failed"); + } + + return; + } + + if (SetConsoleCtrlHandler(ngx_console_handler, 1) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "SetConsoleCtrlHandler() failed"); + } +} + + +static int __stdcall +ngx_console_handler(u_long type) +{ + char *msg; + + switch (type) { + + case CTRL_C_EVENT: + msg = "Ctrl-C pressed, exiting"; + break; + + case CTRL_BREAK_EVENT: + msg = "Ctrl-Break pressed, exiting"; + break; + + case CTRL_CLOSE_EVENT: + msg = "console closing, exiting"; + break; + + case CTRL_LOGOFF_EVENT: + msg = "user logs off, exiting"; + break; + + default: + return 0; + } + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, msg); + + if (ngx_stop_event == NULL) { + return 1; + } + + if (SetEvent(ngx_stop_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "SetEvent(\"%s\") failed", ngx_stop_event_name); + } + + return 1; +} + + +static ngx_int_t +ngx_create_signal_events(ngx_cycle_t *cycle) +{ + ngx_sprintf((u_char *) ngx_stop_event_name, + "Global\\ngx_stop_%s%Z", ngx_unique); + + ngx_stop_event = CreateEvent(NULL, 1, 0, ngx_stop_event_name); + if (ngx_stop_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"%s\") failed", ngx_stop_event_name); + return NGX_ERROR; + } + + + ngx_sprintf((u_char *) ngx_quit_event_name, + "Global\\ngx_quit_%s%Z", ngx_unique); + + ngx_quit_event = CreateEvent(NULL, 1, 0, ngx_quit_event_name); + if (ngx_quit_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"%s\") failed", ngx_quit_event_name); + return NGX_ERROR; + } + + + ngx_sprintf((u_char *) ngx_reopen_event_name, + "Global\\ngx_reopen_%s%Z", ngx_unique); + + ngx_reopen_event = CreateEvent(NULL, 1, 0, ngx_reopen_event_name); + if (ngx_reopen_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"%s\") failed", ngx_reopen_event_name); + return NGX_ERROR; + } + + + ngx_sprintf((u_char *) ngx_reload_event_name, + "Global\\ngx_reload_%s%Z", ngx_unique); + + ngx_reload_event = CreateEvent(NULL, 1, 0, ngx_reload_event_name); + if (ngx_reload_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"%s\") failed", ngx_reload_event_name); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t type) +{ + ngx_int_t n; + ngx_core_conf_t *ccf; + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes"); + + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + for (n = 0; n < ccf->worker_processes; n++) { + if (ngx_spawn_process(cycle, "worker", type) == NGX_INVALID_PID) { + break; + } + } + + return n; +} + + +static void +ngx_reopen_worker_processes(ngx_cycle_t *cycle) +{ + ngx_int_t n; + + for (n = 0; n < ngx_last_process; n++) { + + if (ngx_processes[n].handle == NULL) { + continue; + } + + if (SetEvent(ngx_processes[n].reopen) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "SetEvent(\"%s\") failed", + ngx_processes[n].reopen_event); + } + } +} + + +static void +ngx_quit_worker_processes(ngx_cycle_t *cycle, ngx_uint_t old) +{ + ngx_int_t n; + + for (n = 0; n < ngx_last_process; n++) { + + ngx_log_debug5(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "process: %d %P %p e:%d j:%d", + n, + ngx_processes[n].pid, + ngx_processes[n].handle, + ngx_processes[n].exiting, + ngx_processes[n].just_spawn); + + if (old && ngx_processes[n].just_spawn) { + ngx_processes[n].just_spawn = 0; + continue; + } + + if (ngx_processes[n].handle == NULL) { + continue; + } + + if (SetEvent(ngx_processes[n].quit) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "SetEvent(\"%s\") failed", + ngx_processes[n].quit_event); + } + + ngx_processes[n].exiting = 1; + } +} + + +static void +ngx_terminate_worker_processes(ngx_cycle_t *cycle) +{ + ngx_int_t n; + + for (n = 0; n < ngx_last_process; n++) { + + if (ngx_processes[n].handle == NULL) { + continue; + } + + if (TerminateProcess(ngx_processes[n].handle, 0) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "TerminateProcess(\"%p\") failed", + ngx_processes[n].handle); + } + + ngx_processes[n].exiting = 1; + + ngx_close_handle(ngx_processes[n].reopen); + ngx_close_handle(ngx_processes[n].quit); + ngx_close_handle(ngx_processes[n].term); + ngx_close_handle(ngx_processes[n].handle); + } +} + + +static ngx_uint_t +ngx_reap_worker(ngx_cycle_t *cycle, HANDLE h) +{ + u_long code; + ngx_int_t n; + + for (n = 0; n < ngx_last_process; n++) { + + if (ngx_processes[n].handle != h) { + continue; + } + + if (GetExitCodeProcess(h, &code) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "GetExitCodeProcess(%P) failed", + ngx_processes[n].pid); + } + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, + "%s process %P exited with code %Xl", + ngx_processes[n].name, ngx_processes[n].pid, code); + + ngx_close_handle(ngx_processes[n].reopen); + ngx_close_handle(ngx_processes[n].quit); + ngx_close_handle(ngx_processes[n].term); + ngx_close_handle(h); + + ngx_processes[n].handle = NULL; + ngx_processes[n].term = NULL; + ngx_processes[n].quit = NULL; + ngx_processes[n].reopen = NULL; + + if (!ngx_processes[n].exiting && !ngx_terminate && !ngx_quit) { + + if (ngx_spawn_process(cycle, ngx_processes[n].name, n) + == NGX_INVALID_PID) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "could not respawn %s", ngx_processes[n].name); + + if (n == ngx_last_process - 1) { + ngx_last_process--; + } + } + } + + goto found; + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unknown process handle %p", h); + +found: + + for (n = 0; n < ngx_last_process; n++) { + + ngx_log_debug5(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "process: %d %P %p e:%d j:%d", + n, + ngx_processes[n].pid, + ngx_processes[n].handle, + ngx_processes[n].exiting, + ngx_processes[n].just_spawn); + + if (ngx_processes[n].handle) { + return 1; + } + } + + return 0; +} + + +static void +ngx_master_process_exit(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + + ngx_delete_pidfile(cycle); + + ngx_close_handle(ngx_cache_manager_mutex); + ngx_close_handle(ngx_stop_event); + ngx_close_handle(ngx_quit_event); + ngx_close_handle(ngx_reopen_event); + ngx_close_handle(ngx_reload_event); + ngx_close_handle(ngx_master_process_event); + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit"); + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->exit_master) { + cycle->modules[i]->exit_master(cycle); + } + } + + ngx_destroy_pool(cycle->pool); + + exit(0); +} + + +static void +ngx_worker_process_cycle(ngx_cycle_t *cycle, char *mevn) +{ + char wtevn[NGX_PROCESS_SYNC_NAME]; + char wqevn[NGX_PROCESS_SYNC_NAME]; + char wroevn[NGX_PROCESS_SYNC_NAME]; + HANDLE mev, events[3]; + u_long nev, ev; + ngx_err_t err; + ngx_tid_t wtid, cmtid, cltid; + ngx_log_t *log; + + log = cycle->log; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "worker started"); + + ngx_sprintf((u_char *) wtevn, "ngx_worker_term_%P%Z", ngx_pid); + events[0] = CreateEvent(NULL, 1, 0, wtevn); + if (events[0] == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "CreateEvent(\"%s\") failed", wtevn); + goto failed; + } + + ngx_sprintf((u_char *) wqevn, "ngx_worker_quit_%P%Z", ngx_pid); + events[1] = CreateEvent(NULL, 1, 0, wqevn); + if (events[1] == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "CreateEvent(\"%s\") failed", wqevn); + goto failed; + } + + ngx_sprintf((u_char *) wroevn, "ngx_worker_reopen_%P%Z", ngx_pid); + events[2] = CreateEvent(NULL, 1, 0, wroevn); + if (events[2] == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "CreateEvent(\"%s\") failed", wroevn); + goto failed; + } + + mev = OpenEvent(EVENT_MODIFY_STATE, 0, mevn); + if (mev == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "OpenEvent(\"%s\") failed", mevn); + goto failed; + } + + if (SetEvent(mev) == 0) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "SetEvent(\"%s\") failed", mevn); + goto failed; + } + + + ngx_sprintf((u_char *) ngx_cache_manager_mutex_name, + "ngx_cache_manager_mutex_%s%Z", ngx_unique); + + ngx_cache_manager_mutex = OpenMutex(SYNCHRONIZE, 0, + ngx_cache_manager_mutex_name); + if (ngx_cache_manager_mutex == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "OpenMutex(\"%s\") failed", ngx_cache_manager_mutex_name); + goto failed; + } + + ngx_cache_manager_event = CreateEvent(NULL, 1, 0, NULL); + if (ngx_cache_manager_event == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "CreateEvent(\"ngx_cache_manager_event\") failed"); + goto failed; + } + + + if (ngx_create_thread(&wtid, ngx_worker_thread, NULL, log) != 0) { + goto failed; + } + + if (ngx_create_thread(&cmtid, ngx_cache_manager_thread, NULL, log) != 0) { + goto failed; + } + + if (ngx_create_thread(&cltid, ngx_cache_loader_thread, NULL, log) != 0) { + goto failed; + } + + for ( ;; ) { + ev = WaitForMultipleObjects(3, events, 0, INFINITE); + + err = ngx_errno; + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "worker WaitForMultipleObjects: %ul", ev); + + if (ev == WAIT_OBJECT_0) { + ngx_terminate = 1; + ngx_log_error(NGX_LOG_NOTICE, log, 0, "exiting"); + + if (ResetEvent(events[0]) == 0) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "ResetEvent(\"%s\") failed", wtevn); + } + + break; + } + + if (ev == WAIT_OBJECT_0 + 1) { + ngx_quit = 1; + ngx_log_error(NGX_LOG_NOTICE, log, 0, "gracefully shutting down"); + break; + } + + if (ev == WAIT_OBJECT_0 + 2) { + ngx_reopen = 1; + ngx_log_error(NGX_LOG_NOTICE, log, 0, "reopening logs"); + + if (ResetEvent(events[2]) == 0) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "ResetEvent(\"%s\") failed", wroevn); + } + + continue; + } + + if (ev == WAIT_FAILED) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "WaitForMultipleObjects() failed"); + + goto failed; + } + } + + /* wait threads */ + + if (SetEvent(ngx_cache_manager_event) == 0) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "SetEvent(\"ngx_cache_manager_event\") failed"); + } + + events[1] = wtid; + events[2] = cmtid; + + nev = 3; + + for ( ;; ) { + ev = WaitForMultipleObjects(nev, events, 0, INFINITE); + + err = ngx_errno; + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, + "worker exit WaitForMultipleObjects: %ul", ev); + + if (ev == WAIT_OBJECT_0) { + break; + } + + if (ev == WAIT_OBJECT_0 + 1) { + if (nev == 2) { + break; + } + + events[1] = events[2]; + nev = 2; + continue; + } + + if (ev == WAIT_OBJECT_0 + 2) { + nev = 2; + continue; + } + + if (ev == WAIT_FAILED) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "WaitForMultipleObjects() failed"); + break; + } + } + + ngx_close_handle(ngx_cache_manager_event); + ngx_close_handle(events[0]); + ngx_close_handle(events[1]); + ngx_close_handle(events[2]); + ngx_close_handle(mev); + + ngx_worker_process_exit(cycle); + +failed: + + exit(2); +} + + +static ngx_thread_value_t __stdcall +ngx_worker_thread(void *data) +{ + ngx_int_t n; + ngx_time_t *tp; + ngx_cycle_t *cycle; + + tp = ngx_timeofday(); + srand((ngx_pid << 16) ^ (unsigned) tp->sec ^ tp->msec); + + cycle = (ngx_cycle_t *) ngx_cycle; + + for (n = 0; cycle->modules[n]; n++) { + if (cycle->modules[n]->init_process) { + if (cycle->modules[n]->init_process(cycle) == NGX_ERROR) { + /* fatal */ + exit(2); + } + } + } + + while (!ngx_quit) { + + if (ngx_exiting) { + if (ngx_event_no_timers_left() == NGX_OK) { + break; + } + } + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "worker cycle"); + + ngx_process_events_and_timers(cycle); + + if (ngx_terminate) { + return 0; + } + + if (ngx_quit) { + ngx_quit = 0; + + if (!ngx_exiting) { + ngx_exiting = 1; + ngx_set_shutdown_timer(cycle); + ngx_close_listening_sockets(cycle); + ngx_close_idle_connections(cycle); + } + } + + if (ngx_reopen) { + ngx_reopen = 0; + ngx_reopen_files(cycle, -1); + } + } + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + + return 0; +} + + +static void +ngx_worker_process_exit(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + ngx_connection_t *c; + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit"); + + for (i = 0; cycle->modules[i]; i++) { + if (cycle->modules[i]->exit_process) { + cycle->modules[i]->exit_process(cycle); + } + } + + if (ngx_exiting) { + c = cycle->connections; + for (i = 0; i < cycle->connection_n; i++) { + if (c[i].fd != (ngx_socket_t) -1 + && c[i].read + && !c[i].read->accept + && !c[i].read->channel + && !c[i].read->resolver) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "*%uA open socket #%d left in connection %ui", + c[i].number, c[i].fd, i); + } + } + } + + ngx_destroy_pool(cycle->pool); + + exit(0); +} + + +static ngx_thread_value_t __stdcall +ngx_cache_manager_thread(void *data) +{ + u_long ev; + HANDLE events[2]; + ngx_err_t err; + ngx_cycle_t *cycle; + + cycle = (ngx_cycle_t *) ngx_cycle; + + events[0] = ngx_cache_manager_event; + events[1] = ngx_cache_manager_mutex; + + for ( ;; ) { + ev = WaitForMultipleObjects(2, events, 0, INFINITE); + + err = ngx_errno; + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "cache manager WaitForMultipleObjects: %ul", ev); + + if (ev == WAIT_FAILED) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "WaitForMultipleObjects() failed"); + } + + /* + * ev == WAIT_OBJECT_0 + * ev == WAIT_OBJECT_0 + 1 + * ev == WAIT_ABANDONED_0 + 1 + */ + + if (ngx_terminate || ngx_quit || ngx_exiting) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + return 0; + } + + break; + } + + for ( ;; ) { + + if (ngx_terminate || ngx_quit || ngx_exiting) { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); + break; + } + + ngx_cache_manager_process_handler(); + } + + if (ReleaseMutex(ngx_cache_manager_mutex) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "ReleaseMutex() failed"); + } + + return 0; +} + + +static void +ngx_cache_manager_process_handler(void) +{ + u_long ev; + ngx_uint_t i; + ngx_msec_t next, n; + ngx_path_t **path; + + next = 60 * 60 * 1000; + + path = ngx_cycle->paths.elts; + for (i = 0; i < ngx_cycle->paths.nelts; i++) { + + if (path[i]->manager) { + n = path[i]->manager(path[i]->data); + + next = (n <= next) ? n : next; + + ngx_time_update(); + } + } + + if (next == 0) { + next = 1; + } + + ev = WaitForSingleObject(ngx_cache_manager_event, (u_long) next); + + if (ev != WAIT_TIMEOUT) { + + ngx_time_update(); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, + "cache manager WaitForSingleObject: %ul", ev); + } +} + + +static ngx_thread_value_t __stdcall +ngx_cache_loader_thread(void *data) +{ + ngx_uint_t i; + ngx_path_t **path; + ngx_cycle_t *cycle; + + ngx_msleep(60000); + + cycle = (ngx_cycle_t *) ngx_cycle; + + path = cycle->paths.elts; + for (i = 0; i < cycle->paths.nelts; i++) { + + if (ngx_terminate || ngx_quit || ngx_exiting) { + break; + } + + if (path[i]->loader) { + path[i]->loader(path[i]->data); + ngx_time_update(); + } + } + + return 0; +} + + +void +ngx_single_process_cycle(ngx_cycle_t *cycle) +{ + ngx_tid_t tid; + + ngx_console_init(cycle); + + if (ngx_create_signal_events(cycle) != NGX_OK) { + exit(2); + } + + if (ngx_create_thread(&tid, ngx_worker_thread, NULL, cycle->log) != 0) { + /* fatal */ + exit(2); + } + + /* STUB */ + WaitForSingleObject(ngx_stop_event, INFINITE); +} + + +ngx_int_t +ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_pid_t pid) +{ + HANDLE ev; + ngx_int_t rc; + char evn[NGX_PROCESS_SYNC_NAME]; + + ngx_sprintf((u_char *) evn, "Global\\ngx_%s_%P%Z", sig, pid); + + ev = OpenEvent(EVENT_MODIFY_STATE, 0, evn); + if (ev == NULL) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + "OpenEvent(\"%s\") failed", evn); + return 1; + } + + if (SetEvent(ev) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "SetEvent(\"%s\") failed", evn); + rc = 1; + + } else { + rc = 0; + } + + ngx_close_handle(ev); + + return rc; +} + + +void +ngx_close_handle(HANDLE h) +{ + if (CloseHandle(h) == 0) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, + "CloseHandle(%p) failed", h); + } +} diff --git a/app/nginx/src/os/win32/ngx_process_cycle.h b/app/nginx/src/os/win32/ngx_process_cycle.h new file mode 100644 index 0000000..95d2743 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_process_cycle.h @@ -0,0 +1,44 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_PROCESS_CYCLE_H_INCLUDED_ +#define _NGX_PROCESS_CYCLE_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define NGX_PROCESS_SINGLE 0 +#define NGX_PROCESS_MASTER 1 +#define NGX_PROCESS_SIGNALLER 2 +#define NGX_PROCESS_WORKER 3 + + +void ngx_master_process_cycle(ngx_cycle_t *cycle); +void ngx_single_process_cycle(ngx_cycle_t *cycle); +void ngx_close_handle(HANDLE h); + + +extern ngx_uint_t ngx_process; +extern ngx_uint_t ngx_worker; +extern ngx_pid_t ngx_pid; +extern ngx_uint_t ngx_exiting; + +extern sig_atomic_t ngx_quit; +extern sig_atomic_t ngx_terminate; +extern sig_atomic_t ngx_reopen; + +extern ngx_uint_t ngx_inherited; +extern ngx_pid_t ngx_new_binary; + + +extern HANDLE ngx_master_process_event; +extern char ngx_master_process_event_name[]; + + +#endif /* _NGX_PROCESS_CYCLE_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_service.c b/app/nginx/src/os/win32/ngx_service.c new file mode 100644 index 0000000..835d9cf --- /dev/null +++ b/app/nginx/src/os/win32/ngx_service.c @@ -0,0 +1,134 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + + +#define NGX_SERVICE_CONTROL_SHUTDOWN 128 +#define NGX_SERVICE_CONTROL_REOPEN 129 + + +SERVICE_TABLE_ENTRY st[] = { + { "nginx", service_main }, + { NULL, NULL } +}; + + +ngx_int_t +ngx_service(ngx_log_t *log) +{ + /* primary thread */ + + /* StartServiceCtrlDispatcher() should be called within 30 seconds */ + + if (StartServiceCtrlDispatcher(st) == 0) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "StartServiceCtrlDispatcher() failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +void +service_main(u_int argc, char **argv) +{ + SERVICE_STATUS status; + SERVICE_STATUS_HANDLE service; + + /* thread spawned by SCM */ + + service = RegisterServiceCtrlHandlerEx("nginx", service_handler, ctx); + if (service == INVALID_HANDLE_VALUE) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "RegisterServiceCtrlHandlerEx() failed"); + return; + } + + status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + status.dwCurrentState = SERVICE_START_PENDING; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP + |SERVICE_ACCEPT_PARAMCHANGE; + status.dwWin32ExitCode = NO_ERROR; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 1; + status.dwWaitHint = 2000; + + /* SetServiceStatus() should be called within 80 seconds */ + + if (SetServiceStatus(service, &status) == 0) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "SetServiceStatus() failed"); + return; + } + + /* init */ + + status.dwCurrentState = SERVICE_RUNNING; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; + + if (SetServiceStatus(service, &status) == 0) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "SetServiceStatus() failed"); + return; + } + + /* call master or worker loop */ + + /* + * master should use event notification and look status + * single should use iocp to get notifications from service handler + */ + +} + + +u_int +service_handler(u_int control, u_int type, void *data, void *ctx) +{ + /* primary thread */ + + switch (control) { + + case SERVICE_CONTROL_INTERROGATE: + status = NGX_IOCP_INTERROGATE; + break; + + case SERVICE_CONTROL_STOP: + status = NGX_IOCP_STOP; + break; + + case SERVICE_CONTROL_PARAMCHANGE: + status = NGX_IOCP_RECONFIGURE; + break; + + case NGX_SERVICE_CONTROL_SHUTDOWN: + status = NGX_IOCP_REOPEN; + break; + + case NGX_SERVICE_CONTROL_REOPEN: + status = NGX_IOCP_REOPEN; + break; + + default: + return ERROR_CALL_NOT_IMPLEMENTED; + } + + if (ngx_single) { + if (PostQueuedCompletionStatus(iocp, ... status, ...) == 0) { + err = ngx_errno; + ngx_log_error(NGX_LOG_ALERT, log, err, + "PostQueuedCompletionStatus() failed"); + return err; + } + + } else { + Event + } + + return NO_ERROR; +} diff --git a/app/nginx/src/os/win32/ngx_shmem.c b/app/nginx/src/os/win32/ngx_shmem.c new file mode 100644 index 0000000..c3ed699 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_shmem.c @@ -0,0 +1,161 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +/* + * Base addresses selected by system for shared memory mappings are likely + * to be different on Windows Vista and later versions due to address space + * layout randomization. This is however incompatible with storing absolute + * addresses within the shared memory. + * + * To make it possible to store absolute addresses we create mappings + * at the same address in all processes by starting mappings at predefined + * addresses. The addresses were selected somewhat randomly in order to + * minimize the probability that some other library doing something similar + * conflicts with us. The addresses are from the following typically free + * blocks: + * + * - 0x10000000 .. 0x70000000 (about 1.5 GB in total) on 32-bit platforms + * - 0x000000007fff0000 .. 0x000007f68e8b0000 (about 8 TB) on 64-bit platforms + * + * Additionally, we allow to change the mapping address once it was detected + * to be different from one originally used. This is needed to support + * reconfiguration. + */ + + +#ifdef _WIN64 +#define NGX_SHMEM_BASE 0x0000047047e00000 +#else +#define NGX_SHMEM_BASE 0x2efe0000 +#endif + + +ngx_uint_t ngx_allocation_granularity; + + +ngx_int_t +ngx_shm_alloc(ngx_shm_t *shm) +{ + u_char *name; + uint64_t size; + static u_char *base = (u_char *) NGX_SHMEM_BASE; + + name = ngx_alloc(shm->name.len + 2 + NGX_INT32_LEN, shm->log); + if (name == NULL) { + return NGX_ERROR; + } + + (void) ngx_sprintf(name, "%V_%s%Z", &shm->name, ngx_unique); + + ngx_set_errno(0); + + size = shm->size; + + shm->handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + (u_long) (size >> 32), + (u_long) (size & 0xffffffff), + (char *) name); + + if (shm->handle == NULL) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "CreateFileMapping(%uz, %s) failed", + shm->size, name); + ngx_free(name); + + return NGX_ERROR; + } + + ngx_free(name); + + if (ngx_errno == ERROR_ALREADY_EXISTS) { + shm->exists = 1; + } + + shm->addr = MapViewOfFileEx(shm->handle, FILE_MAP_WRITE, 0, 0, 0, base); + + if (shm->addr != NULL) { + base += ngx_align(size, ngx_allocation_granularity); + return NGX_OK; + } + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, shm->log, ngx_errno, + "MapViewOfFileEx(%uz, %p) of file mapping \"%V\" failed, " + "retry without a base address", + shm->size, base, &shm->name); + + /* + * Order of shared memory zones may be different in the master process + * and worker processes after reconfiguration. As a result, the above + * may fail due to a conflict with a previously created mapping remapped + * to a different address. Additionally, there may be a conflict with + * some other uses of the memory. In this case we retry without a base + * address to let the system assign the address itself. + */ + + shm->addr = MapViewOfFile(shm->handle, FILE_MAP_WRITE, 0, 0, 0); + + if (shm->addr != NULL) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "MapViewOfFile(%uz) of file mapping \"%V\" failed", + shm->size, &shm->name); + + if (CloseHandle(shm->handle) == 0) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "CloseHandle() of file mapping \"%V\" failed", + &shm->name); + } + + return NGX_ERROR; +} + + +ngx_int_t +ngx_shm_remap(ngx_shm_t *shm, u_char *addr) +{ + if (UnmapViewOfFile(shm->addr) == 0) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "UnmapViewOfFile(%p) of file mapping \"%V\" failed", + shm->addr, &shm->name); + return NGX_ERROR; + } + + shm->addr = MapViewOfFileEx(shm->handle, FILE_MAP_WRITE, 0, 0, 0, addr); + + if (shm->addr != NULL) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "MapViewOfFileEx(%uz, %p) of file mapping \"%V\" failed", + shm->size, addr, &shm->name); + + return NGX_ERROR; +} + + +void +ngx_shm_free(ngx_shm_t *shm) +{ + if (UnmapViewOfFile(shm->addr) == 0) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "UnmapViewOfFile(%p) of file mapping \"%V\" failed", + shm->addr, &shm->name); + } + + if (CloseHandle(shm->handle) == 0) { + ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, + "CloseHandle() of file mapping \"%V\" failed", + &shm->name); + } +} diff --git a/app/nginx/src/os/win32/ngx_shmem.h b/app/nginx/src/os/win32/ngx_shmem.h new file mode 100644 index 0000000..ee47429 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_shmem.h @@ -0,0 +1,33 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SHMEM_H_INCLUDED_ +#define _NGX_SHMEM_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +typedef struct { + u_char *addr; + size_t size; + ngx_str_t name; + HANDLE handle; + ngx_log_t *log; + ngx_uint_t exists; /* unsigned exists:1; */ +} ngx_shm_t; + + +ngx_int_t ngx_shm_alloc(ngx_shm_t *shm); +ngx_int_t ngx_shm_remap(ngx_shm_t *shm, u_char *addr); +void ngx_shm_free(ngx_shm_t *shm); + +extern ngx_uint_t ngx_allocation_granularity; + + +#endif /* _NGX_SHMEM_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_socket.c b/app/nginx/src/os/win32/ngx_socket.c new file mode 100644 index 0000000..05a39f4 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_socket.c @@ -0,0 +1,34 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +int +ngx_nonblocking(ngx_socket_t s) +{ + unsigned long nb = 1; + + return ioctlsocket(s, FIONBIO, &nb); +} + + +int +ngx_blocking(ngx_socket_t s) +{ + unsigned long nb = 0; + + return ioctlsocket(s, FIONBIO, &nb); +} + + +int +ngx_tcp_push(ngx_socket_t s) +{ + return 0; +} diff --git a/app/nginx/src/os/win32/ngx_socket.h b/app/nginx/src/os/win32/ngx_socket.h new file mode 100644 index 0000000..a9e26c2 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_socket.h @@ -0,0 +1,207 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_SOCKET_H_INCLUDED_ +#define _NGX_SOCKET_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#define NGX_WRITE_SHUTDOWN SD_SEND + + +typedef SOCKET ngx_socket_t; +typedef int socklen_t; + + +#define ngx_socket(af, type, proto) \ + WSASocketW(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED) + +#define ngx_socket_n "WSASocketW()" + +int ngx_nonblocking(ngx_socket_t s); +int ngx_blocking(ngx_socket_t s); + +#define ngx_nonblocking_n "ioctlsocket(FIONBIO)" +#define ngx_blocking_n "ioctlsocket(!FIONBIO)" + +#define ngx_shutdown_socket shutdown +#define ngx_shutdown_socket_n "shutdown()" + +#define ngx_close_socket closesocket +#define ngx_close_socket_n "closesocket()" + + +#ifndef WSAID_ACCEPTEX + +typedef BOOL (PASCAL FAR * LPFN_ACCEPTEX)( + IN SOCKET sListenSocket, + IN SOCKET sAcceptSocket, + IN PVOID lpOutputBuffer, + IN DWORD dwReceiveDataLength, + IN DWORD dwLocalAddressLength, + IN DWORD dwRemoteAddressLength, + OUT LPDWORD lpdwBytesReceived, + IN LPOVERLAPPED lpOverlapped + ); + +#define WSAID_ACCEPTEX \ + {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} + +#endif + + +#ifndef WSAID_GETACCEPTEXSOCKADDRS + +typedef VOID (PASCAL FAR * LPFN_GETACCEPTEXSOCKADDRS)( + IN PVOID lpOutputBuffer, + IN DWORD dwReceiveDataLength, + IN DWORD dwLocalAddressLength, + IN DWORD dwRemoteAddressLength, + OUT struct sockaddr **LocalSockaddr, + OUT LPINT LocalSockaddrLength, + OUT struct sockaddr **RemoteSockaddr, + OUT LPINT RemoteSockaddrLength + ); + +#define WSAID_GETACCEPTEXSOCKADDRS \ + {0xb5367df2,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} + +#endif + + +#ifndef WSAID_TRANSMITFILE + +#ifndef TF_DISCONNECT + +#define TF_DISCONNECT 1 +#define TF_REUSE_SOCKET 2 +#define TF_WRITE_BEHIND 4 +#define TF_USE_DEFAULT_WORKER 0 +#define TF_USE_SYSTEM_THREAD 16 +#define TF_USE_KERNEL_APC 32 + +typedef struct _TRANSMIT_FILE_BUFFERS { + LPVOID Head; + DWORD HeadLength; + LPVOID Tail; + DWORD TailLength; +} TRANSMIT_FILE_BUFFERS, *PTRANSMIT_FILE_BUFFERS, FAR *LPTRANSMIT_FILE_BUFFERS; + +#endif + +typedef BOOL (PASCAL FAR * LPFN_TRANSMITFILE)( + IN SOCKET hSocket, + IN HANDLE hFile, + IN DWORD nNumberOfBytesToWrite, + IN DWORD nNumberOfBytesPerSend, + IN LPOVERLAPPED lpOverlapped, + IN LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, + IN DWORD dwReserved + ); + +#define WSAID_TRANSMITFILE \ + {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} + +#endif + + +#ifndef WSAID_TRANSMITPACKETS + +/* OpenWatcom has a swapped TP_ELEMENT_FILE and TP_ELEMENT_MEMORY definition */ + +#ifndef TP_ELEMENT_FILE + +#ifdef _MSC_VER +#pragma warning(disable:4201) /* Nonstandard extension, nameless struct/union */ +#endif + +typedef struct _TRANSMIT_PACKETS_ELEMENT { + ULONG dwElFlags; +#define TP_ELEMENT_MEMORY 1 +#define TP_ELEMENT_FILE 2 +#define TP_ELEMENT_EOP 4 + ULONG cLength; + union { + struct { + LARGE_INTEGER nFileOffset; + HANDLE hFile; + }; + PVOID pBuffer; + }; +} TRANSMIT_PACKETS_ELEMENT, *PTRANSMIT_PACKETS_ELEMENT, + FAR *LPTRANSMIT_PACKETS_ELEMENT; + +#ifdef _MSC_VER +#pragma warning(default:4201) +#endif + +#endif + +typedef BOOL (PASCAL FAR * LPFN_TRANSMITPACKETS) ( + SOCKET hSocket, + TRANSMIT_PACKETS_ELEMENT *lpPacketArray, + DWORD nElementCount, + DWORD nSendSize, + LPOVERLAPPED lpOverlapped, + DWORD dwFlags + ); + +#define WSAID_TRANSMITPACKETS \ + {0xd9689da0,0x1f90,0x11d3,{0x99,0x71,0x00,0xc0,0x4f,0x68,0xc8,0x76}} + +#endif + + +#ifndef WSAID_CONNECTEX + +typedef BOOL (PASCAL FAR * LPFN_CONNECTEX) ( + IN SOCKET s, + IN const struct sockaddr FAR *name, + IN int namelen, + IN PVOID lpSendBuffer OPTIONAL, + IN DWORD dwSendDataLength, + OUT LPDWORD lpdwBytesSent, + IN LPOVERLAPPED lpOverlapped + ); + +#define WSAID_CONNECTEX \ + {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}} + +#endif + + +#ifndef WSAID_DISCONNECTEX + +typedef BOOL (PASCAL FAR * LPFN_DISCONNECTEX) ( + IN SOCKET s, + IN LPOVERLAPPED lpOverlapped, + IN DWORD dwFlags, + IN DWORD dwReserved + ); + +#define WSAID_DISCONNECTEX \ + {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} + +#endif + + +extern LPFN_ACCEPTEX ngx_acceptex; +extern LPFN_GETACCEPTEXSOCKADDRS ngx_getacceptexsockaddrs; +extern LPFN_TRANSMITFILE ngx_transmitfile; +extern LPFN_TRANSMITPACKETS ngx_transmitpackets; +extern LPFN_CONNECTEX ngx_connectex; +extern LPFN_DISCONNECTEX ngx_disconnectex; + + +int ngx_tcp_push(ngx_socket_t s); +#define ngx_tcp_push_n "tcp_push()" + + +#endif /* _NGX_SOCKET_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_stat.c b/app/nginx/src/os/win32/ngx_stat.c new file mode 100644 index 0000000..51bcd96 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_stat.c @@ -0,0 +1,34 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +int ngx_file_type(char *file, ngx_file_info_t *sb) +{ + sb->dwFileAttributes = GetFileAttributes(file); + + if (sb->dwFileAttributes == INVALID_FILE_ATTRIBUTES) { + return -1; + } + + return 0; +} + +/* +int ngx_stat(char *file, ngx_stat_t *sb) +{ + *sb = GetFileAttributes(file); + + if (*sb == INVALID_FILE_ATTRIBUTES) { + return -1; + } + + return 0; +} +*/ diff --git a/app/nginx/src/os/win32/ngx_thread.c b/app/nginx/src/os/win32/ngx_thread.c new file mode 100644 index 0000000..a13de2d --- /dev/null +++ b/app/nginx/src/os/win32/ngx_thread.c @@ -0,0 +1,30 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +ngx_err_t +ngx_create_thread(ngx_tid_t *tid, + ngx_thread_value_t (__stdcall *func)(void *arg), void *arg, ngx_log_t *log) +{ + u_long id; + ngx_err_t err; + + *tid = CreateThread(NULL, 0, func, arg, 0, &id); + + if (*tid != NULL) { + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "create thread " NGX_TID_T_FMT, id); + return 0; + } + + err = ngx_errno; + ngx_log_error(NGX_LOG_ALERT, log, err, "CreateThread() failed"); + return err; +} diff --git a/app/nginx/src/os/win32/ngx_thread.h b/app/nginx/src/os/win32/ngx_thread.h new file mode 100644 index 0000000..4012276 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_thread.h @@ -0,0 +1,27 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_THREAD_H_INCLUDED_ +#define _NGX_THREAD_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +typedef HANDLE ngx_tid_t; +typedef DWORD ngx_thread_value_t; + + +ngx_err_t ngx_create_thread(ngx_tid_t *tid, + ngx_thread_value_t (__stdcall *func)(void *arg), void *arg, ngx_log_t *log); + +#define ngx_log_tid GetCurrentThreadId() +#define NGX_TID_T_FMT "%ud" + + +#endif /* _NGX_THREAD_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_time.c b/app/nginx/src/os/win32/ngx_time.c new file mode 100644 index 0000000..bd6d287 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_time.c @@ -0,0 +1,83 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +void +ngx_gettimeofday(struct timeval *tp) +{ + uint64_t intervals; + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + + /* + * A file time is a 64-bit value that represents the number + * of 100-nanosecond intervals that have elapsed since + * January 1, 1601 12:00 A.M. UTC. + * + * Between January 1, 1970 (Epoch) and January 1, 1601 there were + * 134744 days, + * 11644473600 seconds or + * 11644473600,000,000,0 100-nanosecond intervals. + * + * See also MSKB Q167296. + */ + + intervals = ((uint64_t) ft.dwHighDateTime << 32) | ft.dwLowDateTime; + intervals -= 116444736000000000; + + tp->tv_sec = (long) (intervals / 10000000); + tp->tv_usec = (long) ((intervals % 10000000) / 10); +} + + +void +ngx_libc_localtime(time_t s, struct tm *tm) +{ + struct tm *t; + + t = localtime(&s); + *tm = *t; +} + + +void +ngx_libc_gmtime(time_t s, struct tm *tm) +{ + struct tm *t; + + t = gmtime(&s); + *tm = *t; +} + + +ngx_int_t +ngx_gettimezone(void) +{ + u_long n; + TIME_ZONE_INFORMATION tz; + + n = GetTimeZoneInformation(&tz); + + switch (n) { + + case TIME_ZONE_ID_UNKNOWN: + return -tz.Bias; + + case TIME_ZONE_ID_STANDARD: + return -(tz.Bias + tz.StandardBias); + + case TIME_ZONE_ID_DAYLIGHT: + return -(tz.Bias + tz.DaylightBias); + + default: /* TIME_ZONE_ID_INVALID */ + return 0; + } +} diff --git a/app/nginx/src/os/win32/ngx_time.h b/app/nginx/src/os/win32/ngx_time.h new file mode 100644 index 0000000..6c2f806 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_time.h @@ -0,0 +1,51 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_TIME_H_INCLUDED_ +#define _NGX_TIME_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +typedef ngx_rbtree_key_t ngx_msec_t; +typedef ngx_rbtree_key_int_t ngx_msec_int_t; + +typedef SYSTEMTIME ngx_tm_t; +typedef FILETIME ngx_mtime_t; + +#define ngx_tm_sec wSecond +#define ngx_tm_min wMinute +#define ngx_tm_hour wHour +#define ngx_tm_mday wDay +#define ngx_tm_mon wMonth +#define ngx_tm_year wYear +#define ngx_tm_wday wDayOfWeek + +#define ngx_tm_sec_t u_short +#define ngx_tm_min_t u_short +#define ngx_tm_hour_t u_short +#define ngx_tm_mday_t u_short +#define ngx_tm_mon_t u_short +#define ngx_tm_year_t u_short +#define ngx_tm_wday_t u_short + + +#define ngx_msleep Sleep + +#define NGX_HAVE_GETTIMEZONE 1 + +#define ngx_timezone_update() + +ngx_int_t ngx_gettimezone(void); +void ngx_libc_localtime(time_t s, struct tm *tm); +void ngx_libc_gmtime(time_t s, struct tm *tm); +void ngx_gettimeofday(struct timeval *tp); + + +#endif /* _NGX_TIME_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_udp_wsarecv.c b/app/nginx/src/os/win32/ngx_udp_wsarecv.c new file mode 100644 index 0000000..5424375 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_udp_wsarecv.c @@ -0,0 +1,149 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +ssize_t +ngx_udp_wsarecv(ngx_connection_t *c, u_char *buf, size_t size) +{ + int rc; + u_long bytes, flags; + WSABUF wsabuf[1]; + ngx_err_t err; + ngx_event_t *rev; + + wsabuf[0].buf = (char *) buf; + wsabuf[0].len = size; + flags = 0; + bytes = 0; + + rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, NULL, NULL); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: fd:%d rc:%d %ul of %z", c->fd, rc, bytes, size); + + rev = c->read; + + if (rc == -1) { + rev->ready = 0; + err = ngx_socket_errno; + + if (err == WSAEWOULDBLOCK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSARecv() not ready"); + return NGX_AGAIN; + } + + rev->error = 1; + ngx_connection_error(c, err, "WSARecv() failed"); + + return NGX_ERROR; + } + + return bytes; +} + + +ssize_t +ngx_udp_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, size_t size) +{ + int rc; + u_long bytes, flags; + WSABUF wsabuf[1]; + ngx_err_t err; + ngx_event_t *rev; + LPWSAOVERLAPPED ovlp; + + rev = c->read; + + if (!rev->ready) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "second wsa post"); + return NGX_AGAIN; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "rev->complete: %d", rev->complete); + + if (rev->complete) { + rev->complete = 0; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + if (rev->ovlp.error) { + ngx_connection_error(c, rev->ovlp.error, "WSARecv() failed"); + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv ovlp: fd:%d %ul of %z", + c->fd, rev->available, size); + + return rev->available; + } + + if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &rev->ovlp, + &bytes, 0, NULL) + == 0) + { + ngx_connection_error(c, ngx_socket_errno, + "WSARecv() or WSAGetOverlappedResult() failed"); + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: fd:%d %ul of %z", c->fd, bytes, size); + + return bytes; + } + + ovlp = (LPWSAOVERLAPPED) &rev->ovlp; + ngx_memzero(ovlp, sizeof(WSAOVERLAPPED)); + wsabuf[0].buf = (char *) buf; + wsabuf[0].len = size; + flags = 0; + bytes = 0; + + rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, ovlp, NULL); + + rev->complete = 0; + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv ovlp: fd:%d rc:%d %ul of %z", + c->fd, rc, bytes, size); + + if (rc == -1) { + err = ngx_socket_errno; + if (err == WSA_IO_PENDING) { + rev->active = 1; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSARecv() posted"); + return NGX_AGAIN; + } + + rev->error = 1; + ngx_connection_error(c, err, "WSARecv() failed"); + return NGX_ERROR; + } + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + /* + * if a socket was bound with I/O completion port + * then GetQueuedCompletionStatus() would anyway return its status + * despite that WSARecv() was already complete + */ + + rev->active = 1; + return NGX_AGAIN; + } + + rev->active = 0; + + return bytes; +} diff --git a/app/nginx/src/os/win32/ngx_user.c b/app/nginx/src/os/win32/ngx_user.c new file mode 100644 index 0000000..ea6da5a --- /dev/null +++ b/app/nginx/src/os/win32/ngx_user.c @@ -0,0 +1,23 @@ +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +#if (NGX_CRYPT) + +ngx_int_t +ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) +{ + /* STUB: a plain text password */ + + *encrypted = key; + + return NGX_OK; +} + +#endif /* NGX_CRYPT */ diff --git a/app/nginx/src/os/win32/ngx_user.h b/app/nginx/src/os/win32/ngx_user.h new file mode 100644 index 0000000..61408e4 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_user.h @@ -0,0 +1,25 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_USER_H_INCLUDED_ +#define _NGX_USER_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +/* STUB */ +#define ngx_uid_t ngx_int_t +#define ngx_gid_t ngx_int_t + + +ngx_int_t ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, + u_char **encrypted); + + +#endif /* _NGX_USER_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_win32_config.h b/app/nginx/src/os/win32/ngx_win32_config.h new file mode 100644 index 0000000..4824d05 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_win32_config.h @@ -0,0 +1,282 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _NGX_WIN32_CONFIG_H_INCLUDED_ +#define _NGX_WIN32_CONFIG_H_INCLUDED_ + + +#undef WIN32 +#define WIN32 0x0400 +#define _WIN32_WINNT 0x0501 + + +#define STRICT +#define WIN32_LEAN_AND_MEAN + +/* enable getenv() and gmtime() in msvc8 */ +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_DEPRECATE + +/* enable gethostbyname() in msvc2015 */ +#if !(NGX_HAVE_INET6) +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#endif + +/* + * we need to include <windows.h> explicitly before <winsock2.h> because + * the warning 4201 is enabled in <windows.h> + */ +#include <windows.h> + +#ifdef _MSC_VER +#pragma warning(disable:4201) +#endif + +#include <winsock2.h> +#include <ws2tcpip.h> /* ipv6 */ +#include <mswsock.h> +#include <shellapi.h> +#include <stddef.h> /* offsetof() */ + +#ifdef __MINGW64_VERSION_MAJOR + +/* GCC MinGW-w64 supports _FILE_OFFSET_BITS */ +#define _FILE_OFFSET_BITS 64 + +#elif defined __GNUC__ + +/* GCC MinGW's stdio.h includes sys/types.h */ +#define _OFF_T_ +#define __have_typedef_off_t + +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#ifdef __GNUC__ +#include <stdint.h> +#endif +#include <ctype.h> +#include <locale.h> + +#ifdef __WATCOMC__ +#define _TIME_T_DEFINED +typedef long time_t; +/* OpenWatcom defines time_t as "unsigned long" */ +#endif + +#include <time.h> /* localtime(), strftime() */ + + +#ifdef _MSC_VER + +/* the end of the precompiled headers */ +#pragma hdrstop + +#pragma warning(default:4201) + +/* disable some "-W4" level warnings */ + +/* 'type cast': from function pointer to data pointer */ +#pragma warning(disable:4054) + +/* 'type cast': from data pointer to function pointer */ +#pragma warning(disable:4055) + +/* 'function' : different 'const' qualifiers */ +#pragma warning(disable:4090) + +/* unreferenced formal parameter */ +#pragma warning(disable:4100) + +/* FD_SET() and FD_CLR(): conditional expression is constant */ +#pragma warning(disable:4127) + +/* conversion from 'type1' to 'type2', possible loss of data */ +#pragma warning(disable:4244) + +/* conversion from 'size_t' to 'type', possible loss of data */ +#pragma warning(disable:4267) + +/* array is too small to include a terminating null character */ +#pragma warning(disable:4295) + +#endif + + +#ifdef __WATCOMC__ + +/* symbol 'ngx_rbtree_min' has been defined, but not referenced */ +#pragma disable_message(202) + +#endif + + +#ifdef __BORLANDC__ + +/* the end of the precompiled headers */ +#pragma hdrstop + +/* functions containing (for|while|some if) are not expanded inline */ +#pragma warn -8027 + +/* unreferenced formal parameter */ +#pragma warn -8057 + +/* suspicious pointer arithmetic */ +#pragma warn -8072 + +#endif + + +#include <ngx_auto_config.h> + + +#define ngx_inline __inline +#define ngx_cdecl __cdecl + + +#ifdef _MSC_VER +typedef unsigned __int32 uint32_t; +typedef __int32 int32_t; +typedef unsigned __int16 uint16_t; +#define ngx_libc_cdecl __cdecl + +#elif defined __BORLANDC__ +typedef unsigned __int32 uint32_t; +typedef __int32 int32_t; +typedef unsigned __int16 uint16_t; +#define ngx_libc_cdecl __cdecl + +#else /* __WATCOMC__ */ +typedef unsigned int uint32_t; +typedef int int32_t; +typedef unsigned short int uint16_t; +#define ngx_libc_cdecl + +#endif + +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +#if __BORLANDC__ +typedef int intptr_t; +typedef u_int uintptr_t; +#endif + + +#ifndef __MINGW64_VERSION_MAJOR + +/* Windows defines off_t as long, which is 32-bit */ +typedef __int64 off_t; +#define _OFF_T_DEFINED + +#endif + + +#ifdef __WATCOMC__ + +/* off_t is redefined by sys/types.h used by zlib.h */ +#define __TYPES_H_INCLUDED +typedef int dev_t; +typedef unsigned int ino_t; + +#elif __BORLANDC__ + +/* off_t is redefined by sys/types.h used by zlib.h */ +#define __TYPES_H + +typedef int dev_t; +typedef unsigned int ino_t; + +#endif + + +#ifndef __GNUC__ +#ifdef _WIN64 +typedef __int64 ssize_t; +#else +typedef int ssize_t; +#endif +#endif + + +typedef uint32_t in_addr_t; +typedef u_short in_port_t; +typedef int sig_atomic_t; + + +#ifdef _WIN64 + +#define NGX_PTR_SIZE 8 +#define NGX_SIZE_T_LEN (sizeof("-9223372036854775808") - 1) +#define NGX_MAX_SIZE_T_VALUE 9223372036854775807 +#define NGX_TIME_T_LEN (sizeof("-9223372036854775808") - 1) +#define NGX_TIME_T_SIZE 8 +#define NGX_MAX_TIME_T_VALUE 9223372036854775807 + +#else + +#define NGX_PTR_SIZE 4 +#define NGX_SIZE_T_LEN (sizeof("-2147483648") - 1) +#define NGX_MAX_SIZE_T_VALUE 2147483647 +#define NGX_TIME_T_LEN (sizeof("-2147483648") - 1) +#define NGX_TIME_T_SIZE 4 +#define NGX_MAX_TIME_T_VALUE 2147483647 + +#endif + + +#define NGX_OFF_T_LEN (sizeof("-9223372036854775807") - 1) +#define NGX_MAX_OFF_T_VALUE 9223372036854775807 +#define NGX_SIG_ATOMIC_T_SIZE 4 + + +#define NGX_HAVE_LITTLE_ENDIAN 1 +#define NGX_HAVE_NONALIGNED 1 + + +#define NGX_WIN_NT 200000 + + +#define NGX_LISTEN_BACKLOG 511 + + +#ifndef NGX_HAVE_INHERITED_NONBLOCK +#define NGX_HAVE_INHERITED_NONBLOCK 1 +#endif + +#ifndef NGX_HAVE_CASELESS_FILESYSTEM +#define NGX_HAVE_CASELESS_FILESYSTEM 1 +#endif + +#ifndef NGX_HAVE_WIN32_TRANSMITPACKETS +#define NGX_HAVE_WIN32_TRANSMITPACKETS 1 +#define NGX_HAVE_WIN32_TRANSMITFILE 0 +#endif + +#ifndef NGX_HAVE_WIN32_TRANSMITFILE +#define NGX_HAVE_WIN32_TRANSMITFILE 1 +#endif + +#if (NGX_HAVE_WIN32_TRANSMITPACKETS) || (NGX_HAVE_WIN32_TRANSMITFILE) +#define NGX_HAVE_SENDFILE 1 +#endif + +#ifndef NGX_HAVE_SO_SNDLOWAT +/* setsockopt(SO_SNDLOWAT) returns error WSAENOPROTOOPT */ +#define NGX_HAVE_SO_SNDLOWAT 0 +#endif + +#define NGX_HAVE_GETADDRINFO 1 + +#define ngx_random rand +#define ngx_debug_init() + + +#endif /* _NGX_WIN32_CONFIG_H_INCLUDED_ */ diff --git a/app/nginx/src/os/win32/ngx_win32_init.c b/app/nginx/src/os/win32/ngx_win32_init.c new file mode 100644 index 0000000..ec9b51e --- /dev/null +++ b/app/nginx/src/os/win32/ngx_win32_init.c @@ -0,0 +1,297 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <nginx.h> + + +ngx_uint_t ngx_win32_version; +ngx_uint_t ngx_ncpu; +ngx_uint_t ngx_max_wsabufs; +ngx_int_t ngx_max_sockets; +ngx_uint_t ngx_inherited_nonblocking = 1; +ngx_uint_t ngx_tcp_nodelay_and_tcp_nopush; + +char ngx_unique[NGX_INT32_LEN + 1]; + + +ngx_os_io_t ngx_os_io = { + ngx_wsarecv, + ngx_wsarecv_chain, + ngx_udp_wsarecv, + ngx_wsasend, + NULL, + NULL, + ngx_wsasend_chain, + 0 +}; + + +typedef struct { + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; +} ngx_osviex_stub_t; + + +static u_int osviex; +static OSVERSIONINFOEX osvi; + +/* Should these pointers be per protocol ? */ +LPFN_ACCEPTEX ngx_acceptex; +LPFN_GETACCEPTEXSOCKADDRS ngx_getacceptexsockaddrs; +LPFN_TRANSMITFILE ngx_transmitfile; +LPFN_TRANSMITPACKETS ngx_transmitpackets; +LPFN_CONNECTEX ngx_connectex; +LPFN_DISCONNECTEX ngx_disconnectex; + +static GUID ax_guid = WSAID_ACCEPTEX; +static GUID as_guid = WSAID_GETACCEPTEXSOCKADDRS; +static GUID tf_guid = WSAID_TRANSMITFILE; +static GUID tp_guid = WSAID_TRANSMITPACKETS; +static GUID cx_guid = WSAID_CONNECTEX; +static GUID dx_guid = WSAID_DISCONNECTEX; + + +ngx_int_t +ngx_os_init(ngx_log_t *log) +{ + DWORD bytes; + SOCKET s; + WSADATA wsd; + ngx_err_t err; + ngx_time_t *tp; + ngx_uint_t n; + SYSTEM_INFO si; + + /* get Windows version */ + + ngx_memzero(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + +#ifdef _MSC_VER +#pragma warning(disable:4996) +#endif + + osviex = GetVersionEx((OSVERSIONINFO *) &osvi); + + if (osviex == 0) { + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if (GetVersionEx((OSVERSIONINFO *) &osvi) == 0) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "GetVersionEx() failed"); + return NGX_ERROR; + } + } + +#ifdef _MSC_VER +#pragma warning(default:4996) +#endif + + /* + * Windows 3.1 Win32s 0xxxxx + * + * Windows 95 140000 + * Windows 98 141000 + * Windows ME 149000 + * Windows NT 3.51 235100 + * Windows NT 4.0 240000 + * Windows NT 4.0 SP5 240050 + * Windows 2000 250000 + * Windows XP 250100 + * Windows 2003 250200 + * Windows Vista/2008 260000 + * + * Windows CE x.x 3xxxxx + */ + + ngx_win32_version = osvi.dwPlatformId * 100000 + + osvi.dwMajorVersion * 10000 + + osvi.dwMinorVersion * 100; + + if (osviex) { + ngx_win32_version += osvi.wServicePackMajor * 10 + + osvi.wServicePackMinor; + } + + GetSystemInfo(&si); + ngx_pagesize = si.dwPageSize; + ngx_allocation_granularity = si.dwAllocationGranularity; + ngx_ncpu = si.dwNumberOfProcessors; + ngx_cacheline_size = NGX_CPU_CACHE_LINE; + + for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ } + + /* delete default "C" locale for _wcsicmp() */ + setlocale(LC_ALL, ""); + + + /* init Winsock */ + + if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "WSAStartup() failed"); + return NGX_ERROR; + } + + if (ngx_win32_version < NGX_WIN_NT) { + ngx_max_wsabufs = 16; + return NGX_OK; + } + + /* STUB: ngx_uint_t max */ + ngx_max_wsabufs = 1024 * 1024; + + /* + * get AcceptEx(), GetAcceptExSockAddrs(), TransmitFile(), + * TransmitPackets(), ConnectEx(), and DisconnectEx() addresses + */ + + s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (s == (ngx_socket_t) -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_socket_n " failed"); + return NGX_ERROR; + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &ax_guid, sizeof(GUID), + &ngx_acceptex, sizeof(LPFN_ACCEPTEX), &bytes, NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_ACCEPTEX) failed"); + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &as_guid, sizeof(GUID), + &ngx_getacceptexsockaddrs, sizeof(LPFN_GETACCEPTEXSOCKADDRS), + &bytes, NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_GETACCEPTEXSOCKADDRS) failed"); + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &tf_guid, sizeof(GUID), + &ngx_transmitfile, sizeof(LPFN_TRANSMITFILE), &bytes, + NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_TRANSMITFILE) failed"); + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &tp_guid, sizeof(GUID), + &ngx_transmitpackets, sizeof(LPFN_TRANSMITPACKETS), &bytes, + NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_TRANSMITPACKETS) failed"); + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &cx_guid, sizeof(GUID), + &ngx_connectex, sizeof(LPFN_CONNECTEX), &bytes, + NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_CONNECTEX) failed"); + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &dx_guid, sizeof(GUID), + &ngx_disconnectex, sizeof(LPFN_DISCONNECTEX), &bytes, + NULL, NULL) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_DISCONNECTEX) failed"); + } + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + if (GetEnvironmentVariable("ngx_unique", ngx_unique, NGX_INT32_LEN + 1) + != 0) + { + ngx_process = NGX_PROCESS_WORKER; + + } else { + err = ngx_errno; + + if (err != ERROR_ENVVAR_NOT_FOUND) { + ngx_log_error(NGX_LOG_EMERG, log, err, + "GetEnvironmentVariable(\"ngx_unique\") failed"); + return NGX_ERROR; + } + + ngx_sprintf((u_char *) ngx_unique, "%P%Z", ngx_pid); + } + + tp = ngx_timeofday(); + srand((ngx_pid << 16) ^ (unsigned) tp->sec ^ tp->msec); + + return NGX_OK; +} + + +void +ngx_os_status(ngx_log_t *log) +{ + ngx_osviex_stub_t *osviex_stub; + + ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER_BUILD); + + if (osviex) { + + /* + * the MSVC 6.0 SP2 defines wSuiteMask and wProductType + * as WORD wReserved[2] + */ + osviex_stub = (ngx_osviex_stub_t *) &osvi.wServicePackMinor; + + ngx_log_error(NGX_LOG_INFO, log, 0, + "OS: %ud build:%ud, \"%s\", suite:%Xd, type:%ud", + ngx_win32_version, osvi.dwBuildNumber, osvi.szCSDVersion, + osviex_stub->wSuiteMask, osviex_stub->wProductType); + + } else { + if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { + + /* Win9x build */ + + ngx_log_error(NGX_LOG_INFO, log, 0, + "OS: %u build:%ud.%ud.%ud, \"%s\"", + ngx_win32_version, + osvi.dwBuildNumber >> 24, + (osvi.dwBuildNumber >> 16) & 0xff, + osvi.dwBuildNumber & 0xffff, + osvi.szCSDVersion); + + } else { + + /* + * VER_PLATFORM_WIN32_NT + * + * we do not currently support VER_PLATFORM_WIN32_CE + * and we do not support VER_PLATFORM_WIN32s at all + */ + + ngx_log_error(NGX_LOG_INFO, log, 0, "OS: %ud build:%ud, \"%s\"", + ngx_win32_version, osvi.dwBuildNumber, + osvi.szCSDVersion); + } + } +} diff --git a/app/nginx/src/os/win32/ngx_wsarecv.c b/app/nginx/src/os/win32/ngx_wsarecv.c new file mode 100644 index 0000000..1925f0b --- /dev/null +++ b/app/nginx/src/os/win32/ngx_wsarecv.c @@ -0,0 +1,174 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +ssize_t +ngx_wsarecv(ngx_connection_t *c, u_char *buf, size_t size) +{ + int rc; + u_long bytes, flags; + WSABUF wsabuf[1]; + ngx_err_t err; + ngx_int_t n; + ngx_event_t *rev; + + wsabuf[0].buf = (char *) buf; + wsabuf[0].len = size; + flags = 0; + bytes = 0; + + rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, NULL, NULL); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: fd:%d rc:%d %ul of %z", c->fd, rc, bytes, size); + + rev = c->read; + + if (rc == -1) { + rev->ready = 0; + err = ngx_socket_errno; + + if (err == WSAEWOULDBLOCK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSARecv() not ready"); + return NGX_AGAIN; + } + + n = ngx_connection_error(c, err, "WSARecv() failed"); + + if (n == NGX_ERROR) { + rev->error = 1; + } + + return n; + } + + if (bytes < size) { + rev->ready = 0; + } + + if (bytes == 0) { + rev->eof = 1; + } + + return bytes; +} + + +ssize_t +ngx_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, size_t size) +{ + int rc; + u_long bytes, flags; + WSABUF wsabuf[1]; + ngx_err_t err; + ngx_int_t n; + ngx_event_t *rev; + LPWSAOVERLAPPED ovlp; + + rev = c->read; + + if (!rev->ready) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "second wsa post"); + return NGX_AGAIN; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "rev->complete: %d", rev->complete); + + if (rev->complete) { + rev->complete = 0; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + if (rev->ovlp.error) { + ngx_connection_error(c, rev->ovlp.error, "WSARecv() failed"); + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv ovlp: fd:%d %ul of %z", + c->fd, rev->available, size); + + return rev->available; + } + + if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &rev->ovlp, + &bytes, 0, NULL) + == 0) + { + ngx_connection_error(c, ngx_socket_errno, + "WSARecv() or WSAGetOverlappedResult() failed"); + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: fd:%d %ul of %z", c->fd, bytes, size); + + return bytes; + } + + ovlp = (LPWSAOVERLAPPED) &rev->ovlp; + ngx_memzero(ovlp, sizeof(WSAOVERLAPPED)); + wsabuf[0].buf = (char *) buf; + wsabuf[0].len = size; + flags = 0; + bytes = 0; + + rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, ovlp, NULL); + + rev->complete = 0; + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv ovlp: fd:%d rc:%d %ul of %z", + c->fd, rc, bytes, size); + + if (rc == -1) { + err = ngx_socket_errno; + if (err == WSA_IO_PENDING) { + rev->active = 1; + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSARecv() posted"); + return NGX_AGAIN; + } + + n = ngx_connection_error(c, err, "WSARecv() failed"); + + if (n == NGX_ERROR) { + rev->error = 1; + } + + return n; + } + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + /* + * if a socket was bound with I/O completion port + * then GetQueuedCompletionStatus() would anyway return its status + * despite that WSARecv() was already complete + */ + + rev->active = 1; + return NGX_AGAIN; + } + + if (bytes == 0) { + rev->eof = 1; + rev->ready = 0; + + } else { + rev->ready = 1; + } + + rev->active = 0; + + return bytes; +} diff --git a/app/nginx/src/os/win32/ngx_wsarecv_chain.c b/app/nginx/src/os/win32/ngx_wsarecv_chain.c new file mode 100644 index 0000000..2598e09 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_wsarecv_chain.c @@ -0,0 +1,106 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +#define NGX_WSABUFS 8 + + +ssize_t +ngx_wsarecv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) +{ + int rc; + u_char *prev; + u_long bytes, flags; + size_t n, size; + ngx_err_t err; + ngx_array_t vec; + ngx_event_t *rev; + LPWSABUF wsabuf; + WSABUF wsabufs[NGX_WSABUFS]; + + prev = NULL; + wsabuf = NULL; + flags = 0; + size = 0; + bytes = 0; + + vec.elts = wsabufs; + vec.nelts = 0; + vec.size = sizeof(WSABUF); + vec.nalloc = NGX_WSABUFS; + vec.pool = c->pool; + + /* coalesce the neighbouring bufs */ + + while (chain) { + n = chain->buf->end - chain->buf->last; + + if (limit) { + if (size >= (size_t) limit) { + break; + } + + if (size + n > (size_t) limit) { + n = (size_t) limit - size; + } + } + + if (prev == chain->buf->last) { + wsabuf->len += n; + + } else { + wsabuf = ngx_array_push(&vec); + if (wsabuf == NULL) { + return NGX_ERROR; + } + + wsabuf->buf = (char *) chain->buf->last; + wsabuf->len = n; + } + + size += n; + prev = chain->buf->end; + chain = chain->next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSARecv: %d:%d", vec.nelts, wsabuf->len); + + + rc = WSARecv(c->fd, vec.elts, vec.nelts, &bytes, &flags, NULL, NULL); + + rev = c->read; + + if (rc == -1) { + rev->ready = 0; + err = ngx_socket_errno; + + if (err == WSAEWOULDBLOCK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSARecv() not ready"); + return NGX_AGAIN; + } + + rev->error = 1; + ngx_connection_error(c, err, "WSARecv() failed"); + return NGX_ERROR; + } + + if (bytes < size) { + rev->ready = 0; + } + + if (bytes == 0) { + rev->eof = 1; + } + + return bytes; +} diff --git a/app/nginx/src/os/win32/ngx_wsasend.c b/app/nginx/src/os/win32/ngx_wsasend.c new file mode 100644 index 0000000..d6a23d1 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_wsasend.c @@ -0,0 +1,185 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +ssize_t +ngx_wsasend(ngx_connection_t *c, u_char *buf, size_t size) +{ + int n; + u_long sent; + ngx_err_t err; + ngx_event_t *wev; + WSABUF wsabuf; + + wev = c->write; + + if (!wev->ready) { + return NGX_AGAIN; + } + + /* + * WSABUF must be 4-byte aligned otherwise + * WSASend() will return undocumented WSAEINVAL error. + */ + + wsabuf.buf = (char *) buf; + wsabuf.len = size; + + sent = 0; + + n = WSASend(c->fd, &wsabuf, 1, &sent, 0, NULL, NULL); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend: fd:%d, %d, %ul of %uz", c->fd, n, sent, size); + + if (n == 0) { + if (sent < size) { + wev->ready = 0; + } + + c->sent += sent; + + return sent; + } + + err = ngx_socket_errno; + + if (err == WSAEWOULDBLOCK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "WSASend() not ready"); + wev->ready = 0; + return NGX_AGAIN; + } + + wev->error = 1; + ngx_connection_error(c, err, "WSASend() failed"); + + return NGX_ERROR; +} + + +ssize_t +ngx_overlapped_wsasend(ngx_connection_t *c, u_char *buf, size_t size) +{ + int n; + u_long sent; + ngx_err_t err; + ngx_event_t *wev; + LPWSAOVERLAPPED ovlp; + WSABUF wsabuf; + + wev = c->write; + + if (!wev->ready) { + return NGX_AGAIN; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "wev->complete: %d", wev->complete); + + if (!wev->complete) { + + /* post the overlapped WSASend() */ + + /* + * WSABUFs must be 4-byte aligned otherwise + * WSASend() will return undocumented WSAEINVAL error. + */ + + wsabuf.buf = (char *) buf; + wsabuf.len = size; + + sent = 0; + + ovlp = (LPWSAOVERLAPPED) &c->write->ovlp; + ngx_memzero(ovlp, sizeof(WSAOVERLAPPED)); + + n = WSASend(c->fd, &wsabuf, 1, &sent, 0, ovlp, NULL); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend: fd:%d, %d, %ul of %uz", c->fd, n, sent, size); + + wev->complete = 0; + + if (n == 0) { + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + /* + * if a socket was bound with I/O completion port then + * GetQueuedCompletionStatus() would anyway return its status + * despite that WSASend() was already complete + */ + + wev->active = 1; + return NGX_AGAIN; + } + + if (sent < size) { + wev->ready = 0; + } + + c->sent += sent; + + return sent; + } + + err = ngx_socket_errno; + + if (err == WSA_IO_PENDING) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSASend() posted"); + wev->active = 1; + return NGX_AGAIN; + } + + wev->error = 1; + ngx_connection_error(c, err, "WSASend() failed"); + + return NGX_ERROR; + } + + /* the overlapped WSASend() complete */ + + wev->complete = 0; + wev->active = 0; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + if (wev->ovlp.error) { + ngx_connection_error(c, wev->ovlp.error, "WSASend() failed"); + return NGX_ERROR; + } + + sent = wev->available; + + } else { + if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &wev->ovlp, + &sent, 0, NULL) + == 0) + { + ngx_connection_error(c, ngx_socket_errno, + "WSASend() or WSAGetOverlappedResult() failed"); + + return NGX_ERROR; + } + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSAGetOverlappedResult: fd:%d, %ul of %uz", + c->fd, sent, size); + + if (sent < size) { + wev->ready = 0; + } + + c->sent += sent; + + return sent; +} diff --git a/app/nginx/src/os/win32/ngx_wsasend_chain.c b/app/nginx/src/os/win32/ngx_wsasend_chain.c new file mode 100644 index 0000000..e2dde22 --- /dev/null +++ b/app/nginx/src/os/win32/ngx_wsasend_chain.c @@ -0,0 +1,292 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> + + +#define NGX_WSABUFS 8 + + +ngx_chain_t * +ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + int rc; + u_char *prev; + u_long size, sent, send, prev_send; + ngx_err_t err; + ngx_event_t *wev; + ngx_array_t vec; + ngx_chain_t *cl; + LPWSABUF wsabuf; + WSABUF wsabufs[NGX_WSABUFS]; + + wev = c->write; + + if (!wev->ready) { + return in; + } + + /* the maximum limit size is the maximum u_long value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_UINT32_VALUE - ngx_pagesize)) { + limit = NGX_MAX_UINT32_VALUE - ngx_pagesize; + } + + send = 0; + + /* + * WSABUFs must be 4-byte aligned otherwise + * WSASend() will return undocumented WSAEINVAL error. + */ + + vec.elts = wsabufs; + vec.size = sizeof(WSABUF); + vec.nalloc = NGX_WSABUFS; + vec.pool = c->pool; + + for ( ;; ) { + prev = NULL; + wsabuf = NULL; + prev_send = send; + + vec.nelts = 0; + + /* create the WSABUF and coalesce the neighbouring bufs */ + + for (cl = in; + cl && vec.nelts < ngx_max_wsabufs && send < limit; + cl = cl->next) + { + if (ngx_buf_special(cl->buf)) { + continue; + } + + size = cl->buf->last - cl->buf->pos; + + if (send + size > limit) { + size = (u_long) (limit - send); + } + + if (prev == cl->buf->pos) { + wsabuf->len += cl->buf->last - cl->buf->pos; + + } else { + wsabuf = ngx_array_push(&vec); + if (wsabuf == NULL) { + return NGX_CHAIN_ERROR; + } + + wsabuf->buf = (char *) cl->buf->pos; + wsabuf->len = cl->buf->last - cl->buf->pos; + } + + prev = cl->buf->last; + send += size; + } + + sent = 0; + + rc = WSASend(c->fd, vec.elts, vec.nelts, &sent, 0, NULL, NULL); + + if (rc == -1) { + err = ngx_errno; + + if (err == WSAEWOULDBLOCK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSASend() not ready"); + + } else { + wev->error = 1; + ngx_connection_error(c, err, "WSASend() failed"); + return NGX_CHAIN_ERROR; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend: fd:%d, s:%ul", c->fd, sent); + + c->sent += sent; + + in = ngx_chain_update_sent(in, sent); + + if (send - prev_send != sent) { + wev->ready = 0; + return in; + } + + if (send >= limit || in == NULL) { + return in; + } + } +} + + +ngx_chain_t * +ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +{ + int rc; + u_char *prev; + u_long size, send, sent; + ngx_err_t err; + ngx_event_t *wev; + ngx_array_t vec; + ngx_chain_t *cl; + LPWSAOVERLAPPED ovlp; + LPWSABUF wsabuf; + WSABUF wsabufs[NGX_WSABUFS]; + + wev = c->write; + + if (!wev->ready) { + return in; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "wev->complete: %d", wev->complete); + + if (!wev->complete) { + + /* post the overlapped WSASend() */ + + /* the maximum limit size is the maximum u_long value - the page size */ + + if (limit == 0 || limit > (off_t) (NGX_MAX_UINT32_VALUE - ngx_pagesize)) + { + limit = NGX_MAX_UINT32_VALUE - ngx_pagesize; + } + + /* + * WSABUFs must be 4-byte aligned otherwise + * WSASend() will return undocumented WSAEINVAL error. + */ + + vec.elts = wsabufs; + vec.nelts = 0; + vec.size = sizeof(WSABUF); + vec.nalloc = NGX_WSABUFS; + vec.pool = c->pool; + + send = 0; + prev = NULL; + wsabuf = NULL; + + /* create the WSABUF and coalesce the neighbouring bufs */ + + for (cl = in; + cl && vec.nelts < ngx_max_wsabufs && send < limit; + cl = cl->next) + { + if (ngx_buf_special(cl->buf)) { + continue; + } + + size = cl->buf->last - cl->buf->pos; + + if (send + size > limit) { + size = (u_long) (limit - send); + } + + if (prev == cl->buf->pos) { + wsabuf->len += cl->buf->last - cl->buf->pos; + + } else { + wsabuf = ngx_array_push(&vec); + if (wsabuf == NULL) { + return NGX_CHAIN_ERROR; + } + + wsabuf->buf = (char *) cl->buf->pos; + wsabuf->len = cl->buf->last - cl->buf->pos; + } + + prev = cl->buf->last; + send += size; + } + + ovlp = (LPWSAOVERLAPPED) &c->write->ovlp; + ngx_memzero(ovlp, sizeof(WSAOVERLAPPED)); + + rc = WSASend(c->fd, vec.elts, vec.nelts, &sent, 0, ovlp, NULL); + + wev->complete = 0; + + if (rc == -1) { + err = ngx_errno; + + if (err == WSA_IO_PENDING) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSASend() posted"); + wev->active = 1; + return in; + + } else { + wev->error = 1; + ngx_connection_error(c, err, "WSASend() failed"); + return NGX_CHAIN_ERROR; + } + + } else if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + /* + * if a socket was bound with I/O completion port then + * GetQueuedCompletionStatus() would anyway return its status + * despite that WSASend() was already complete + */ + + wev->active = 1; + return in; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend: fd:%d, s:%ul", c->fd, sent); + + } else { + + /* the overlapped WSASend() complete */ + + wev->complete = 0; + wev->active = 0; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + if (wev->ovlp.error) { + ngx_connection_error(c, wev->ovlp.error, "WSASend() failed"); + return NGX_CHAIN_ERROR; + } + + sent = wev->available; + + } else { + if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &wev->ovlp, + &sent, 0, NULL) + == 0) + { + ngx_connection_error(c, ngx_socket_errno, + "WSASend() or WSAGetOverlappedResult() failed"); + + return NGX_CHAIN_ERROR; + } + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend ovlp: fd:%d, s:%ul", c->fd, sent); + + c->sent += sent; + + in = ngx_chain_update_sent(in, sent); + + if (in) { + wev->ready = 0; + + } else { + wev->ready = 1; + } + + return in; +} |