Initial commit
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
extern int ngx_kqueue;
|
||||
|
||||
|
||||
ssize_t
|
||||
ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size)
|
||||
{
|
||||
int n;
|
||||
ngx_event_t *rev;
|
||||
|
||||
rev = c->read;
|
||||
|
||||
if (!rev->ready) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, 0, "second aio post");
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"rev->complete: %d", rev->complete);
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"aio size: %d", size);
|
||||
|
||||
if (!rev->complete) {
|
||||
ngx_memzero(&rev->aiocb, sizeof(struct aiocb));
|
||||
|
||||
rev->aiocb.aio_fildes = c->fd;
|
||||
rev->aiocb.aio_buf = buf;
|
||||
rev->aiocb.aio_nbytes = size;
|
||||
|
||||
#if (NGX_HAVE_KQUEUE)
|
||||
rev->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue;
|
||||
rev->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
|
||||
rev->aiocb.aio_sigevent.sigev_value.sigval_ptr = rev;
|
||||
#endif
|
||||
|
||||
if (aio_read(&rev->aiocb) == -1) {
|
||||
ngx_log_error(NGX_LOG_CRIT, rev->log, ngx_errno,
|
||||
"aio_read() failed");
|
||||
rev->error = 1;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"aio_read: #%d OK", c->fd);
|
||||
|
||||
rev->active = 1;
|
||||
rev->ready = 0;
|
||||
}
|
||||
|
||||
rev->complete = 0;
|
||||
|
||||
n = aio_error(&rev->aiocb);
|
||||
if (n == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "aio_error() failed");
|
||||
rev->error = 1;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (n != 0) {
|
||||
if (n == NGX_EINPROGRESS) {
|
||||
if (rev->ready) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, n,
|
||||
"aio_read() still in progress");
|
||||
rev->ready = 0;
|
||||
}
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_CRIT, c->log, n, "aio_read() failed");
|
||||
rev->error = 1;
|
||||
rev->ready = 0;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
n = aio_return(&rev->aiocb);
|
||||
if (n == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
|
||||
"aio_return() failed");
|
||||
|
||||
rev->error = 1;
|
||||
rev->ready = 0;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, rev->log, 0,
|
||||
"aio_read: #%d %d", c->fd, n);
|
||||
|
||||
if (n == 0) {
|
||||
rev->eof = 1;
|
||||
rev->ready = 0;
|
||||
} else {
|
||||
rev->ready = 1;
|
||||
}
|
||||
|
||||
rev->active = 0;
|
||||
|
||||
return n;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
ssize_t
|
||||
ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit)
|
||||
{
|
||||
int n;
|
||||
u_char *buf, *prev;
|
||||
size_t size;
|
||||
ssize_t total;
|
||||
|
||||
if (c->read->pending_eof) {
|
||||
c->read->ready = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
total = 0;
|
||||
|
||||
while (cl) {
|
||||
|
||||
/* we can post the single aio operation only */
|
||||
|
||||
if (!c->read->ready) {
|
||||
return total ? total : NGX_AGAIN;
|
||||
}
|
||||
|
||||
buf = cl->buf->last;
|
||||
prev = cl->buf->last;
|
||||
size = 0;
|
||||
|
||||
/* coalesce the neighbouring bufs */
|
||||
|
||||
while (cl && prev == cl->buf->last) {
|
||||
size += cl->buf->end - cl->buf->last;
|
||||
prev = cl->buf->end;
|
||||
cl = cl->next;
|
||||
}
|
||||
|
||||
n = ngx_aio_read(c, buf, size);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "aio_read: %d", n);
|
||||
|
||||
if (n == NGX_AGAIN) {
|
||||
return total ? total : NGX_AGAIN;
|
||||
}
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
c->read->pending_eof = 1;
|
||||
if (total) {
|
||||
c->read->eof = 0;
|
||||
c->read->ready = 1;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
total += n;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"aio_read total: %d", total);
|
||||
}
|
||||
|
||||
return total ? total : NGX_AGAIN;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
extern int ngx_kqueue;
|
||||
|
||||
|
||||
ssize_t
|
||||
ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size)
|
||||
{
|
||||
int n;
|
||||
ngx_event_t *wev;
|
||||
|
||||
wev = c->write;
|
||||
|
||||
if (!wev->ready) {
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, wev->log, 0,
|
||||
"aio: wev->complete: %d", wev->complete);
|
||||
|
||||
if (!wev->complete) {
|
||||
ngx_memzero(&wev->aiocb, sizeof(struct aiocb));
|
||||
|
||||
wev->aiocb.aio_fildes = c->fd;
|
||||
wev->aiocb.aio_buf = buf;
|
||||
wev->aiocb.aio_nbytes = size;
|
||||
|
||||
#if (NGX_HAVE_KQUEUE)
|
||||
wev->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue;
|
||||
wev->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
|
||||
wev->aiocb.aio_sigevent.sigev_value.sigval_ptr = wev;
|
||||
#endif
|
||||
|
||||
if (aio_write(&wev->aiocb) == -1) {
|
||||
ngx_log_error(NGX_LOG_CRIT, wev->log, ngx_errno,
|
||||
"aio_write() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, wev->log, 0, "aio_write: OK");
|
||||
|
||||
wev->active = 1;
|
||||
wev->ready = 0;
|
||||
}
|
||||
|
||||
wev->complete = 0;
|
||||
|
||||
n = aio_error(&wev->aiocb);
|
||||
if (n == -1) {
|
||||
ngx_log_error(NGX_LOG_CRIT, wev->log, ngx_errno, "aio_error() failed");
|
||||
wev->error = 1;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (n != 0) {
|
||||
if (n == NGX_EINPROGRESS) {
|
||||
if (wev->ready) {
|
||||
ngx_log_error(NGX_LOG_ALERT, wev->log, n,
|
||||
"aio_write() still in progress");
|
||||
wev->ready = 0;
|
||||
}
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_CRIT, wev->log, n, "aio_write() failed");
|
||||
wev->error = 1;
|
||||
wev->ready = 0;
|
||||
|
||||
#if 1
|
||||
n = aio_return(&wev->aiocb);
|
||||
if (n == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, wev->log, ngx_errno,
|
||||
"aio_return() failed");
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_CRIT, wev->log, n, "aio_return() %d", n);
|
||||
#endif
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
n = aio_return(&wev->aiocb);
|
||||
if (n == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, wev->log, ngx_errno,
|
||||
"aio_return() failed");
|
||||
|
||||
wev->error = 1;
|
||||
wev->ready = 0;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, wev->log, 0, "aio_write: %d", n);
|
||||
|
||||
wev->active = 0;
|
||||
wev->ready = 1;
|
||||
|
||||
return n;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
ngx_chain_t *
|
||||
ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
|
||||
{
|
||||
u_char *buf, *prev;
|
||||
off_t send, sent;
|
||||
size_t len;
|
||||
ssize_t n, size;
|
||||
ngx_chain_t *cl;
|
||||
|
||||
/* 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;
|
||||
sent = 0;
|
||||
cl = in;
|
||||
|
||||
while (cl) {
|
||||
|
||||
if (cl->buf->pos == cl->buf->last) {
|
||||
cl = cl->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we can post the single aio operation only */
|
||||
|
||||
if (!c->write->ready) {
|
||||
return cl;
|
||||
}
|
||||
|
||||
buf = cl->buf->pos;
|
||||
prev = buf;
|
||||
len = 0;
|
||||
|
||||
/* coalesce the neighbouring bufs */
|
||||
|
||||
while (cl && prev == cl->buf->pos && send < limit) {
|
||||
if (ngx_buf_special(cl->buf)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size = cl->buf->last - cl->buf->pos;
|
||||
|
||||
if (send + size > limit) {
|
||||
size = limit - send;
|
||||
}
|
||||
|
||||
len += size;
|
||||
prev = cl->buf->pos + size;
|
||||
send += size;
|
||||
cl = cl->next;
|
||||
}
|
||||
|
||||
n = ngx_aio_write(c, buf, len);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "aio_write: %z", n);
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
return NGX_CHAIN_ERROR;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
sent += n;
|
||||
c->sent += n;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"aio_write sent: %O", c->sent);
|
||||
|
||||
for (cl = in; cl; cl = cl->next) {
|
||||
|
||||
if (sent >= cl->buf->last - cl->buf->pos) {
|
||||
sent -= cl->buf->last - cl->buf->pos;
|
||||
cl->buf->pos = cl->buf->last;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
cl->buf->pos += sent;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cl;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -0,0 +1,95 @@
|
||||
|
||||
/*
|
||||
* 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>
|
||||
|
||||
|
||||
#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_ */
|
||||
@@ -0,0 +1,196 @@
|
||||
|
||||
/*
|
||||
* 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,
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
|
||||
/*
|
||||
* 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_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_ */
|
||||
@@ -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:%z %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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,673 @@
|
||||
|
||||
/*
|
||||
* 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);
|
||||
#endif
|
||||
|
||||
|
||||
#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;
|
||||
u_char *buf;
|
||||
size_t size;
|
||||
off_t offset;
|
||||
|
||||
size_t read;
|
||||
ngx_err_t err;
|
||||
} ngx_thread_read_ctx_t;
|
||||
|
||||
|
||||
ssize_t
|
||||
ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file, u_char *buf,
|
||||
size_t size, off_t offset, ngx_pool_t *pool)
|
||||
{
|
||||
ngx_thread_task_t *task;
|
||||
ngx_thread_read_ctx_t *ctx;
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
|
||||
"thread read: %d, %p, %uz, %O",
|
||||
file->fd, buf, size, offset);
|
||||
|
||||
task = *taskp;
|
||||
|
||||
if (task == NULL) {
|
||||
task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_read_ctx_t));
|
||||
if (task == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
task->handler = ngx_thread_read_handler;
|
||||
|
||||
*taskp = task;
|
||||
}
|
||||
|
||||
ctx = task->ctx;
|
||||
|
||||
if (task->event.complete) {
|
||||
task->event.complete = 0;
|
||||
|
||||
if (ctx->err) {
|
||||
ngx_log_error(NGX_LOG_CRIT, file->log, ctx->err,
|
||||
"pread() \"%s\" failed", file->name.data);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return ctx->read;
|
||||
}
|
||||
|
||||
ctx->fd = file->fd;
|
||||
ctx->buf = buf;
|
||||
ctx->size = size;
|
||||
ctx->offset = offset;
|
||||
|
||||
if (file->thread_handler(task, file) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_HAVE_PREAD)
|
||||
|
||||
static void
|
||||
ngx_thread_read_handler(void *data, ngx_log_t *log)
|
||||
{
|
||||
ngx_thread_read_ctx_t *ctx = data;
|
||||
|
||||
ssize_t n;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "thread read handler");
|
||||
|
||||
n = pread(ctx->fd, ctx->buf, ctx->size, ctx->offset);
|
||||
|
||||
if (n == -1) {
|
||||
ctx->err = ngx_errno;
|
||||
|
||||
} else {
|
||||
ctx->read = n;
|
||||
ctx->err = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
ngx_time_update();
|
||||
#endif
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_CORE, log, 0,
|
||||
"pread: %z (err: %i) of %uz @%O",
|
||||
n, ctx->err, ctx->size, ctx->offset);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error pread() is required!
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* NGX_THREADS */
|
||||
|
||||
|
||||
ssize_t
|
||||
ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
|
||||
{
|
||||
ssize_t n, written;
|
||||
|
||||
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) {
|
||||
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
|
||||
"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) {
|
||||
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
|
||||
"write() \"%s\" failed", file->name.data);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#define NGX_IOVS 8
|
||||
|
||||
ssize_t
|
||||
ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset,
|
||||
ngx_pool_t *pool)
|
||||
{
|
||||
u_char *prev;
|
||||
size_t size;
|
||||
ssize_t total, n;
|
||||
ngx_array_t vec;
|
||||
struct iovec *iov, iovs[NGX_IOVS];
|
||||
|
||||
/* 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.elts = iovs;
|
||||
vec.size = sizeof(struct iovec);
|
||||
vec.nalloc = NGX_IOVS;
|
||||
vec.pool = pool;
|
||||
|
||||
do {
|
||||
prev = NULL;
|
||||
iov = NULL;
|
||||
size = 0;
|
||||
|
||||
vec.nelts = 0;
|
||||
|
||||
/* create the iovec and coalesce the neighbouring bufs */
|
||||
|
||||
while (cl && vec.nelts < IOV_MAX) {
|
||||
if (prev == cl->buf->pos) {
|
||||
iov->iov_len += cl->buf->last - cl->buf->pos;
|
||||
|
||||
} else {
|
||||
iov = ngx_array_push(&vec);
|
||||
if (iov == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
iov->iov_base = (void *) cl->buf->pos;
|
||||
iov->iov_len = cl->buf->last - cl->buf->pos;
|
||||
}
|
||||
|
||||
size += cl->buf->last - cl->buf->pos;
|
||||
prev = cl->buf->last;
|
||||
cl = cl->next;
|
||||
}
|
||||
|
||||
/* use pwrite() if there is the only iovec buffer */
|
||||
|
||||
if (vec.nelts == 1) {
|
||||
iov = vec.elts;
|
||||
|
||||
n = ngx_write_file(file, (u_char *) iov[0].iov_base,
|
||||
iov[0].iov_len, offset);
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
return n;
|
||||
}
|
||||
|
||||
return total + n;
|
||||
}
|
||||
|
||||
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 = writev(file->fd, vec.elts, vec.nelts);
|
||||
|
||||
if (n == -1) {
|
||||
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
|
||||
"writev() \"%s\" failed", file->name.data);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((size_t) n != size) {
|
||||
ngx_log_error(NGX_LOG_CRIT, file->log, 0,
|
||||
"writev() \"%s\" has written only %z of %uz",
|
||||
file->name.data, n, size);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
|
||||
"writev: %d, %z", file->fd, n);
|
||||
|
||||
file->sys_offset += n;
|
||||
file->offset += n;
|
||||
offset += n;
|
||||
total += n;
|
||||
|
||||
} while (cl);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
@@ -0,0 +1,392 @@
|
||||
|
||||
/*
|
||||
* 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_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_thread_task_t **taskp, ngx_file_t *file,
|
||||
u_char *buf, size_t size, off_t offset, ngx_pool_t *pool);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_FILES_H_INCLUDED_ */
|
||||
@@ -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_ */
|
||||
@@ -0,0 +1,121 @@
|
||||
|
||||
/*
|
||||
* 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>
|
||||
|
||||
|
||||
#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 || NGX_HAVE_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_ */
|
||||
@@ -0,0 +1,260 @@
|
||||
|
||||
/*
|
||||
* 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,
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
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 (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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")
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
extern int ngx_linux_rtsig_max;
|
||||
|
||||
|
||||
#endif /* _NGX_LINUX_H_INCLUDED_ */
|
||||
@@ -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:%z %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);
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
|
||||
/*
|
||||
* 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 <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_RTSIG)
|
||||
#include <poll.h>
|
||||
#include <sys/sysctl.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_ */
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
/*
|
||||
* 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];
|
||||
|
||||
int ngx_linux_rtsig_max;
|
||||
|
||||
|
||||
static ngx_os_io_t ngx_linux_io = {
|
||||
ngx_unix_recv,
|
||||
ngx_readv_chain,
|
||||
ngx_udp_unix_recv,
|
||||
ngx_unix_send,
|
||||
#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));
|
||||
|
||||
#if (NGX_HAVE_RTSIG)
|
||||
{
|
||||
int name[2];
|
||||
size_t len;
|
||||
ngx_err_t err;
|
||||
|
||||
name[0] = CTL_KERN;
|
||||
name[1] = KERN_RTSIGMAX;
|
||||
len = sizeof(ngx_linux_rtsig_max);
|
||||
|
||||
if (sysctl(name, 2, &ngx_linux_rtsig_max, &len, NULL, 0) == -1) {
|
||||
err = ngx_errno;
|
||||
|
||||
if (err != NGX_ENOTDIR && err != NGX_ENOSYS) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"sysctl(KERN_RTSIGMAX) failed");
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_linux_rtsig_max = 0;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
#if (NGX_HAVE_RTSIG)
|
||||
ngx_log_error(NGX_LOG_NOTICE, log, 0, "sysctl(KERN_RTSIGMAX): %d",
|
||||
ngx_linux_rtsig_max);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
|
||||
/*
|
||||
* 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 ngx_int_t ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file,
|
||||
size_t size, size_t *sent);
|
||||
static void ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit
|
||||
* offsets only, and the including <sys/sendfile.h> breaks the compiling,
|
||||
* 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];
|
||||
#if (NGX_THREADS)
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t thread_handled, thread_complete;
|
||||
#endif
|
||||
|
||||
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;
|
||||
#if (NGX_THREADS)
|
||||
thread_handled = 0;
|
||||
thread_complete = 0;
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
|
||||
#if (NGX_THREADS)
|
||||
if (file->file->thread_handler) {
|
||||
rc = ngx_linux_sendfile_thread(c, file, file_size, &sent);
|
||||
|
||||
switch (rc) {
|
||||
case NGX_OK:
|
||||
thread_handled = 1;
|
||||
break;
|
||||
|
||||
case NGX_DONE:
|
||||
thread_complete = 1;
|
||||
break;
|
||||
|
||||
case NGX_AGAIN:
|
||||
break;
|
||||
|
||||
default: /* NGX_ERROR */
|
||||
return NGX_CHAIN_ERROR;
|
||||
}
|
||||
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
n = ngx_linux_sendfile(c, file, file_size);
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
return NGX_CHAIN_ERROR;
|
||||
}
|
||||
|
||||
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 ((size_t) (send - prev_send) != sent) {
|
||||
#if (NGX_THREADS)
|
||||
if (thread_handled) {
|
||||
return in;
|
||||
}
|
||||
|
||||
if (thread_complete) {
|
||||
send = prev_send + sent;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
wev->ready = 0;
|
||||
return in;
|
||||
}
|
||||
|
||||
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_HAVE_SENDFILE64)
|
||||
offset = file->file_pos;
|
||||
#else
|
||||
offset = (int32_t) file->file_pos;
|
||||
#endif
|
||||
|
||||
eintr:
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"sendfile: @%O %uz", file->file_pos, size);
|
||||
|
||||
n = sendfile(c->fd, file->file->fd, &offset, size);
|
||||
|
||||
if (n == -1) {
|
||||
err = ngx_errno;
|
||||
|
||||
switch (err) {
|
||||
case NGX_EAGAIN:
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
|
||||
"sendfile() is not ready");
|
||||
return NGX_AGAIN;
|
||||
|
||||
case NGX_EINTR:
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
|
||||
"sendfile() was interrupted");
|
||||
goto eintr;
|
||||
|
||||
default:
|
||||
c->write->error = 1;
|
||||
ngx_connection_error(c, err, "sendfile() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %z of %uz @%O",
|
||||
n, size, file->file_pos);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_THREADS)
|
||||
|
||||
typedef struct {
|
||||
ngx_buf_t *file;
|
||||
ngx_socket_t socket;
|
||||
size_t size;
|
||||
|
||||
size_t sent;
|
||||
ngx_err_t err;
|
||||
} ngx_linux_sendfile_ctx_t;
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size,
|
||||
size_t *sent)
|
||||
{
|
||||
ngx_uint_t flags;
|
||||
ngx_event_t *wev;
|
||||
ngx_thread_task_t *task;
|
||||
ngx_linux_sendfile_ctx_t *ctx;
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_CORE, c->log, 0,
|
||||
"linux sendfile thread: %d, %uz, %O",
|
||||
file->file->fd, size, file->file_pos);
|
||||
|
||||
task = c->sendfile_task;
|
||||
|
||||
if (task == NULL) {
|
||||
task = ngx_thread_task_alloc(c->pool, sizeof(ngx_linux_sendfile_ctx_t));
|
||||
if (task == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
task->handler = ngx_linux_sendfile_thread_handler;
|
||||
|
||||
c->sendfile_task = task;
|
||||
}
|
||||
|
||||
ctx = task->ctx;
|
||||
wev = c->write;
|
||||
|
||||
if (task->event.complete) {
|
||||
task->event.complete = 0;
|
||||
|
||||
if (ctx->err && ctx->err != NGX_EAGAIN) {
|
||||
wev->error = 1;
|
||||
ngx_connection_error(c, ctx->err, "sendfile() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*sent = ctx->sent;
|
||||
|
||||
return (ctx->sent == ctx->size) ? NGX_DONE : NGX_AGAIN;
|
||||
}
|
||||
|
||||
ctx->file = file;
|
||||
ctx->socket = c->fd;
|
||||
ctx->size = size;
|
||||
|
||||
if (wev->active) {
|
||||
flags = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ? NGX_CLEAR_EVENT
|
||||
: NGX_LEVEL_EVENT;
|
||||
|
||||
if (ngx_del_event(wev, NGX_WRITE_EVENT, flags) == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (file->file->thread_handler(task, file->file) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*sent = 0;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log)
|
||||
{
|
||||
ngx_linux_sendfile_ctx_t *ctx = data;
|
||||
|
||||
off_t offset;
|
||||
ssize_t n;
|
||||
ngx_buf_t *file;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "linux sendfile thread handler");
|
||||
|
||||
file = ctx->file;
|
||||
offset = file->file_pos;
|
||||
|
||||
again:
|
||||
|
||||
n = sendfile(ctx->socket, file->file->fd, &offset, ctx->size);
|
||||
|
||||
if (n == -1) {
|
||||
ctx->err = ngx_errno;
|
||||
|
||||
} else {
|
||||
ctx->sent = n;
|
||||
ctx->err = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
ngx_time_update();
|
||||
#endif
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0,
|
||||
"sendfile: %z (err: %i) of %uz @%O",
|
||||
n, ctx->err, ctx->size, file->file_pos);
|
||||
|
||||
if (ctx->err == NGX_EINTR) {
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NGX_THREADS */
|
||||
@@ -0,0 +1,105 @@
|
||||
|
||||
/*
|
||||
* 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_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_int_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);
|
||||
|
||||
#if (NGX_HAVE_AIO)
|
||||
ssize_t ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size);
|
||||
ssize_t ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit);
|
||||
ssize_t ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size);
|
||||
ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in,
|
||||
off_t limit);
|
||||
#endif
|
||||
|
||||
|
||||
#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_ */
|
||||
@@ -0,0 +1,158 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
|
||||
#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_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)
|
||||
#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_ */
|
||||
@@ -0,0 +1,130 @@
|
||||
|
||||
/*
|
||||
* 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_writev_chain,
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_os_init(ngx_log_t *log)
|
||||
{
|
||||
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
|
||||
|
||||
srandom(ngx_time());
|
||||
|
||||
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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
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_int_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;
|
||||
}
|
||||
@@ -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_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,60 @@
|
||||
|
||||
/*
|
||||
* 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_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_ */
|
||||
@@ -0,0 +1,186 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
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: %d, last:%d", vec.nelts, iov->iov_len);
|
||||
|
||||
do {
|
||||
n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (rev->available < 0) {
|
||||
rev->available = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
|
||||
/*
|
||||
* on FreeBSD recv() may return 0 on closed socket
|
||||
* even if kqueue reported about available data
|
||||
*/
|
||||
|
||||
#if 0
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
|
||||
"readv() returned 0 while kevent() reported "
|
||||
"%d available bytes", rev->available);
|
||||
#endif
|
||||
|
||||
rev->ready = 0;
|
||||
rev->eof = 1;
|
||||
rev->available = 0;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif /* NGX_HAVE_KQUEUE */
|
||||
|
||||
if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) {
|
||||
rev->ready = 0;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
rev->eof = 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#if (NGX_HAVE_KQUEUE)
|
||||
|
||||
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_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
n = recv(c->fd, buf, size, 0);
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"recv: fd:%d %d of %d", c->fd, n, size);
|
||||
|
||||
if (n >= 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (rev->available < 0) {
|
||||
rev->available = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
|
||||
/*
|
||||
* on FreeBSD recv() may return 0 on closed socket
|
||||
* even if kqueue reported about available data
|
||||
*/
|
||||
|
||||
rev->ready = 0;
|
||||
rev->eof = 1;
|
||||
rev->available = 0;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
if ((size_t) n < size
|
||||
&& !(ngx_event_flags & NGX_USE_GREEDY_EVENT))
|
||||
{
|
||||
rev->ready = 0;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
rev->eof = 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#else /* ! NGX_HAVE_KQUEUE */
|
||||
|
||||
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;
|
||||
|
||||
do {
|
||||
n = recv(c->fd, buf, size, 0);
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"recv: fd:%d %d of %d", c->fd, n, size);
|
||||
|
||||
if (n == 0) {
|
||||
rev->ready = 0;
|
||||
rev->eof = 1;
|
||||
return n;
|
||||
|
||||
} else if (n > 0) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif /* NGX_HAVE_KQUEUE */
|
||||
@@ -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 %d of %d", 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#if (NGX_HAVE_CPUSET_SETAFFINITY)
|
||||
|
||||
#include <sys/cpuset.h>
|
||||
|
||||
void
|
||||
ngx_setaffinity(uint64_t cpu_affinity, ngx_log_t *log)
|
||||
{
|
||||
cpuset_t mask;
|
||||
ngx_uint_t i;
|
||||
|
||||
ngx_log_error(NGX_LOG_NOTICE, log, 0,
|
||||
"cpuset_setaffinity(0x%08Xl)", cpu_affinity);
|
||||
|
||||
CPU_ZERO(&mask);
|
||||
i = 0;
|
||||
do {
|
||||
if (cpu_affinity & 1) {
|
||||
CPU_SET(i, &mask);
|
||||
}
|
||||
i++;
|
||||
cpu_affinity >>= 1;
|
||||
} while (cpu_affinity);
|
||||
|
||||
if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
|
||||
sizeof(cpuset_t), &mask) == -1)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
|
||||
"cpuset_setaffinity() failed");
|
||||
}
|
||||
}
|
||||
|
||||
#elif (NGX_HAVE_SCHED_SETAFFINITY)
|
||||
|
||||
void
|
||||
ngx_setaffinity(uint64_t cpu_affinity, ngx_log_t *log)
|
||||
{
|
||||
cpu_set_t mask;
|
||||
ngx_uint_t i;
|
||||
|
||||
ngx_log_error(NGX_LOG_NOTICE, log, 0,
|
||||
"sched_setaffinity(0x%08Xl)", cpu_affinity);
|
||||
|
||||
CPU_ZERO(&mask);
|
||||
i = 0;
|
||||
do {
|
||||
if (cpu_affinity & 1) {
|
||||
CPU_SET(i, &mask);
|
||||
}
|
||||
i++;
|
||||
cpu_affinity >>= 1;
|
||||
} while (cpu_affinity);
|
||||
|
||||
if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
|
||||
"sched_setaffinity() failed");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
void ngx_setaffinity(uint64_t cpu_affinity, ngx_log_t *log);
|
||||
|
||||
#else
|
||||
|
||||
#define ngx_setaffinity(cpu_affinity, log)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_SETAFFINITY_H_INCLUDED_ */
|
||||
@@ -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 */
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -0,0 +1,110 @@
|
||||
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#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_ */
|
||||
@@ -0,0 +1,75 @@
|
||||
|
||||
/*
|
||||
* 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,
|
||||
#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);
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
|
||||
/*
|
||||
* 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_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;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_ */
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_thread_cond_create(ngx_thread_cond_t *cond, ngx_log_t *log)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
err = pthread_cond_init(cond, NULL);
|
||||
if (err == 0) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
|
||||
"pthread_cond_init(%p)", cond);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_init() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_thread_cond_destroy(ngx_thread_cond_t *cond, ngx_log_t *log)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
err = pthread_cond_destroy(cond);
|
||||
if (err == 0) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
|
||||
"pthread_cond_destroy(%p)", cond);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_destroy() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_thread_cond_signal(ngx_thread_cond_t *cond, ngx_log_t *log)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
err = pthread_cond_signal(cond);
|
||||
if (err == 0) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
|
||||
"pthread_cond_signal(%p)", cond);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_EMERG, log, err, "pthread_cond_signal() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_thread_cond_wait(ngx_thread_cond_t *cond, ngx_thread_mutex_t *mtx,
|
||||
ngx_log_t *log)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
|
||||
"pthread_cond_wait(%p) enter", cond);
|
||||
|
||||
err = pthread_cond_wait(cond, mtx);
|
||||
|
||||
#if 0
|
||||
ngx_time_update();
|
||||
#endif
|
||||
|
||||
if (err == 0) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
|
||||
"pthread_cond_wait(%p) exit", cond);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_cond_wait() failed");
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,174 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
/*
|
||||
* All modern pthread mutex implementations try to acquire a lock
|
||||
* atomically in userland before going to sleep in kernel. Some
|
||||
* spins before the sleeping.
|
||||
*
|
||||
* In Solaris since version 8 all mutex types spin before sleeping.
|
||||
* The default spin count is 1000. It can be overridden using
|
||||
* _THREAD_ADAPTIVE_SPIN=100 environment variable.
|
||||
*
|
||||
* In MacOSX all mutex types spin to acquire a lock protecting a mutex's
|
||||
* internals. If the mutex is busy, thread calls Mach semaphore_wait().
|
||||
*
|
||||
*
|
||||
* PTHREAD_MUTEX_NORMAL lacks deadlock detection and is the fastest
|
||||
* mutex type.
|
||||
*
|
||||
* Linux: No spinning. The internal name PTHREAD_MUTEX_TIMED_NP
|
||||
* remains from the times when pthread_mutex_timedlock() was
|
||||
* non-standard extension. Alias name: PTHREAD_MUTEX_FAST_NP.
|
||||
* FreeBSD: No spinning.
|
||||
*
|
||||
*
|
||||
* PTHREAD_MUTEX_ERRORCHECK is usually as fast as PTHREAD_MUTEX_NORMAL
|
||||
* yet has lightweight deadlock detection.
|
||||
*
|
||||
* Linux: No spinning. The internal name: PTHREAD_MUTEX_ERRORCHECK_NP.
|
||||
* FreeBSD: No spinning.
|
||||
*
|
||||
*
|
||||
* PTHREAD_MUTEX_RECURSIVE allows recursive locking.
|
||||
*
|
||||
* Linux: No spinning. The internal name: PTHREAD_MUTEX_RECURSIVE_NP.
|
||||
* FreeBSD: No spinning.
|
||||
*
|
||||
*
|
||||
* PTHREAD_MUTEX_ADAPTIVE_NP spins on SMP systems before sleeping.
|
||||
*
|
||||
* Linux: No deadlock detection. Dynamically changes a spin count
|
||||
* for each mutex from 10 to 100 based on spin count taken
|
||||
* previously.
|
||||
* FreeBSD: Deadlock detection. The default spin count is 2000.
|
||||
* It can be overriden using LIBPTHREAD_SPINLOOPS environment
|
||||
* variable or by pthread_mutex_setspinloops_np(). If a lock
|
||||
* is still busy, sched_yield() can be called on both UP and
|
||||
* SMP systems. The default yield loop count is zero, but
|
||||
* it can be set by LIBPTHREAD_YIELDLOOPS environment
|
||||
* variable or by pthread_mutex_setyieldloops_np().
|
||||
* Solaris: No PTHREAD_MUTEX_ADAPTIVE_NP.
|
||||
* MacOSX: No PTHREAD_MUTEX_ADAPTIVE_NP.
|
||||
*
|
||||
*
|
||||
* PTHREAD_MUTEX_ELISION_NP is a Linux extension to elide locks using
|
||||
* Intel Restricted Transactional Memory. It is the most suitable for
|
||||
* rwlock pattern access because it allows simultaneous reads without lock.
|
||||
* Supported since glibc 2.18.
|
||||
*
|
||||
*
|
||||
* PTHREAD_MUTEX_DEFAULT is default mutex type.
|
||||
*
|
||||
* Linux: PTHREAD_MUTEX_NORMAL.
|
||||
* FreeBSD: PTHREAD_MUTEX_ERRORCHECK.
|
||||
* Solaris: PTHREAD_MUTEX_NORMAL.
|
||||
* MacOSX: PTHREAD_MUTEX_NORMAL.
|
||||
*/
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_thread_mutex_create(ngx_thread_mutex_t *mtx, ngx_log_t *log)
|
||||
{
|
||||
ngx_err_t err;
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
err = pthread_mutexattr_init(&attr);
|
||||
if (err != 0) {
|
||||
ngx_log_error(NGX_LOG_EMERG, log, err,
|
||||
"pthread_mutexattr_init() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
if (err != 0) {
|
||||
ngx_log_error(NGX_LOG_EMERG, log, err,
|
||||
"pthread_mutexattr_settype"
|
||||
"(PTHREAD_MUTEX_ERRORCHECK) failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
err = pthread_mutex_init(mtx, &attr);
|
||||
if (err != 0) {
|
||||
ngx_log_error(NGX_LOG_EMERG, log, err,
|
||||
"pthread_mutex_init() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
err = pthread_mutexattr_destroy(&attr);
|
||||
if (err != 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"pthread_mutexattr_destroy() failed");
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
|
||||
"pthread_mutex_init(%p)", mtx);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_thread_mutex_destroy(ngx_thread_mutex_t *mtx, ngx_log_t *log)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
err = pthread_mutex_destroy(mtx);
|
||||
if (err != 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err,
|
||||
"pthread_mutex_destroy() failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
|
||||
"pthread_mutex_destroy(%p)", mtx);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_thread_mutex_lock(ngx_thread_mutex_t *mtx, ngx_log_t *log)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
|
||||
"pthread_mutex_lock(%p) enter", mtx);
|
||||
|
||||
err = pthread_mutex_lock(mtx);
|
||||
if (err == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_mutex_lock() failed");
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_thread_mutex_unlock(ngx_thread_mutex_t *mtx, ngx_log_t *log)
|
||||
{
|
||||
ngx_err_t err;
|
||||
|
||||
err = pthread_mutex_unlock(mtx);
|
||||
|
||||
#if 0
|
||||
ngx_time_update();
|
||||
#endif
|
||||
|
||||
if (err == 0) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
|
||||
"pthread_mutex_unlock(%p) exit", mtx);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, log, err, "pthread_mutex_unlock() failed");
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -0,0 +1,115 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#if (NGX_HAVE_KQUEUE)
|
||||
|
||||
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 %d of %d", c->fd, n, size);
|
||||
|
||||
if (n >= 0) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#else /* ! NGX_HAVE_KQUEUE */
|
||||
|
||||
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 %d of %d", c->fd, n, size);
|
||||
|
||||
if (n >= 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;
|
||||
}
|
||||
|
||||
#endif /* NGX_HAVE_KQUEUE */
|
||||
@@ -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 */
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user