Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/nsprpub/pr/src/misc/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 8 kB image not shown  

Quelle  pratom.c   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


/*
**     PR Atomic operations
*/


#include "pratom.h"
#include "primpl.h"

#include <string.h>

/*
 * The following is a fallback implementation that emulates
 * atomic operations for platforms without atomic operations.
 * If a platform has atomic operations, it should define the
 * macro _PR_HAVE_ATOMIC_OPS, and the following will not be
 * compiled in.
 */


#if !defined(_PR_HAVE_ATOMIC_OPS)

#  if defined(_PR_PTHREADS)
/*
 * PR_AtomicDecrement() is used in NSPR's thread-specific data
 * destructor.  Because thread-specific data destructors may be
 * invoked after a PR_Cleanup() call, we need an implementation
 * of the atomic routines that doesn't need NSPR to be initialized.
 */


/*
 * We use a set of locks for all the emulated atomic operations.
 * By hashing on the address of the integer to be locked the
 * contention between multiple threads should be lessened.
 *
 * The number of atomic locks can be set by the environment variable
 * NSPR_ATOMIC_HASH_LOCKS
 */


/*
 * lock counts should be a power of 2
 */

#    define DEFAULT_ATOMIC_LOCKS                              \
      16 /* should be in sync with the number of initializers \
             below */

#    define MAX_ATOMIC_LOCKS (4 * 1024)

static pthread_mutex_t static_atomic_locks[DEFAULT_ATOMIC_LOCKS] = {
    PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER};

#    ifdef DEBUG
static PRInt32 static_hash_lock_counts[DEFAULT_ATOMIC_LOCKS];
static PRInt32* hash_lock_counts = static_hash_lock_counts;
#    endif

static PRUint32 num_atomic_locks = DEFAULT_ATOMIC_LOCKS;
static pthread_mutex_t* atomic_locks = static_atomic_locks;
static PRUint32 atomic_hash_mask = DEFAULT_ATOMIC_LOCKS - 1;

#    define _PR_HASH_FOR_LOCK(ptr)                                       \
      ((PRUint32)(((PRUptrdiff)(ptr) >> 2) ^ ((PRUptrdiff)(ptr) >> 8)) & \
       atomic_hash_mask)

void _PR_MD_INIT_ATOMIC() {
  char* eval;
  int index;

  PR_ASSERT(PR_FloorLog2(MAX_ATOMIC_LOCKS) == PR_CeilingLog2(MAX_ATOMIC_LOCKS));

  PR_ASSERT(PR_FloorLog2(DEFAULT_ATOMIC_LOCKS) ==
            PR_CeilingLog2(DEFAULT_ATOMIC_LOCKS));

  if (((eval = getenv("NSPR_ATOMIC_HASH_LOCKS")) != NULL) &&
      ((num_atomic_locks = atoi(eval)) != DEFAULT_ATOMIC_LOCKS)) {
    if (num_atomic_locks > MAX_ATOMIC_LOCKS) {
      num_atomic_locks = MAX_ATOMIC_LOCKS;
    } else if (num_atomic_locks < 1) {
      num_atomic_locks = 1;
    } else {
      num_atomic_locks = PR_FloorLog2(num_atomic_locks);
      num_atomic_locks = 1L << num_atomic_locks;
    }
    atomic_locks =
        (pthread_mutex_t*)PR_Malloc(sizeof(pthread_mutex_t) * num_atomic_locks);
    if (atomic_locks) {
      for (index = 0; index < num_atomic_locks; index++) {
        if (pthread_mutex_init(&atomic_locks[index], NULL)) {
          PR_DELETE(atomic_locks);
          atomic_locks = NULL;
          break;
        }
      }
    }
#    ifdef DEBUG
    if (atomic_locks) {
      hash_lock_counts = PR_CALLOC(num_atomic_locks * sizeof(PRInt32));
      if (hash_lock_counts == NULL) {
        PR_DELETE(atomic_locks);
        atomic_locks = NULL;
      }
    }
#    endif
    if (atomic_locks == NULL) {
      /*
       *  Use statically allocated locks
       */

      atomic_locks = static_atomic_locks;
      num_atomic_locks = DEFAULT_ATOMIC_LOCKS;
#    ifdef DEBUG
      hash_lock_counts = static_hash_lock_counts;
#    endif
    }
    atomic_hash_mask = num_atomic_locks - 1;
  }
  PR_ASSERT(PR_FloorLog2(num_atomic_locks) == PR_CeilingLog2(num_atomic_locks));
}

PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32* val) {
  PRInt32 rv;
  PRInt32 idx = _PR_HASH_FOR_LOCK(val);

  pthread_mutex_lock(&atomic_locks[idx]);
  rv = ++(*val);
#    ifdef DEBUG
  hash_lock_counts[idx]++;
#    endif
  pthread_mutex_unlock(&atomic_locks[idx]);
  return rv;
}

PRInt32 _PR_MD_ATOMIC_ADD(PRInt32* ptr, PRInt32 val) {
  PRInt32 rv;
  PRInt32 idx = _PR_HASH_FOR_LOCK(ptr);

  pthread_mutex_lock(&atomic_locks[idx]);
  rv = ((*ptr) += val);
#    ifdef DEBUG
  hash_lock_counts[idx]++;
#    endif
  pthread_mutex_unlock(&atomic_locks[idx]);
  return rv;
}

PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32* val) {
  PRInt32 rv;
  PRInt32 idx = _PR_HASH_FOR_LOCK(val);

  pthread_mutex_lock(&atomic_locks[idx]);
  rv = --(*val);
#    ifdef DEBUG
  hash_lock_counts[idx]++;
#    endif
  pthread_mutex_unlock(&atomic_locks[idx]);
  return rv;
}

PRInt32 _PR_MD_ATOMIC_SET(PRInt32* val, PRInt32 newval) {
  PRInt32 rv;
  PRInt32 idx = _PR_HASH_FOR_LOCK(val);

  pthread_mutex_lock(&atomic_locks[idx]);
  rv = *val;
  *val = newval;
#    ifdef DEBUG
  hash_lock_counts[idx]++;
#    endif
  pthread_mutex_unlock(&atomic_locks[idx]);
  return rv;
}
#  else  /* _PR_PTHREADS */
/*
 * We use a single lock for all the emulated atomic operations.
 * The lock contention should be acceptable.
 */

static PRLock* atomic_lock = NULL;
void _PR_MD_INIT_ATOMIC(void) {
  if (atomic_lock == NULL) {
    atomic_lock = PR_NewLock();
  }
}

PRInt32 _PR_MD_ATOMIC_INCREMENT(PRInt32* val) {
  PRInt32 rv;

  if (!_pr_initialized) {
    _PR_ImplicitInitialization();
  }
  PR_Lock(atomic_lock);
  rv = ++(*val);
  PR_Unlock(atomic_lock);
  return rv;
}

PRInt32 _PR_MD_ATOMIC_ADD(PRInt32* ptr, PRInt32 val) {
  PRInt32 rv;

  if (!_pr_initialized) {
    _PR_ImplicitInitialization();
  }
  PR_Lock(atomic_lock);
  rv = ((*ptr) += val);
  PR_Unlock(atomic_lock);
  return rv;
}

PRInt32 _PR_MD_ATOMIC_DECREMENT(PRInt32* val) {
  PRInt32 rv;

  if (!_pr_initialized) {
    _PR_ImplicitInitialization();
  }
  PR_Lock(atomic_lock);
  rv = --(*val);
  PR_Unlock(atomic_lock);
  return rv;
}

PRInt32 _PR_MD_ATOMIC_SET(PRInt32* val, PRInt32 newval) {
  PRInt32 rv;

  if (!_pr_initialized) {
    _PR_ImplicitInitialization();
  }
  PR_Lock(atomic_lock);
  rv = *val;
  *val = newval;
  PR_Unlock(atomic_lock);
  return rv;
}
#  endif /* _PR_PTHREADS */

