src/core/ngx_shmtx.c - nginx-1.7.10

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>


  7. #if (NGX_HAVE_ATOMIC_OPS)


  8. static void ngx_shmtx_wakeup(ngx_shmtx_t *mtx);


  9. ngx_int_t
  10. ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
  11. {
  12.     mtx->lock = &addr->lock;

  13.     if (mtx->spin == (ngx_uint_t) -1) {
  14.         return NGX_OK;
  15.     }

  16.     mtx->spin = 2048;

  17. #if (NGX_HAVE_POSIX_SEM)

  18.     mtx->wait = &addr->wait;

  19.     if (sem_init(&mtx->sem, 1, 0) == -1) {
  20.         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
  21.                       "sem_init() failed");
  22.     } else {
  23.         mtx->semaphore = 1;
  24.     }

  25. #endif

  26.     return NGX_OK;
  27. }


  28. void
  29. ngx_shmtx_destroy(ngx_shmtx_t *mtx)
  30. {
  31. #if (NGX_HAVE_POSIX_SEM)

  32.     if (mtx->semaphore) {
  33.         if (sem_destroy(&mtx->sem) == -1) {
  34.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
  35.                           "sem_destroy() failed");
  36.         }
  37.     }

  38. #endif
  39. }


  40. ngx_uint_t
  41. ngx_shmtx_trylock(ngx_shmtx_t *mtx)
  42. {
  43.     return (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid));
  44. }


  45. void
  46. ngx_shmtx_lock(ngx_shmtx_t *mtx)
  47. {
  48.     ngx_uint_t         i, n;

  49.     ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx lock");

  50.     for ( ;; ) {

  51.         if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
  52.             return;
  53.         }

  54.         if (ngx_ncpu > 1) {

  55.             for (n = 1; n < mtx->spin; n <<= 1) {

  56.                 for (i = 0; i < n; i++) {
  57.                     ngx_cpu_pause();
  58.                 }

  59.                 if (*mtx->lock == 0
  60.                     && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid))
  61.                 {
  62.                     return;
  63.                 }
  64.             }
  65.         }

  66. #if (NGX_HAVE_POSIX_SEM)

  67.         if (mtx->semaphore) {
  68.             (void) ngx_atomic_fetch_add(mtx->wait, 1);

  69.             if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
  70.                 (void) ngx_atomic_fetch_add(mtx->wait, -1);
  71.                 return;
  72.             }

  73.             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
  74.                            "shmtx wait %uA", *mtx->wait);

  75.             while (sem_wait(&mtx->sem) == -1) {
  76.                 ngx_err_t  err;

  77.                 err = ngx_errno;

  78.                 if (err != NGX_EINTR) {
  79.                     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
  80.                                   "sem_wait() failed while waiting on shmtx");
  81.                     break;
  82.                 }
  83.             }

  84.             ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
  85.                            "shmtx awoke");

  86.             continue;
  87.         }

  88. #endif

  89.         ngx_sched_yield();
  90.     }
  91. }


  92. void
  93. ngx_shmtx_unlock(ngx_shmtx_t *mtx)
  94. {
  95.     if (mtx->spin != (ngx_uint_t) -1) {
  96.         ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx unlock");
  97.     }

  98.     if (ngx_atomic_cmp_set(mtx->lock, ngx_pid, 0)) {
  99.         ngx_shmtx_wakeup(mtx);
  100.     }
  101. }


  102. ngx_uint_t
  103. ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
  104. {
  105.     ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
  106.                    "shmtx forced unlock");

  107.     if (ngx_atomic_cmp_set(mtx->lock, pid, 0)) {
  108.         ngx_shmtx_wakeup(mtx);
  109.         return 1;
  110.     }

  111.     return 0;
  112. }


  113. static void
  114. ngx_shmtx_wakeup(ngx_shmtx_t *mtx)
  115. {
  116. #if (NGX_HAVE_POSIX_SEM)
  117.     ngx_atomic_uint_t  wait;

  118.     if (!mtx->semaphore) {
  119.         return;
  120.     }

  121.     for ( ;; ) {

  122.         wait = *mtx->wait;

  123.         if ((ngx_atomic_int_t) wait <= 0) {
  124.             return;
  125.         }

  126.         if (ngx_atomic_cmp_set(mtx->wait, wait, wait - 1)) {
  127.             break;
  128.         }
  129.     }

  130.     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
  131.                    "shmtx wake %uA", wait);

  132.     if (sem_post(&mtx->sem) == -1) {
  133.         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
  134.                       "sem_post() failed while wake shmtx");
  135.     }

  136. #endif
  137. }


  138. #else


  139. ngx_int_t
  140. ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
  141. {
  142.     if (mtx->name) {

  143.         if (ngx_strcmp(name, mtx->name) == 0) {
  144.             mtx->name = name;
  145.             return NGX_OK;
  146.         }

  147.         ngx_shmtx_destroy(mtx);
  148.     }

  149.     mtx->fd = ngx_open_file(name, NGX_FILE_RDWR, NGX_FILE_CREATE_OR_OPEN,
  150.                             NGX_FILE_DEFAULT_ACCESS);

  151.     if (mtx->fd == NGX_INVALID_FILE) {
  152.         ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
  153.                       ngx_open_file_n " \"%s\" failed", name);
  154.         return NGX_ERROR;
  155.     }

  156.     if (ngx_delete_file(name) == NGX_FILE_ERROR) {
  157.         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
  158.                       ngx_delete_file_n " \"%s\" failed", name);
  159.     }

  160.     mtx->name = name;

  161.     return NGX_OK;
  162. }


  163. void
  164. ngx_shmtx_destroy(ngx_shmtx_t *mtx)
  165. {
  166.     if (ngx_close_file(mtx->fd) == NGX_FILE_ERROR) {
  167.         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
  168.                       ngx_close_file_n " \"%s\" failed", mtx->name);
  169.     }
  170. }


  171. ngx_uint_t
  172. ngx_shmtx_trylock(ngx_shmtx_t *mtx)
  173. {
  174.     ngx_err_t  err;

  175.     err = ngx_trylock_fd(mtx->fd);

  176.     if (err == 0) {
  177.         return 1;
  178.     }

  179.     if (err == NGX_EAGAIN) {
  180.         return 0;
  181.     }

  182. #if __osf__ /* Tru64 UNIX */

  183.     if (err == NGX_EACCES) {
  184.         return 0;
  185.     }

  186. #endif

  187.     ngx_log_abort(err, ngx_trylock_fd_n " %s failed", mtx->name);

  188.     return 0;
  189. }


  190. void
  191. ngx_shmtx_lock(ngx_shmtx_t *mtx)
  192. {
  193.     ngx_err_t  err;

  194.     err = ngx_lock_fd(mtx->fd);

  195.     if (err == 0) {
  196.         return;
  197.     }

  198.     ngx_log_abort(err, ngx_lock_fd_n " %s failed", mtx->name);
  199. }


  200. void
  201. ngx_shmtx_unlock(ngx_shmtx_t *mtx)
  202. {
  203.     ngx_err_t  err;

  204.     err = ngx_unlock_fd(mtx->fd);

  205.     if (err == 0) {
  206.         return;
  207.     }

  208.     ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name);
  209. }


  210. ngx_uint_t
  211. ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
  212. {
  213.     return 0;
  214. }

  215. #endif