diff options
Diffstat (limited to 'src/os/unix')
-rw-r--r-- | src/os/unix/ngx_atomic.h | 384 | ||||
-rw-r--r-- | src/os/unix/ngx_channel.c | 20 | ||||
-rw-r--r-- | src/os/unix/ngx_files.c | 79 | ||||
-rw-r--r-- | src/os/unix/ngx_gcc_atomic_amd64.h | 74 | ||||
-rw-r--r-- | src/os/unix/ngx_gcc_atomic_ppc.h | 66 | ||||
-rw-r--r-- | src/os/unix/ngx_gcc_atomic_sparc64.h | 69 | ||||
-rw-r--r-- | src/os/unix/ngx_gcc_atomic_x86.h | 103 | ||||
-rw-r--r-- | src/os/unix/ngx_readv_chain.c | 2 | ||||
-rw-r--r-- | src/os/unix/ngx_sunpro_amd64.il | 30 | ||||
-rw-r--r-- | src/os/unix/ngx_sunpro_atomic_sparc64.h | 52 | ||||
-rw-r--r-- | src/os/unix/ngx_sunpro_sparc64.il | 35 | ||||
-rw-r--r-- | src/os/unix/ngx_sunpro_x86.il | 31 | ||||
-rw-r--r-- | src/os/unix/ngx_time.h | 39 | ||||
-rw-r--r-- | src/os/unix/ngx_writev_chain.c | 2 |
14 files changed, 631 insertions, 355 deletions
diff --git a/src/os/unix/ngx_atomic.h b/src/os/unix/ngx_atomic.h index b3d300314..5856103c6 100644 --- a/src/os/unix/ngx_atomic.h +++ b/src/os/unix/ngx_atomic.h @@ -14,275 +14,99 @@ #if ( __i386__ || __i386 ) -#define NGX_HAVE_ATOMIC_OPS 1 - -typedef int32_t ngx_atomic_int_t; -typedef uint32_t ngx_atomic_uint_t; +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 (NGX_SMP) -#define NGX_SMP_LOCK "lock;" -#else -#define NGX_SMP_LOCK -#endif - -/* - * the "=q" is any of the %eax, %ebx, %ecx, or %edx registers. - * the '"0" (1)' parameter preloads 1 into %0. - * the "cc" means that flags were changed. - * - * "xadd r, [m]": - * - * temp = [m]; - * [m] += r; - * r = temp; - */ - -static ngx_inline ngx_atomic_uint_t -ngx_atomic_inc(ngx_atomic_t *value) -{ - ngx_atomic_uint_t old; - - __asm__ volatile ( - - NGX_SMP_LOCK - " xaddl %0, %2; " - " incl %0; " - - : "=q" (old) : "0" (1), "m" (*value) : "cc", "memory"); - - return old; -} - - -static ngx_inline ngx_atomic_uint_t -ngx_atomic_dec(ngx_atomic_t *value) -{ - ngx_atomic_uint_t old; - - __asm__ volatile ( - - NGX_SMP_LOCK - " xaddl %0, %2; " - " decl %0; " - - : "=q" (old) : "0" (-1), "m" (*value) : "cc", "memory"); +#define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 - return old; -} +#if ( __SUNPRO_C ) -/* - * the "q" is any of the %eax, %ebx, %ecx, or %edx registers. - * the "=a" and "a" are the %eax register. Although we can return result - * in any register, we use %eax because it is used in cmpxchg anyway. - * - * "cmpxchg r, [m]": - * - * if (eax == [m]) { - * zf = 1; - * [m] = r; - * } else { - * zf = 0; - * eax = [m]; - * } - */ +#define NGX_HAVE_ATOMIC_OPS 1 -static ngx_inline ngx_atomic_uint_t +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; + ngx_atomic_uint_t set); - __asm__ volatile ( +ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add); - NGX_SMP_LOCK - " cmpxchgl %3, %1; " - " setz %b0; " - " movzbl %b0, %0; " +/* the code in src/os/unix/ngx_sunpro_x86.il */ - : "=a" (res) : "m" (*lock), "a" (old), "q" (set) : "cc", "memory"); - - return res; -} - -#elif ( __amd64__ || __amd64 ) +#else /* ( __GNUC__ || __INTEL_COMPILER ) */ #define NGX_HAVE_ATOMIC_OPS 1 -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 - +#include "ngx_gcc_atomic_x86.h" -#if (NGX_SMP) -#define NGX_SMP_LOCK "lock;" -#else -#define NGX_SMP_LOCK #endif -static ngx_inline ngx_atomic_uint_t -ngx_atomic_inc(ngx_atomic_t *value) -{ - ngx_atomic_uint_t old; - - __asm__ volatile ( - - NGX_SMP_LOCK - " xaddq %0, %2; " - " incq %0; " - - : "=r" (old) : "0" (1), "m" (*value) : "cc", "memory"); - - return old; -} - - -/* the '"0" (-1LL)' parameter preloads -1 into the 64-bit %0 register */ - -static ngx_inline ngx_atomic_uint_t -ngx_atomic_dec(ngx_atomic_t *value) -{ - ngx_atomic_uint_t old; - - __asm__ volatile ( - - NGX_SMP_LOCK - " xaddq %0, %2; " - " decq %0; " +#elif ( __amd64__ || __amd64 ) - : "=r" (old) : "0" (-1LL), "m" (*value) : "cc", "memory"); +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 - return old; -} +#if ( __SUNPRO_C ) -/* the "=a" and "a" are the %rax register. */ +#define NGX_HAVE_ATOMIC_OPS 1 -static ngx_inline ngx_atomic_uint_t +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; - - __asm__ volatile ( + ngx_atomic_uint_t set); - NGX_SMP_LOCK - " cmpxchgq %3, %1; " - " setz %b0; " - " movzbq %b0, %0; " +ngx_atomic_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add); - : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory"); +/* the code in src/os/unix/ngx_sunpro_amd64.il */ - return res; -} - -#elif ( __sparc__ || __sparcv9 ) +#else /* ( __GNUC__ || __INTEL_COMPILER ) */ #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_CASXA "casxa" -#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_CASXA "casa" -#endif - -typedef volatile ngx_atomic_uint_t ngx_atomic_t; - - -/* - * the "+r" means the general register used for both input and output. - * - * "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 successfull. - */ - -static ngx_inline ngx_atomic_uint_t -ngx_atomic_inc(ngx_atomic_t *value) -{ - ngx_atomic_uint_t old, new, res; - - old = *value; - - for ( ;; ) { +#include "ngx_gcc_atomic_amd64.h" - new = old + 1; - res = new; - - __asm__ volatile ( - - NGX_CASXA " [%1] 0x80, %2, %0" - - : "+r" (res) : "r" (value), "r" (old) : "memory"); +#endif - if (res == old) { - return new; - } - old = res; - } -} +#elif ( __sparc__ || __sparcv9 ) +#if (NGX_PTR_SIZE == 8) -static ngx_inline ngx_atomic_uint_t -ngx_atomic_dec(ngx_atomic_t *value) -{ - ngx_atomic_uint_t old, new, res; +typedef int64_t ngx_atomic_int_t; +typedef uint64_t ngx_atomic_uint_t; +#define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 - old = *value; +#else - for ( ;; ) { +typedef int32_t ngx_atomic_int_t; +typedef uint32_t ngx_atomic_uint_t; +#define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 - new = old - 1; - res = new; +#endif - __asm__ volatile ( +typedef volatile ngx_atomic_uint_t ngx_atomic_t; - NGX_CASXA " [%1] 0x80, %2, %0" - : "+r" (res) : "r" (value), "r" (old) : "memory"); +#if ( __SUNPRO_C ) - if (res == old) { - return new; - } +#define NGX_HAVE_ATOMIC_OPS 1 - old = res; - } -} +#include "ngx_sunpro_atomic_sparc64.h" -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 ( +#else /* ( __GNUC__ || __INTEL_COMPILER ) */ - NGX_CASXA " [%1] 0x80, %2, %0" +#define NGX_HAVE_ATOMIC_OPS 1 - : "+r" (set) : "r" (lock), "r" (old) : "memory"); +#include "ngx_gcc_atomic_sparc64.h" - return (set == old); -} +#endif #elif ( __ppc__ || __powerpc__ ) @@ -290,116 +114,60 @@ ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, #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; +typedef int64_t ngx_atomic_int_t; +typedef uint64_t ngx_atomic_uint_t; +#define NGX_ATOMIC_T_LEN sizeof("-9223372036854775808") - 1 -/* - * 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 "=&r" means that no input registers can be used. - * 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 "1b" means the nearest backward label "1" and the "1f" means - * the nearest forward label "1". - */ +#else -static ngx_inline ngx_atomic_uint_t -ngx_atomic_inc(ngx_atomic_t *value) -{ - ngx_atomic_uint_t res; +typedef int32_t ngx_atomic_int_t; +typedef uint32_t ngx_atomic_uint_t; +#define NGX_ATOMIC_T_LEN sizeof("-2147483648") - 1 - __asm__ volatile ( +#endif - "1: lwarx %0, 0, %1 \n" /* load from [value] into "res" */ - /* and store reservation */ - " addi %0, %0, 1 \n" /* add "1" to "res" */ - " stwcx. %0, 0, %1 \n" /* store "res" into [value] if reservation */ - /* is not cleared */ - " bne- 1b \n" /* try again if reservation was cleared */ +typedef volatile ngx_atomic_uint_t ngx_atomic_t; - : "=&b" (res) : "r" (value) : "cc", "memory"); - return res; -} +#include "ngx_gcc_atomic_ppc.h" -static ngx_inline ngx_atomic_uint_t -ngx_atomic_dec(ngx_atomic_t *value) -{ - ngx_atomic_uint_t res; +#endif - __asm__ volatile ( - "1: lwarx %0, 0, %1 \n" /* load from [value] into "res" */ - /* and store reservation */ - " addi %0, %0, -1 \n" /* sub "1" from "res" */ - " stwcx. %0, 0, %1 \n" /* store "res" into [value] if reservation */ - /* is not cleared */ - " bne- 1b \n" /* try again if reservation was cleared */ +#if !(NGX_HAVE_ATOMIC_OPS) - : "=&b" (res) : "r" (value) : "cc", "memory"); +#define NGX_HAVE_ATOMIC_OPS 0 - return res; -} +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) + ngx_atomic_uint_t set) { - ngx_atomic_uint_t res, temp; - - __asm__ volatile ( - - " li %0, 0 \n" /* preset "0" to "res" */ - " lwarx %1, 0, %2 \n" /* load from [lock] into "temp" */ - /* and store reservation */ - " cmpw %1, %3 \n" /* compare "temp" and "old" */ - " bne- 1f \n" /* not equal */ - " stwcx. %4, 0, %2 \n" /* store "set" into [lock] if reservation */ - /* is not cleared */ - " bne- 1f \n" /* the reservation was cleared */ - " li %0, 1 \n" /* set "1" to "res" */ - "1: \n" - - : "=&r" (res), "=&r" (temp) - : "r" (lock), "r" (old), "r" (set) - : "cc", "memory"); - - return res; -} + if (*lock == old { + *lock = set; + return 1; + } + return 0; +} -#else -#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_int_t +ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add) +{ + ngx_atomic_int_t old; -#define ngx_atomic_inc(x) ++(*(x)) -#define ngx_atomic_dec(x) --(*(x)) + old = *value; + *value += add; -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) -{ - *lock = set; - return 1; + return old; } #endif diff --git a/src/os/unix/ngx_channel.c b/src/os/unix/ngx_channel.c index 01a0514b5..051f466fd 100644 --- a/src/os/unix/ngx_channel.c +++ b/src/os/unix/ngx_channel.c @@ -192,30 +192,14 @@ ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, ngx_int_t event, return NGX_ERROR; } - rev = c->read; - wev = c->write; - - ngx_memzero(c, sizeof(ngx_connection_t)); - - c->read = rev; - c->write = wev; - c->fd = fd; - c->log = cycle->log; - c->pool = cycle->pool; - ngx_memzero(rev, sizeof(ngx_event_t)); - ngx_memzero(wev, sizeof(ngx_event_t)); + rev = c->read; + wev = c->write; rev->log = cycle->log; wev->log = cycle->log; - rev->index = NGX_INVALID_INDEX; - wev->index = NGX_INVALID_INDEX; - - rev->data = c; - wev->data = c; - #if (NGX_THREADS) rev->lock = &c->lock; wev->lock = &c->lock; diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c index f8f98c7fe..67cad1a69 100644 --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -8,9 +8,10 @@ #include <ngx_core.h> -ssize_t ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) +ssize_t +ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) { - ssize_t n; + ssize_t n; ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, "read: %d, %p, %uz, %O", file->fd, buf, size, offset); @@ -53,9 +54,10 @@ ssize_t ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) } -ssize_t ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) +ssize_t +ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) { - ssize_t n; + ssize_t n; ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, "write: %d, %p, %uz, %O", file->fd, buf, size, offset); @@ -109,7 +111,8 @@ ssize_t ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset) } -ngx_fd_t ngx_open_tempfile(u_char *name, ngx_uint_t persistent) +ngx_fd_t +ngx_open_tempfile(u_char *name, ngx_uint_t persistent) { ngx_fd_t fd; @@ -125,8 +128,9 @@ ngx_fd_t ngx_open_tempfile(u_char *name, ngx_uint_t persistent) #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) +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; @@ -216,7 +220,8 @@ ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, } -ngx_int_t ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir) +ngx_int_t +ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir) { dir->dir = opendir((const char *) name->data); @@ -228,3 +233,61 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir) return NGX_OK; } + + +ngx_int_t +ngx_lock_file(ngx_file_t *file) +{ + ngx_err_t err; + struct flock fl; + + fl.l_whence = SEEK_SET; + fl.l_len = 0; + fl.l_pid = 0; + fl.l_type = F_WRLCK; + fl.l_start = 0; + + if (fcntl(file->fd, F_SETLK, &fl) == -1) { + err = ngx_errno; + + if (err == NGX_EAGAIN) { + return NGX_BUSY; + } + + ngx_log_error(NGX_LOG_ALERT, file->log, err, + "fcntl(%s, F_SETLK, F_WRLCK) failed", file->name.data); + + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_unlock_file(ngx_file_t *file) +{ + ngx_err_t err; + struct flock fl; + + fl.l_whence = SEEK_SET; + fl.l_len = 0; + fl.l_pid = 0; + fl.l_type = F_UNLCK; + fl.l_start = 0; + + if (fcntl(file->fd, F_SETLK, &fl) == -1) { + err = ngx_errno; + + if (err == NGX_EAGAIN) { + return NGX_BUSY; + } + + ngx_log_error(NGX_LOG_ALERT, file->log, err, + "fcntl(%s, F_SETLK, F_UNLCK) failed", file->name.data); + + return NGX_ERROR; + } + + return NGX_OK; +} diff --git a/src/os/unix/ngx_gcc_atomic_amd64.h b/src/os/unix/ngx_gcc_atomic_amd64.h new file mode 100644 index 000000000..07b2d50b5 --- /dev/null +++ b/src/os/unix/ngx_gcc_atomic_amd64.h @@ -0,0 +1,74 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#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 %rax because it is used in cmpxchgq anyway. + * 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) +{ + ngx_atomic_uint_t res; + + __asm__ volatile ( + + NGX_SMP_LOCK + " cmpxchgq %3, %1; " + " setz %b0; " + " movzbq %b0, %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; " + + : "+q" (add) : "m" (*value) : "cc", "memory"); + + return add; +} diff --git a/src/os/unix/ngx_gcc_atomic_ppc.h b/src/os/unix/ngx_gcc_atomic_ppc.h new file mode 100644 index 000000000..8fc3bc041 --- /dev/null +++ b/src/os/unix/ngx_gcc_atomic_ppc.h @@ -0,0 +1,66 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +/* + * 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. + */ + +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" */ + " lwarx %1, 0, %2 \n" /* load from [lock] into "temp" */ + /* and store reservation */ + " cmpw %1, %3 \n" /* compare "temp" and "old" */ + " bne- 1f \n" /* not equal */ + " stwcx. %4, 0, %2 \n" /* store "set" into [lock] if reservation */ + /* is not cleared */ + " bne- 1f \n" /* the reservation was cleared */ + " li %0, 1 \n" /* set "1" to "res" */ + "1: \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 ( + + "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 */ + + : "=&b" (res), "=&b" (temp) + : "b" (value), "b" (add) + : "cc", "memory"); + + return res; +} diff --git a/src/os/unix/ngx_gcc_atomic_sparc64.h b/src/os/unix/ngx_gcc_atomic_sparc64.h new file mode 100644 index 000000000..c7022a930 --- /dev/null +++ b/src/os/unix/ngx_gcc_atomic_sparc64.h @@ -0,0 +1,69 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +/* + * "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 successfull. + * + * + * 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; + } +} diff --git a/src/os/unix/ngx_gcc_atomic_x86.h b/src/os/unix/ngx_gcc_atomic_x86.h new file mode 100644 index 000000000..e3c0c9379 --- /dev/null +++ b/src/os/unix/ngx_gcc_atomic_x86.h @@ -0,0 +1,103 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#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 "q" is any of the %eax, %ebx, %ecx, or %edx registers. + * The "=a" and "a" are the %eax register. Although we can return result + * in any register, we use %eax because it is used in cmpxchgl anyway. + * 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) +{ + ngx_atomic_uint_t res; + + __asm__ volatile ( + + NGX_SMP_LOCK + " cmpxchgl %3, %1; " + " setz %b0; " + " movzbl %b0, %0; " + + : "=a" (res) : "m" (*lock), "a" (old), "q" (set) : "cc", "memory"); + + return res; +} + + +/* + * "xaddl r, [m]": + * + * temp = [m]; + * [m] += r; + * r = temp; + * + * + * The "+q" is any of the %eax, %ebx, %ecx, or %edx registers. + * The "cc" means that flags were changed. + */ + + +#if !(__GNUC__ == 2 && __GNUC_MINOR__ <= 7) + +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; " + + : "+q" (add) : "m" (*value) : "cc", "memory"); + + return add; +} + + +#else /* (__GNUC__ == 2 && __GNUC_MINOR__ <= 7) */ + +/* + * gcc 2.7 does not support "+q", 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 diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c index 47d8f3b7c..08b5cc033 100644 --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -182,7 +182,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) return NGX_ERROR; } - iov->iov_base = chain->buf->last; + iov->iov_base = (void *) chain->buf->last; iov->iov_len = chain->buf->end - chain->buf->last; } diff --git a/src/os/unix/ngx_sunpro_amd64.il b/src/os/unix/ngx_sunpro_amd64.il new file mode 100644 index 000000000..0cd94b023 --- /dev/null +++ b/src/os/unix/ngx_sunpro_amd64.il @@ -0,0 +1,30 @@ +/ +/ Copyright (C) Igor Sysoev +/ + +/ 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 diff --git a/src/os/unix/ngx_sunpro_atomic_sparc64.h b/src/os/unix/ngx_sunpro_atomic_sparc64.h new file mode 100644 index 000000000..e634416ab --- /dev/null +++ b/src/os/unix/ngx_sunpro_atomic_sparc64.h @@ -0,0 +1,52 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#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) +{ + 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; + + NGX_CASA(res, old, value); + + if (res == old) { + return res; + } + + old = res; + } +} diff --git a/src/os/unix/ngx_sunpro_sparc64.il b/src/os/unix/ngx_sunpro_sparc64.il new file mode 100644 index 000000000..d2708ed9d --- /dev/null +++ b/src/os/unix/ngx_sunpro_sparc64.il @@ -0,0 +1,35 @@ +/ +/ Copyright (C) Igor Sysoev +/ + + +/ "casa [%o2] 0x80, %o1, %o0" and +/ "casxa [%o2] 0x80, %o1, %o0" do the following: +/ +/ if ([%o2] == %o1) { +/ swap(%o0, [%o2]); +/ } else { +/ %o0 = [%o2]; +/ } + + +/ ngx_atomic_uint_t ngx_casa(ngx_atomic_uint_t set, ngx_atomic_uint_t old, +/ ngx_atomic_t *lock); +/ +/ the arguments are passed in the %o0, %o1, %o2 +/ the result is returned in the %o0 + + .inline ngx_casa,0 + casa [%o2] 0x80, %o1, %o0 + .end + + +/ ngx_atomic_uint_t ngx_casxa(ngx_atomic_uint_t set, ngx_atomic_uint_t old, +/ ngx_atomic_t *lock); +/ +/ the arguments are passed in the %o0, %o1, %o2 +/ the result is returned in the %o0 + + .inline ngx_casxa,0 + casxa [%o2] 0x80, %o1, %o0 + .end diff --git a/src/os/unix/ngx_sunpro_x86.il b/src/os/unix/ngx_sunpro_x86.il new file mode 100644 index 000000000..a16568ac8 --- /dev/null +++ b/src/os/unix/ngx_sunpro_x86.il @@ -0,0 +1,31 @@ +/ +/ Copyright (C) Igor Sysoev +/ + +/ 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 the 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 the stack (%esp), 4(%esp) + + .inline ngx_atomic_fetch_add,0 + movl (%esp), %ecx + movl 4(%esp), %eax + lock + xaddl %eax, (%ecx) + .end diff --git a/src/os/unix/ngx_time.h b/src/os/unix/ngx_time.h index 63a0ad9f7..f9fe3c52f 100644 --- a/src/os/unix/ngx_time.h +++ b/src/os/unix/ngx_time.h @@ -12,31 +12,32 @@ #include <ngx_core.h> -typedef ngx_rbtree_key_t ngx_msec_t; +typedef ngx_rbtree_key_t ngx_msec_t; +typedef ngx_rbtree_key_int_t ngx_msec_int_t; -typedef struct tm ngx_tm_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 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 +#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 +#define ngx_tm_gmtoff tm_gmtoff +#define ngx_tm_zone tm_zone #endif diff --git a/src/os/unix/ngx_writev_chain.c b/src/os/unix/ngx_writev_chain.c index 9baeb1f3c..f95c2cad8 100644 --- a/src/os/unix/ngx_writev_chain.c +++ b/src/os/unix/ngx_writev_chain.c @@ -81,7 +81,7 @@ ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) size = cl->buf->last - cl->buf->pos; if (send + size > limit) { - size = (ssize_t) limit - send; + size = (ssize_t) (limit - send); } if (prev == cl->buf->pos) { |