aboutsummaryrefslogtreecommitdiff
path: root/src/os/unix
diff options
context:
space:
mode:
Diffstat (limited to 'src/os/unix')
-rw-r--r--src/os/unix/ngx_atomic.h384
-rw-r--r--src/os/unix/ngx_channel.c20
-rw-r--r--src/os/unix/ngx_files.c79
-rw-r--r--src/os/unix/ngx_gcc_atomic_amd64.h74
-rw-r--r--src/os/unix/ngx_gcc_atomic_ppc.h66
-rw-r--r--src/os/unix/ngx_gcc_atomic_sparc64.h69
-rw-r--r--src/os/unix/ngx_gcc_atomic_x86.h103
-rw-r--r--src/os/unix/ngx_readv_chain.c2
-rw-r--r--src/os/unix/ngx_sunpro_amd64.il30
-rw-r--r--src/os/unix/ngx_sunpro_atomic_sparc64.h52
-rw-r--r--src/os/unix/ngx_sunpro_sparc64.il35
-rw-r--r--src/os/unix/ngx_sunpro_x86.il31
-rw-r--r--src/os/unix/ngx_time.h39
-rw-r--r--src/os/unix/ngx_writev_chain.c2
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) {