#endif /* !_PR_HAVE_ATOMIC_OPS */

void _PR_InitAtomic(void) { _PR_MD_INIT_ATOMIC(); }

PR_IMPLEMENT(PRInt32)
PR_AtomicIncrement(PRInt32* val) { return _PR_MD_ATOMIC_INCREMENT(val); }

PR_IMPLEMENT(PRInt32)
PR_AtomicDecrement(PRInt32* val) { return _PR_MD_ATOMIC_DECREMENT(val); }

PR_IMPLEMENT(PRInt32)
PR_AtomicSet(PRInt32* val, PRInt32 newval) {
  return _PR_MD_ATOMIC_SET(val, newval);
}

PR_IMPLEMENT(PRInt32)
PR_AtomicAdd(PRInt32* ptr, PRInt32 val) { return _PR_MD_ATOMIC_ADD(ptr, val); }
/*
 * For platforms, which don't support the CAS (compare-and-swap) instruction
 * (or an equivalent), the stack operations are implemented by use of PRLock
 */


PR_IMPLEMENT(PRStack*)
PR_CreateStack(const char* stack_name) {
  PRStack* stack;

  if (!_pr_initialized) {
    _PR_ImplicitInitialization();
  }

  if ((stack = PR_NEW(PRStack)) == NULL) {
    return NULL;
  }
  if (stack_name) {
    stack->prstk_name = (char*)PR_Malloc(strlen(stack_name) + 1);
    if (stack->prstk_name == NULL) {
      PR_DELETE(stack);
      return NULL;
    }
    strcpy(stack->prstk_name, stack_name);
  } else {
    stack->prstk_name = NULL;
  }

#ifndef _PR_HAVE_ATOMIC_CAS
  stack->prstk_lock = PR_NewLock();
  if (stack->prstk_lock == NULL) {
    PR_Free(stack->prstk_name);
    PR_DELETE(stack);
    return NULL;
  }
#endif /* !_PR_HAVE_ATOMIC_CAS */

  stack->prstk_head.prstk_elem_next = NULL;

  return stack;
}

PR_IMPLEMENT(PRStatus)
PR_DestroyStack(PRStack* stack) {
  if (stack->prstk_head.prstk_elem_next != NULL) {
    PR_SetError(PR_INVALID_STATE_ERROR, 0);
    return PR_FAILURE;
  }

  if (stack->prstk_name) {
    PR_Free(stack->prstk_name);
  }
#ifndef _PR_HAVE_ATOMIC_CAS
  PR_DestroyLock(stack->prstk_lock);
#endif /* !_PR_HAVE_ATOMIC_CAS */
  PR_DELETE(stack);

  return PR_SUCCESS;
}

#ifndef _PR_HAVE_ATOMIC_CAS

PR_IMPLEMENT(void)
PR_StackPush(PRStack* stack, PRStackElem* stack_elem) {
  PR_Lock(stack->prstk_lock);
  stack_elem->prstk_elem_next = stack->prstk_head.prstk_elem_next;
  stack->prstk_head.prstk_elem_next = stack_elem;
  PR_Unlock(stack->prstk_lock);
  return;
}

PR_IMPLEMENT(PRStackElem*)
PR_StackPop(PRStack* stack) {
  PRStackElem* element;

  PR_Lock(stack->prstk_lock);
  element = stack->prstk_head.prstk_elem_next;
  if (element != NULL) {
    stack->prstk_head.prstk_elem_next = element->prstk_elem_next;
    element->prstk_elem_next = NULL; /* debugging aid */
  }
  PR_Unlock(stack->prstk_lock);
  return element;
}
#endif /* !_PR_HAVE_ATOMIC_CAS */

Messung V0.5
C=94 H=96 G=94

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.