POSIX semaphores patch
Igor Sysoev
igor at sysoev.ru
Wed May 4 15:08:17 MSD 2011
The attache patch enables POSIX semaphores usage during shared memory access.
It should decrease CPU usage on start-up or online upgrade of installations
with large caches or large number of workers.
I tested the patch on FreeBSD 8.2. There is no sense to test it on
FreeBSD prior to 7.2 version, since semaphores does not work on these systems.
You can ensure that there are enough semaphores:
sysctl p1003_1b.sem_nsems_max
By default there should be 32 semaphores. On 8.2+ you can increase them
dynamically. You need one semaphores per shared zone.
"sysctl p1003_1b.nsems" shows current number of semaphores.
It would be intresting to test the patch on other platforms - Linux
and Solaris. Please draw attention to alerts in error_log.
Note also that nginx does not destroy semaphores on exit. They should
deleted by kernel automatically. Please check that there is no
semaphore leakage while nginx work.
--
Igor Sysoev
-------------- next part --------------
Index: src/event/ngx_event.c
===================================================================
--- src/event/ngx_event.c (revision 3907)
+++ src/event/ngx_event.c (working copy)
@@ -519,6 +519,7 @@
shared = shm.addr;
ngx_accept_mutex_ptr = (ngx_atomic_t *) shared;
+ ngx_accept_mutex.spin = (ngx_uint_t) -1;
if (ngx_shmtx_create(&ngx_accept_mutex, shared, cycle->lock_file.data)
!= NGX_OK)
Index: src/os/unix/ngx_posix_config.h
===================================================================
--- src/os/unix/ngx_posix_config.h (revision 3907)
+++ src/os/unix/ngx_posix_config.h (working copy)
@@ -96,6 +96,11 @@
#include <ngx_auto_config.h>
+#if (NGX_HAVE_POSIX_SEM)
+#include <semaphore.h>
+#endif
+
+
#if (NGX_HAVE_POLL)
#include <poll.h>
#endif
Index: src/os/unix/ngx_linux_config.h
===================================================================
--- src/os/unix/ngx_linux_config.h (revision 3907)
+++ src/os/unix/ngx_linux_config.h (working copy)
@@ -58,6 +58,11 @@
#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
Index: src/os/unix/ngx_freebsd_config.h
===================================================================
--- src/os/unix/ngx_freebsd_config.h (revision 3907)
+++ src/os/unix/ngx_freebsd_config.h (working copy)
@@ -68,6 +68,11 @@
#include <ngx_auto_config.h>
+#if (NGX_HAVE_POSIX_SEM)
+#include <semaphore.h>
+#endif
+
+
#if (NGX_HAVE_POLL)
#include <poll.h>
#endif
Index: src/os/unix/ngx_solaris_config.h
===================================================================
--- src/os/unix/ngx_solaris_config.h (revision 3907)
+++ src/os/unix/ngx_solaris_config.h (working copy)
@@ -57,6 +57,11 @@
#include <ngx_auto_config.h>
+#if (NGX_HAVE_POSIX_SEM)
+#include <semaphore.h>
+#endif
+
+
#if (NGX_HAVE_POLL)
#include <poll.h>
#endif
Index: src/os/unix/ngx_darwin_config.h
===================================================================
--- src/os/unix/ngx_darwin_config.h (revision 3907)
+++ src/os/unix/ngx_darwin_config.h (working copy)
@@ -56,6 +56,11 @@
#include <ngx_auto_config.h>
+#if (NGX_HAVE_POSIX_SEM)
+#include <semaphore.h>
+#endif
+
+
#if (NGX_HAVE_POLL)
#include <poll.h>
#endif
Index: src/core/ngx_shmtx.c
===================================================================
--- src/core/ngx_shmtx.c (revision 3907)
+++ src/core/ngx_shmtx.c (working copy)
@@ -16,9 +16,160 @@
{
mtx->lock = addr;
+ if (mtx->spin == (ngx_uint_t) -1) {
+ return NGX_OK;
+ }
+
+ mtx->spin = 2048;
+
+#if (NGX_HAVE_POSIX_SEM)
+
+ if (sem_init(&mtx->sem, 1, 0) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
+ "sem_init() failed");
+ } else {
+ mtx->semaphore = 1;
+ }
+
+#endif
+
return NGX_OK;
}
+
+void
+ngx_shmtx_destory(ngx_shmtx_t *mtx)
+{
+#if (NGX_HAVE_POSIX_SEM)
+
+ if (mtx->semaphore) {
+ if (sem_destroy(&mtx->sem) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
+ "sem_destroy() failed");
+ }
+ }
+
+#endif
+}
+
+
+ngx_uint_t
+ngx_shmtx_trylock(ngx_shmtx_t *mtx)
+{
+ ngx_atomic_uint_t val;
+
+ val = *mtx->lock;
+
+ return ((val & 0x80000000) == 0
+ && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000));
+}
+
+
+void
+ngx_shmtx_lock(ngx_shmtx_t *mtx)
+{
+ ngx_uint_t i, n;
+ ngx_atomic_uint_t val;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx lock");
+
+ for ( ;; ) {
+
+ val = *mtx->lock;
+
+ if ((val & 0x80000000) == 0
+ && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000))
+ {
+ return;
+ }
+
+ if (ngx_ncpu > 1) {
+
+ for (n = 1; n < mtx->spin; n <<= 1) {
+
+ for (i = 0; i < n; i++) {
+ ngx_cpu_pause();
+ }
+
+ val = *mtx->lock;
+
+ if ((val & 0x80000000) == 0
+ && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000))
+ {
+ return;
+ }
+ }
+ }
+
+#if (NGX_HAVE_POSIX_SEM)
+
+ if (mtx->semaphore) {
+ val = *mtx->lock;
+
+ if ((val & 0x80000000)
+ && ngx_atomic_cmp_set(mtx->lock, val, val + 1))
+ {
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "shmtx wait %XA", val);
+
+ if (sem_wait(&mtx->sem) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
+ "sem_wait() failed while waiting on shmtx");
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "shmtx awoke");
+
+ continue;
+ }
+ }
+
+#endif
+
+ ngx_sched_yield();
+ }
+}
+
+
+void
+ngx_shmtx_unlock(ngx_shmtx_t *mtx)
+{
+ ngx_atomic_uint_t val, old, wait;
+
+ if (mtx->spin != (ngx_uint_t) -1) {
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx unlock");
+ }
+
+ for ( ;; ) {
+
+ old = *mtx->lock;
+ wait = old & 0x7fffffff;
+ val = wait ? wait - 1 : 0;
+
+ if (ngx_atomic_cmp_set(mtx->lock, old, val)) {
+ break;
+ }
+ }
+
+#if (NGX_HAVE_POSIX_SEM)
+ {
+
+ if (wait == 0 || !mtx->semaphore) {
+ return;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "shmtx wake %XA", old);
+
+ if (sem_post(&mtx->sem) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
+ "sem_post() failed while wake shmtx");
+ }
+ }
+#endif
+}
+
+
#else
@@ -65,4 +216,62 @@
}
+ngx_uint_t
+ngx_shmtx_trylock(ngx_shmtx_t *mtx)
+{
+ ngx_err_t err;
+
+ err = ngx_trylock_fd(mtx->fd);
+
+ if (err == 0) {
+ return 1;
+ }
+
+ if (err == NGX_EAGAIN) {
+ return 0;
+ }
+
+#if __osf__ /* Tru64 UNIX */
+
+ if (err == NGX_EACCESS) {
+ return 0;
+ }
+
#endif
+
+ ngx_log_abort(err, ngx_trylock_fd_n " %s failed", mtx->name);
+
+ return 0;
+}
+
+
+void
+ngx_shmtx_lock(ngx_shmtx_t *mtx)
+{
+ ngx_err_t err;
+
+ err = ngx_lock_fd(mtx->fd);
+
+ if (err == 0) {
+ return;
+ }
+
+ ngx_log_abort(err, ngx_lock_fd_n " %s failed", mtx->name);
+}
+
+
+void
+ngx_shmtx_unlock(ngx_shmtx_t *mtx)
+{
+ ngx_err_t err;
+
+ err = ngx_unlock_fd(mtx->fd);
+
+ if (err == 0) {
+ return;
+ }
+
+ ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name);
+}
+
+#endif
Index: src/core/ngx_shmtx.h
===================================================================
--- src/core/ngx_shmtx.h (revision 3907)
+++ src/core/ngx_shmtx.h (working copy)
@@ -15,95 +15,23 @@
typedef struct {
#if (NGX_HAVE_ATOMIC_OPS)
ngx_atomic_t *lock;
+#if (NGX_HAVE_POSIX_SEM)
+ ngx_uint_t semaphore;
+ sem_t sem;
+#endif
#else
ngx_fd_t fd;
u_char *name;
#endif
+ ngx_uint_t spin;
} ngx_shmtx_t;
ngx_int_t ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name);
-
-
-#if (NGX_HAVE_ATOMIC_OPS)
-
-static ngx_inline ngx_uint_t
-ngx_shmtx_trylock(ngx_shmtx_t *mtx)
-{
- return (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid));
-}
-
-#define ngx_shmtx_lock(mtx) ngx_spinlock((mtx)->lock, ngx_pid, 1024)
-
-#define ngx_shmtx_unlock(mtx) (void) ngx_atomic_cmp_set((mtx)->lock, ngx_pid, 0)
-
-#define ngx_shmtx_destory(mtx)
-
-
-#else
-
-static ngx_inline ngx_uint_t
-ngx_shmtx_trylock(ngx_shmtx_t *mtx)
-{
- ngx_err_t err;
-
- err = ngx_trylock_fd(mtx->fd);
-
- if (err == 0) {
- return 1;
- }
-
- if (err == NGX_EAGAIN) {
- return 0;
- }
-
-#if __osf__ /* Tru64 UNIX */
-
- if (err == NGX_EACCESS) {
- return 0;
- }
-
-#endif
-
- ngx_log_abort(err, ngx_trylock_fd_n " %s failed", mtx->name);
-
- return 0;
-}
-
-
-static ngx_inline void
-ngx_shmtx_lock(ngx_shmtx_t *mtx)
-{
- ngx_err_t err;
-
- err = ngx_lock_fd(mtx->fd);
-
- if (err == 0) {
- return;
- }
-
- ngx_log_abort(err, ngx_lock_fd_n " %s failed", mtx->name);
-}
-
-
-static ngx_inline void
-ngx_shmtx_unlock(ngx_shmtx_t *mtx)
-{
- ngx_err_t err;
-
- err = ngx_unlock_fd(mtx->fd);
-
- if (err == 0) {
- return;
- }
-
- ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name);
-}
-
-
void ngx_shmtx_destory(ngx_shmtx_t *mtx);
+ngx_uint_t ngx_shmtx_trylock(ngx_shmtx_t *mtx);
+void ngx_shmtx_lock(ngx_shmtx_t *mtx);
+void ngx_shmtx_unlock(ngx_shmtx_t *mtx);
-#endif
-
#endif /* _NGX_SHMTX_H_INCLUDED_ */
Index: auto/os/freebsd
===================================================================
--- auto/os/freebsd (revision 3907)
+++ auto/os/freebsd (working copy)
@@ -49,7 +49,16 @@
have=NGX_HAVE_AIO_SENDFILE . auto/have
fi
+# POSIX semaphores
+# http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/127545
+if [ $osreldate -ge 701106 ]; then
+ echo " + POSIX semaphores should work"
+else
+ have=NGX_HAVE_POSIX_SEM . auto/nohave
+fi
+
+
# kqueue
if [ \( $osreldate -lt 500000 -a $osreldate -ge 410000 \) \
Index: auto/unix
===================================================================
--- auto/unix (revision 3907)
+++ auto/unix (working copy)
@@ -234,6 +234,18 @@
. auto/feature
+ngx_feature="POSIX semaphores"
+ngx_feature_name="NGX_HAVE_POSIX_SEM"
+ngx_feature_run=yes
+ngx_feature_incs="#include <semaphore.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="sem_t sem;
+ if (sem_init(&sem, 1, 0) == -1) return 1;
+ sem_destroy(&sem);"
+. auto/feature
+
+
ngx_feature="struct msghdr.msg_control"
ngx_feature_name="NGX_HAVE_MSGHDR_MSG_CONTROL"
ngx_feature_run=no
More information about the nginx
mailing list