コード例 #1
0
ファイル: nc_mutex.c プロジェクト: Lind-Project/native_client
int pthread_mutex_unlock(pthread_mutex_t *mutex) {
  if (NACL_UNLIKELY(mutex->mutex_type != PTHREAD_MUTEX_FAST_NP)) {
    if ((PTHREAD_MUTEX_RECURSIVE_NP == mutex->mutex_type) &&
        (0 != (--mutex->recursion_counter))) {
      /*
       * We assume that this thread owns the lock
       * (no verification for recursive locks),
       * so just decrement the counter, this thread is still the owner.
       */
      return 0;
    }
    if ((PTHREAD_MUTEX_ERRORCHECK_NP == mutex->mutex_type) &&
        (pthread_self() != mutex->owner_thread_id)) {
      /* Error - releasing a mutex that's free or owned by another thread. */
      return EPERM;
    }
    /* Writing to owner_thread_id here must be done atomically. */
    mutex->owner_thread_id = NACL_PTHREAD_ILLEGAL_THREAD_ID;
    mutex->recursion_counter = 0;
  }

  /*
   * Release the mutex.  This atomic decrement executes the full
   * memory barrier that pthread_mutex_unlock() is required to
   * execute.
   */
  int old_state = __sync_fetch_and_sub(&mutex->mutex_state, 1);
  if (NACL_UNLIKELY(old_state != LOCKED_WITHOUT_WAITERS)) {
    if (old_state == UNLOCKED) {
      /*
       * The mutex was not locked.  mutex_state is now -1 and the
       * mutex is likely unusable, but that is the caller's fault for
       * using the mutex interface incorrectly.
       */
      return EPERM;
    }
    /*
     * We decremented mutex_state from LOCKED_WITH_WAITERS to
     * LOCKED_WITHOUT_WAITERS.  We must now release the mutex fully.
     *
     * No further memory barrier is required for the following
     * modification of mutex_state.  The full memory barrier from the
     * atomic decrement acts as a release memory barrier for the
     * following modification.
     *
     * TODO(mseaborn): Change the following store to use an atomic
     * store builtin when this is available in all the NaCl
     * toolchains.  For now, PNaCl converts the volatile store to an
     * atomic store.
     */
    mutex->mutex_state = UNLOCKED;
    int woken;
    __nc_irt_futex.futex_wake(&mutex->mutex_state, 1, &woken);
  }
  return 0;
}
コード例 #2
0
ファイル: nc_mutex.c プロジェクト: dsagal/native_client
static int mutex_lock_nonrecursive(pthread_mutex_t *mutex, int try_only,
                                   const struct timespec *abstime) {
  /*
   * Try to claim the mutex.  This compare-and-swap executes the full
   * memory barrier that pthread_mutex_lock() is required to execute.
   */
  int old_state = __sync_val_compare_and_swap(&mutex->mutex_state, UNLOCKED,
                                              LOCKED_WITHOUT_WAITERS);
  if (NACL_UNLIKELY(old_state != UNLOCKED)) {
    if (try_only) {
      return EBUSY;
    }
    if (abstime != NULL &&
        (abstime->tv_nsec < 0 || 1000000000 <= abstime->tv_nsec)) {
      return EINVAL;
    }
    do {
      /*
       * If the state shows there are already waiters, or we can
       * update it to indicate that there are waiters, then wait.
       */
      if (old_state == LOCKED_WITH_WAITERS ||
          __sync_val_compare_and_swap(&mutex->mutex_state,
                                      LOCKED_WITHOUT_WAITERS,
                                      LOCKED_WITH_WAITERS) != UNLOCKED) {
        int rc = __libnacl_irt_futex.futex_wait_abs(&mutex->mutex_state,
                                                    LOCKED_WITH_WAITERS,
                                                    abstime);
        if (abstime != NULL && rc == ETIMEDOUT)
          return ETIMEDOUT;
      }
      /*
       * Try again to claim the mutex.  On this try, we must set
       * mutex_state to LOCKED_WITH_WAITERS rather than
       * LOCKED_WITHOUT_WAITERS.  We could have been woken up when
       * many threads are in the wait queue for the mutex.
       */
      old_state = __sync_val_compare_and_swap(&mutex->mutex_state, UNLOCKED,
                                              LOCKED_WITH_WAITERS);
    } while (old_state != UNLOCKED);
  }
  return 0;
}