mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-10 07:39:16 +00:00
ICU-3039 assorted threading changes and cleanups, in search of the elusive
threading failure. X-SVN-Rev: 14564
This commit is contained in:
parent
0db5ea8076
commit
cdbbd81e4a
10 changed files with 923 additions and 554 deletions
|
@ -341,7 +341,7 @@ Locale::Locale( const char * newLanguage,
|
|||
size += 1; // at least: _v
|
||||
}
|
||||
|
||||
if ( newKeywords != NULL)
|
||||
if ( newKeywords != NULL)
|
||||
{
|
||||
ksize = (int32_t)uprv_strlen(newKeywords);
|
||||
size += ksize + 1;
|
||||
|
@ -613,17 +613,25 @@ Locale::setToBogus() {
|
|||
const Locale&
|
||||
Locale::getDefault()
|
||||
{
|
||||
const Locale *retLocale;
|
||||
umtx_lock(NULL);
|
||||
UBool needInit = (gDefaultLocale == NULL);
|
||||
retLocale = gDefaultLocale;
|
||||
umtx_unlock(NULL);
|
||||
if (needInit) {
|
||||
if (retLocale == NULL) {
|
||||
umtx_lock(NULL);
|
||||
/* uprv_getDefaultLocaleID is not thread safe, so we surround it with a mutex */
|
||||
const char *cLocale = uprv_getDefaultLocaleID();
|
||||
umtx_unlock(NULL);
|
||||
locale_set_default_internal(cLocale);
|
||||
umtx_lock(NULL);
|
||||
// Need a mutex in case some other thread set a new
|
||||
// default inbetween when we set and when we get the new default. For
|
||||
// processors with weak memory coherency, we might not otherwise see all
|
||||
// of the newly created new default locale.
|
||||
retLocale = gDefaultLocale;
|
||||
umtx_unlock(NULL);
|
||||
}
|
||||
return *gDefaultLocale;
|
||||
return *retLocale;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
|
||||
#include "unicode/utypes.h"
|
||||
#include "unicode/resbund.h"
|
||||
#include "umutex.h"
|
||||
|
||||
#include "uresimp.h"
|
||||
|
||||
|
@ -172,52 +173,52 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ResourceBundle)
|
|||
ResourceBundle::ResourceBundle( const UnicodeString& path,
|
||||
const Locale& locale,
|
||||
UErrorCode& error)
|
||||
:UObject(), locName(NULL)
|
||||
:UObject(), fLocale(NULL)
|
||||
{
|
||||
constructForLocale(path, locale, error);
|
||||
}
|
||||
|
||||
ResourceBundle::ResourceBundle(UErrorCode &err)
|
||||
:UObject(), locName(NULL)
|
||||
:UObject(), fLocale(NULL)
|
||||
{
|
||||
resource = ures_open(0, Locale::getDefault().getName(), &err);
|
||||
fResource = ures_open(0, Locale::getDefault().getName(), &err);
|
||||
}
|
||||
|
||||
ResourceBundle::ResourceBundle( const UnicodeString& path,
|
||||
UErrorCode& error)
|
||||
:UObject(), locName(NULL)
|
||||
:UObject(), fLocale(NULL)
|
||||
{
|
||||
constructForLocale(path, Locale::getDefault(), error);
|
||||
}
|
||||
|
||||
ResourceBundle::ResourceBundle(const ResourceBundle &other)
|
||||
:UObject(other), locName(NULL)
|
||||
:UObject(other), fLocale(NULL)
|
||||
{
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
if (other.resource) {
|
||||
resource = ures_copyResb(0, other.resource, &status);
|
||||
if (other.fResource) {
|
||||
fResource = ures_copyResb(0, other.fResource, &status);
|
||||
} else {
|
||||
/* Copying a bad resource bundle */
|
||||
resource = NULL;
|
||||
fResource = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ResourceBundle::ResourceBundle(UResourceBundle *res, UErrorCode& err)
|
||||
:UObject(), locName(NULL)
|
||||
:UObject(), fLocale(NULL)
|
||||
{
|
||||
if (res) {
|
||||
resource = ures_copyResb(0, res, &err);
|
||||
fResource = ures_copyResb(0, res, &err);
|
||||
} else {
|
||||
/* Copying a bad resource bundle */
|
||||
resource = NULL;
|
||||
fResource = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ResourceBundle::ResourceBundle(const char* path, const Locale& locale, UErrorCode& err)
|
||||
:UObject(), locName(NULL)
|
||||
:UObject(), fLocale(NULL)
|
||||
{
|
||||
resource = ures_open(path, locale.getName(), &err);
|
||||
fResource = ures_open(path, locale.getName(), &err);
|
||||
}
|
||||
|
||||
|
||||
|
@ -226,27 +227,27 @@ ResourceBundle& ResourceBundle::operator=(const ResourceBundle& other)
|
|||
if(this == &other) {
|
||||
return *this;
|
||||
}
|
||||
if(resource != 0) {
|
||||
ures_close(resource);
|
||||
resource = NULL;
|
||||
if(fResource != 0) {
|
||||
ures_close(fResource);
|
||||
fResource = NULL;
|
||||
}
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
if (other.resource) {
|
||||
resource = ures_copyResb(0, other.resource, &status);
|
||||
if (other.fResource) {
|
||||
fResource = ures_copyResb(0, other.fResource, &status);
|
||||
} else {
|
||||
/* Copying a bad resource bundle */
|
||||
resource = NULL;
|
||||
fResource = NULL;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ResourceBundle::~ResourceBundle()
|
||||
{
|
||||
if(resource != 0) {
|
||||
ures_close(resource);
|
||||
if(fResource != 0) {
|
||||
ures_close(fResource);
|
||||
}
|
||||
if(locName != NULL) {
|
||||
delete(locName);
|
||||
if(fLocale != NULL) {
|
||||
delete(fLocale);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,63 +265,63 @@ ResourceBundle::constructForLocale(const UnicodeString& path,
|
|||
|
||||
if(!path.isEmpty()) {
|
||||
path.extract(name, sizeof(name), 0, error);
|
||||
resource = ures_open(name, locale.getName(), &error);
|
||||
fResource = ures_open(name, locale.getName(), &error);
|
||||
} else {
|
||||
resource = ures_open(0, locale.getName(), &error);
|
||||
fResource = ures_open(0, locale.getName(), &error);
|
||||
}
|
||||
}
|
||||
|
||||
UnicodeString ResourceBundle::getString(UErrorCode& status) const {
|
||||
int32_t len = 0;
|
||||
const UChar *r = ures_getString(resource, &len, &status);
|
||||
const UChar *r = ures_getString(fResource, &len, &status);
|
||||
return UnicodeString(TRUE, r, len);
|
||||
}
|
||||
|
||||
const uint8_t *ResourceBundle::getBinary(int32_t& len, UErrorCode& status) const {
|
||||
return ures_getBinary(resource, &len, &status);
|
||||
return ures_getBinary(fResource, &len, &status);
|
||||
}
|
||||
|
||||
const int32_t *ResourceBundle::getIntVector(int32_t& len, UErrorCode& status) const {
|
||||
return ures_getIntVector(resource, &len, &status);
|
||||
return ures_getIntVector(fResource, &len, &status);
|
||||
}
|
||||
|
||||
uint32_t ResourceBundle::getUInt(UErrorCode& status) const {
|
||||
return ures_getUInt(resource, &status);
|
||||
return ures_getUInt(fResource, &status);
|
||||
}
|
||||
|
||||
int32_t ResourceBundle::getInt(UErrorCode& status) const {
|
||||
return ures_getInt(resource, &status);
|
||||
return ures_getInt(fResource, &status);
|
||||
}
|
||||
|
||||
const char *ResourceBundle::getName(void) {
|
||||
return ures_getName(resource);
|
||||
return ures_getName(fResource);
|
||||
}
|
||||
|
||||
const char *ResourceBundle::getKey(void) {
|
||||
return ures_getKey(resource);
|
||||
return ures_getKey(fResource);
|
||||
}
|
||||
|
||||
UResType ResourceBundle::getType(void) {
|
||||
return ures_getType(resource);
|
||||
return ures_getType(fResource);
|
||||
}
|
||||
|
||||
int32_t ResourceBundle::getSize(void) const {
|
||||
return ures_getSize(resource);
|
||||
return ures_getSize(fResource);
|
||||
}
|
||||
|
||||
UBool ResourceBundle::hasNext(void) const {
|
||||
return ures_hasNext(resource);
|
||||
return ures_hasNext(fResource);
|
||||
}
|
||||
|
||||
void ResourceBundle::resetIterator(void) {
|
||||
ures_resetIterator(resource);
|
||||
ures_resetIterator(fResource);
|
||||
}
|
||||
|
||||
ResourceBundle ResourceBundle::getNext(UErrorCode& status) {
|
||||
UResourceBundle r;
|
||||
|
||||
ures_initStackObject(&r);
|
||||
ures_getNextResource(resource, &r, &status);
|
||||
ures_getNextResource(fResource, &r, &status);
|
||||
ResourceBundle res(&r, status);
|
||||
if (U_SUCCESS(status)) {
|
||||
ures_close(&r);
|
||||
|
@ -330,13 +331,13 @@ ResourceBundle ResourceBundle::getNext(UErrorCode& status) {
|
|||
|
||||
UnicodeString ResourceBundle::getNextString(UErrorCode& status) {
|
||||
int32_t len = 0;
|
||||
const UChar* r = ures_getNextString(resource, &len, 0, &status);
|
||||
const UChar* r = ures_getNextString(fResource, &len, 0, &status);
|
||||
return UnicodeString(TRUE, r, len);
|
||||
}
|
||||
|
||||
UnicodeString ResourceBundle::getNextString(const char ** key, UErrorCode& status) {
|
||||
int32_t len = 0;
|
||||
const UChar* r = ures_getNextString(resource, &len, key, &status);
|
||||
const UChar* r = ures_getNextString(fResource, &len, key, &status);
|
||||
return UnicodeString(TRUE, r, len);
|
||||
}
|
||||
|
||||
|
@ -344,7 +345,7 @@ ResourceBundle ResourceBundle::get(int32_t indexR, UErrorCode& status) const {
|
|||
UResourceBundle r;
|
||||
|
||||
ures_initStackObject(&r);
|
||||
ures_getByIndex(resource, indexR, &r, &status);
|
||||
ures_getByIndex(fResource, indexR, &r, &status);
|
||||
ResourceBundle res(&r, status);
|
||||
if (U_SUCCESS(status)) {
|
||||
ures_close(&r);
|
||||
|
@ -354,7 +355,7 @@ ResourceBundle ResourceBundle::get(int32_t indexR, UErrorCode& status) const {
|
|||
|
||||
UnicodeString ResourceBundle::getStringEx(int32_t indexS, UErrorCode& status) const {
|
||||
int32_t len = 0;
|
||||
const UChar* r = ures_getStringByIndex(resource, indexS, &len, &status);
|
||||
const UChar* r = ures_getStringByIndex(fResource, indexS, &len, &status);
|
||||
return UnicodeString(TRUE, r, len);
|
||||
}
|
||||
|
||||
|
@ -362,7 +363,7 @@ ResourceBundle ResourceBundle::get(const char* key, UErrorCode& status) const {
|
|||
UResourceBundle r;
|
||||
|
||||
ures_initStackObject(&r);
|
||||
ures_getByKey(resource, key, &r, &status);
|
||||
ures_getByKey(fResource, key, &r, &status);
|
||||
ResourceBundle res(&r, status);
|
||||
if (U_SUCCESS(status)) {
|
||||
ures_close(&r);
|
||||
|
@ -372,34 +373,45 @@ ResourceBundle ResourceBundle::get(const char* key, UErrorCode& status) const {
|
|||
|
||||
UnicodeString ResourceBundle::getStringEx(const char* key, UErrorCode& status) const {
|
||||
int32_t len = 0;
|
||||
const UChar* r = ures_getStringByKey(resource, key, &len, &status);
|
||||
const UChar* r = ures_getStringByKey(fResource, key, &len, &status);
|
||||
return UnicodeString(TRUE, r, len);
|
||||
}
|
||||
|
||||
const char*
|
||||
ResourceBundle::getVersionNumber() const
|
||||
{
|
||||
return ures_getVersionNumber(resource);
|
||||
return ures_getVersionNumber(fResource);
|
||||
}
|
||||
|
||||
void ResourceBundle::getVersion(UVersionInfo versionInfo) const {
|
||||
ures_getVersion(resource, versionInfo);
|
||||
ures_getVersion(fResource, versionInfo);
|
||||
}
|
||||
|
||||
const Locale &ResourceBundle::getLocale(void) const
|
||||
{
|
||||
if(locName == NULL) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
const char *localeName = ures_getLocale(resource, &status);
|
||||
ResourceBundle *me = (ResourceBundle *)this; // semantically const
|
||||
me->locName = new Locale(localeName);
|
||||
}
|
||||
return *locName;
|
||||
UBool needInit;
|
||||
umtx_lock(NULL);
|
||||
needInit = (fLocale == NULL);
|
||||
umtx_unlock(NULL);
|
||||
if(needInit) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
const char *localeName = ures_getLocale(fResource, &status);
|
||||
Locale *tLocale = new Locale(localeName);
|
||||
umtx_lock(NULL);
|
||||
ResourceBundle *me = (ResourceBundle *)this; // semantically const
|
||||
if (me->fLocale == NULL) {
|
||||
me->fLocale = tLocale;
|
||||
tLocale = NULL;
|
||||
}
|
||||
umtx_unlock(NULL);
|
||||
delete tLocale;
|
||||
}
|
||||
return *fLocale;
|
||||
}
|
||||
|
||||
const Locale ResourceBundle::getLocale(ULocDataLocaleType type, UErrorCode &status) const
|
||||
{
|
||||
return ures_getLocaleByType(resource, type, &status);
|
||||
return ures_getLocaleByType(fResource, type, &status);
|
||||
}
|
||||
|
||||
//eof
|
||||
|
|
|
@ -84,34 +84,62 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/* The global ICU mutex. */
|
||||
#if defined(WIN32)
|
||||
static UMTX gGlobalMutex = NULL;
|
||||
|
||||
#define MAX_MUTEXES 30
|
||||
static char gMutexesInUse[MAX_MUTEXES];
|
||||
static UBool gMutexPoolInitialized = FALSE;
|
||||
static UMTX gGlobalMutex = NULL;
|
||||
static UMTX gIncDecMutex = NULL;
|
||||
|
||||
/*-------------------------------------------------------------
|
||||
*
|
||||
* WINDOWS platform variable declarations
|
||||
*
|
||||
*-------------------------------------------------------------*/
|
||||
#if defined(WIN32)
|
||||
static CRITICAL_SECTION gMutexes[MAX_MUTEXES];
|
||||
static CRITICAL_SECTION gGlobalWinMutex;
|
||||
|
||||
/* Detect Recursive locking of the global mutex. For debugging only. */
|
||||
#if defined(_DEBUG) && (ICU_USE_THREADS==1)
|
||||
static int32_t gRecursionCount = 0;
|
||||
#endif
|
||||
|
||||
|
||||
/*-------------------------------------------------------------
|
||||
*
|
||||
* POSIX platform variable declarations
|
||||
*
|
||||
*-------------------------------------------------------------*/
|
||||
#elif defined(POSIX)
|
||||
#if (ICU_USE_THREADS == 1)
|
||||
static pthread_mutex_t gGlobalPosixMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static UMTX gGlobalMutex = &gGlobalPosixMutex;
|
||||
static UMTX gIncDecMutex = NULL;
|
||||
#else
|
||||
static UMTX gGlobalMutex = NULL;
|
||||
static UMTX gIncDecMutex = NULL;
|
||||
static pthread_mutex_t gMutexes[MAX_MUTEXES] = {
|
||||
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, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
|
||||
PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/*-------------------------------------------------------------
|
||||
*
|
||||
* UNKNOWN platform declarations
|
||||
*
|
||||
*-------------------------------------------------------------*/
|
||||
#else
|
||||
/* Unknown platform. OK so long as ICU_USE_THREAD is not set.
|
||||
Note that user can still set mutex functions at run time,
|
||||
and that the global mutex variable is still needed in that case. */
|
||||
static UMTX gGlobalMutex = NULL;
|
||||
#if (ICU_USE_THREADS == 1)
|
||||
#error no ICU mutex implementation for this platform
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Detect Recursive locking of the global mutex. For debugging only. */
|
||||
#if defined(WIN32) && defined(_DEBUG) && (ICU_USE_THREADS==1)
|
||||
static int32_t gRecursionCount = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
@ -202,50 +230,6 @@ umtx_unlock(UMTX* mutex)
|
|||
|
||||
|
||||
|
||||
/*
|
||||
* umtx_raw_init Do the platform specific mutex allocation and initialization
|
||||
* for all ICU mutexes _except_ the ICU global mutex.
|
||||
*/
|
||||
static void umtx_raw_init(UMTX *mutex) {
|
||||
if (pMutexInitFn != NULL) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
(*pMutexInitFn)(gMutexContext, mutex, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
/* TODO: how should errors here be handled? */
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
||||
#if (ICU_USE_THREADS == 1)
|
||||
#if defined (WIN32)
|
||||
CRITICAL_SECTION *cs = uprv_malloc(sizeof(CRITICAL_SECTION));
|
||||
if (cs == NULL) {
|
||||
return;
|
||||
}
|
||||
InitializeCriticalSection(cs);
|
||||
*mutex = cs;
|
||||
#elif defined( POSIX )
|
||||
pthread_mutex_t *m = (pthread_mutex_t *)uprv_malloc(sizeof(pthread_mutex_t));
|
||||
if (m == NULL) {
|
||||
return;
|
||||
}
|
||||
# if defined (HPUX_CMA)
|
||||
pthread_mutex_init(m, pthread_mutexattr_default);
|
||||
# else
|
||||
pthread_mutex_init(m, NULL);
|
||||
# endif
|
||||
*mutex = m;
|
||||
#endif /* cascade of platforms */
|
||||
#else /* ICU_USE_THREADS */
|
||||
*mutex = mutex; /* With no threads, we must still set the mutex to
|
||||
* some non-null value to make the rest of the
|
||||
* (not ifdefed) mutex code think that it is initialized.
|
||||
*/
|
||||
#endif /* ICU_USE_THREADS */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* initGlobalMutex Do the platform specific initialization of the ICU global mutex.
|
||||
|
@ -254,9 +238,11 @@ static void umtx_raw_init(UMTX *mutex) {
|
|||
* without the use of another mutex.
|
||||
*/
|
||||
static void initGlobalMutex() {
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Call user mutex init function if one has been specified and the global mutex
|
||||
* is not already initialized.
|
||||
* If User Supplied mutex functions are in use
|
||||
* init the icu global mutex using them.
|
||||
*/
|
||||
if (pMutexInitFn != NULL) {
|
||||
if (gGlobalMutex==NULL) {
|
||||
|
@ -274,31 +260,34 @@ static void initGlobalMutex() {
|
|||
* Use default ICU mutex implementations.
|
||||
*/
|
||||
#if (ICU_USE_THREADS == 1)
|
||||
/*
|
||||
* for Windows, init the pool of critical sections that we
|
||||
* will use as needed for ICU mutexes.
|
||||
*/
|
||||
#if defined (WIN32)
|
||||
{
|
||||
void *t;
|
||||
CRITICAL_SECTION *ourCritSec = uprv_malloc(sizeof(CRITICAL_SECTION));
|
||||
InitializeCriticalSection(ourCritSec);
|
||||
#if defined (InterlockedCompareExchangePointer) || defined (_WIN64)
|
||||
t = InterlockedCompareExchangePointer(&gGlobalMutex, ourCritSec, NULL);
|
||||
#else
|
||||
/* Note that the headers from Microsoft's WIndows SDK define InterlockedCompareExchangePointer
|
||||
* for all platforms, but the old headers included with MSVC 6 do not.
|
||||
*/
|
||||
t = (void *)InterlockedCompareExchange(&gGlobalMutex, ourCritSec, NULL);
|
||||
#endif
|
||||
if (t != NULL) {
|
||||
/* Some other thread stored into gGlobalMutex first. Discard the critical
|
||||
* section we just created; the system will go with the other one.
|
||||
*/
|
||||
DeleteCriticalSection(ourCritSec);
|
||||
uprv_free(ourCritSec);
|
||||
if (gMutexPoolInitialized == FALSE) {
|
||||
for (i=0; i<MAX_MUTEXES; i++) {
|
||||
InitializeCriticalSection(&gMutexes[i]);
|
||||
}
|
||||
}
|
||||
#elif defined( POSIX )
|
||||
/* No Action Required. Global mutex set up with C static initialization. */
|
||||
U_ASSERT(gGlobalMutex == &gGlobalPosixMutex);
|
||||
#endif /* cascade of platforms */
|
||||
gMutexPoolInitialized = TRUE;
|
||||
#elif defined (POSIX)
|
||||
/* TODO: experimental code. Shouldn't need to explicitly init the mutexes. */
|
||||
if (gMutexPoolInitialized == FALSE) {
|
||||
for (i=0; i<MAX_MUTEXES; i++) {
|
||||
pthread_mutex_init(&gMutexes[i], NULL);
|
||||
}
|
||||
}
|
||||
gMutexPoolInitialized = TRUE;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* for both Windows & POSIX, the first mutex in the array is used
|
||||
* for the ICU global mutex.
|
||||
*/
|
||||
gGlobalMutex = &gMutexes[0];
|
||||
gMutexesInUse[0] = 1;
|
||||
|
||||
#else /* ICU_USE_THREADS */
|
||||
gGlobalMutex = &gGlobalMutex; /* With no threads, we must still set the mutex to
|
||||
* some non-null value to make the rest of the
|
||||
|
@ -317,32 +306,36 @@ umtx_init(UMTX *mutex)
|
|||
if (mutex == NULL || mutex == &gGlobalMutex) {
|
||||
initGlobalMutex();
|
||||
} else {
|
||||
/*
|
||||
* Thread safe initialization of mutexes other than the global one,
|
||||
* using the global mutex.
|
||||
*/
|
||||
UBool isInitialized;
|
||||
UMTX tMutex = NULL;
|
||||
|
||||
int i;
|
||||
umtx_lock(NULL);
|
||||
isInitialized = (*mutex != NULL);
|
||||
umtx_unlock(NULL);
|
||||
if (isInitialized) {
|
||||
if (*mutex != NULL) {
|
||||
/* Another thread initialized this mutex first. */
|
||||
umtx_unlock(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
umtx_raw_init(&tMutex);
|
||||
if (pMutexInitFn != NULL) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
(*pMutexInitFn)(gMutexContext, mutex, &status);
|
||||
/* TODO: how to report failure on init? */
|
||||
umtx_unlock(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
umtx_lock(NULL);
|
||||
if (*mutex == NULL) {
|
||||
*mutex = tMutex;
|
||||
tMutex = NULL;
|
||||
/* Search through our pool of pre-allocated mutexes for one that is not
|
||||
* already in use. */
|
||||
for (i=0; i<MAX_MUTEXES; i++) {
|
||||
if (gMutexesInUse[i] == 0) {
|
||||
gMutexesInUse[i] = 1;
|
||||
*mutex = &gMutexes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
umtx_unlock(NULL);
|
||||
|
||||
if (tMutex != NULL) {
|
||||
umtx_destroy(&tMutex);
|
||||
}
|
||||
|
||||
/* No more mutexes were available from our pre-allocated pool. */
|
||||
/* TODO: how best to deal with this? */
|
||||
U_ASSERT(*mutex != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -364,38 +357,28 @@ umtx_destroy(UMTX *mutex) {
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined (POSIX)
|
||||
/* The life of the inc/dec mutex for POSIX is tied to that of the global mutex. */
|
||||
/* The life of the inc/dec mutex is tied to that of the global mutex. */
|
||||
if (mutex == &gGlobalMutex) {
|
||||
umtx_destroy(&gIncDecMutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pMutexDestroyFn != NULL) {
|
||||
/* Mutexes are being managed by the app. Call back to it for the destroy. */
|
||||
(*pMutexDestroyFn)(gMutexContext, mutex);
|
||||
*mutex = NULL;
|
||||
} else {
|
||||
#if (ICU_USE_THREADS == 1)
|
||||
#if defined (WIN32)
|
||||
DeleteCriticalSection((CRITICAL_SECTION*)*mutex);
|
||||
uprv_free(*mutex);
|
||||
*mutex = NULL;
|
||||
#elif defined (POSIX)
|
||||
if (*mutex != &gGlobalPosixMutex) {
|
||||
/* Only POSIX mutexes other than the ICU global mutex get destroyed. */
|
||||
pthread_mutex_destroy((pthread_mutex_t*)*mutex);
|
||||
uprv_free(*mutex);
|
||||
*mutex = NULL;
|
||||
}
|
||||
#endif /* chain of platforms */
|
||||
#else /* ICU_USE_THREADS==1 */
|
||||
/* NO ICU Threads. We still need to zero out the mutex pointer, so that
|
||||
* it appears to be uninitialized */
|
||||
*mutex = NULL;
|
||||
#endif /* ICU_USE_THREADS */
|
||||
|
||||
/* Return this mutex to the pool of available mutexes, if it came from the
|
||||
* pool in the first place.
|
||||
*/
|
||||
int i;
|
||||
for (i=0; i<MAX_MUTEXES; i++) {
|
||||
if (*mutex == &gMutexes[i]) {
|
||||
gMutexesInUse[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*mutex = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -528,22 +511,35 @@ u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *ip, UMtxAtomicFn *
|
|||
* Destroy the global mutex(es), and reset the mutex function callback pointers.
|
||||
*/
|
||||
U_CFUNC UBool umtx_cleanup(void) {
|
||||
int i;
|
||||
umtx_destroy(NULL);
|
||||
pMutexInitFn = NULL;
|
||||
pMutexDestroyFn = NULL;
|
||||
pMutexLockFn = NULL;
|
||||
pMutexUnlockFn = NULL;
|
||||
gMutexContext = NULL;
|
||||
|
||||
gGlobalMutex = NULL;
|
||||
#if defined (POSIX)
|
||||
gIncDecMutex = NULL;
|
||||
#if (ICU_USE_THREADS == 1)
|
||||
gGlobalMutex = &gGlobalPosixMutex;
|
||||
#endif
|
||||
#endif
|
||||
pIncFn = NULL;
|
||||
pDecFn = NULL;
|
||||
gIncDecMutex = NULL;
|
||||
|
||||
#if defined (WIN32)
|
||||
if (gMutexPoolInitialized) {
|
||||
for (i=0; i<MAX_MUTEXES; i++) {
|
||||
DeleteCriticalSection(&gMutexes[i]);
|
||||
gMutexesInUse[i] = 0;
|
||||
}
|
||||
}
|
||||
gMutexPoolInitialized = FALSE;
|
||||
|
||||
#elif defined (POSIX)
|
||||
gIncDecMutex = NULL;
|
||||
for (i=0; i<MAX_MUTEXES; i++) {
|
||||
pthread_mutex_destroy(&gMutexes[i]);
|
||||
gMutexesInUse[i] = 0;
|
||||
}
|
||||
gMutexPoolInitialized = FALSE;
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -457,9 +457,9 @@ public:
|
|||
private:
|
||||
ResourceBundle(); // default constructor not implemented
|
||||
|
||||
UResourceBundle *resource;
|
||||
UResourceBundle *fResource;
|
||||
void constructForLocale(const UnicodeString& path, const Locale& locale, UErrorCode& error);
|
||||
Locale *locName;
|
||||
Locale *fLocale;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -246,6 +246,7 @@ static void setEntryName(UResourceDataEntry *res, char *name, UErrorCode *status
|
|||
|
||||
/**
|
||||
* INTERNAL: Inits and opens an entry from a data DLL.
|
||||
* CAUTION: resbMutex must be locked when calling this function.
|
||||
*/
|
||||
static UResourceDataEntry *init_entry(const char *localeID, const char *path, UErrorCode *status) {
|
||||
UResourceDataEntry *r = NULL;
|
||||
|
@ -377,6 +378,7 @@ static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE
|
|||
}
|
||||
|
||||
/* INTERNAL: */
|
||||
/* CAUTION: resbMutex must be locked when calling this function! */
|
||||
static UResourceDataEntry *findFirstExisting(const char* path, char* name, UBool *isRoot, UBool *hasChopped, UBool *isDefault, UErrorCode* status) {
|
||||
UResourceDataEntry *r = NULL;
|
||||
UBool hasRealData = FALSE;
|
||||
|
@ -517,6 +519,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID, UEr
|
|||
|
||||
/**
|
||||
* Functions to create and destroy resource bundles.
|
||||
* CAUTION: resbMutex must be locked when calling this function.
|
||||
*/
|
||||
/* INTERNAL: */
|
||||
static void entryCloseInt(UResourceDataEntry *resB) {
|
||||
|
|
|
@ -18,11 +18,14 @@
|
|||
#include "rbt_data.h"
|
||||
#include "rbt_rule.h"
|
||||
#include "rbt.h"
|
||||
#include "umutex.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTransliterator)
|
||||
|
||||
static UMTX transliteratorDataMutex = NULL;
|
||||
|
||||
void RuleBasedTransliterator::_construct(const UnicodeString& rules,
|
||||
UTransDirection direction,
|
||||
UParseError& parseError,
|
||||
|
@ -228,7 +231,7 @@ RuleBasedTransliterator::handleTransliterate(Replaceable& text, UTransPosition&
|
|||
}
|
||||
|
||||
if (isDataOwned==FALSE) {
|
||||
fData->lock();
|
||||
umtx_lock(&transliteratorDataMutex);
|
||||
}
|
||||
while (index.start < index.limit &&
|
||||
loopCount <= loopLimit &&
|
||||
|
@ -236,7 +239,7 @@ RuleBasedTransliterator::handleTransliterate(Replaceable& text, UTransPosition&
|
|||
++loopCount;
|
||||
}
|
||||
if (isDataOwned==FALSE) {
|
||||
fData->unlock();
|
||||
umtx_unlock(&transliteratorDataMutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ U_NAMESPACE_BEGIN
|
|||
|
||||
TransliterationRuleData::TransliterationRuleData(UErrorCode& status)
|
||||
: UMemory(), ruleSet(status),
|
||||
variableNames(0), variables(0), fLock(NULL)
|
||||
variableNames(0), variables(0)
|
||||
{
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
|
@ -44,8 +44,7 @@ TransliterationRuleData::TransliterationRuleData(UErrorCode& status)
|
|||
TransliterationRuleData::TransliterationRuleData(const TransliterationRuleData& other) :
|
||||
UMemory(other), ruleSet(other.ruleSet),
|
||||
variablesBase(other.variablesBase),
|
||||
variablesLength(other.variablesLength),
|
||||
fLock(NULL) /* The mutex must NOT be copied from the source data */
|
||||
variablesLength(other.variablesLength)
|
||||
{
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
variableNames = new Hashtable(status);
|
||||
|
@ -85,7 +84,6 @@ TransliterationRuleData::~TransliterationRuleData() {
|
|||
}
|
||||
uprv_free(variables);
|
||||
}
|
||||
umtx_destroy(&fLock);
|
||||
}
|
||||
|
||||
UnicodeFunctor*
|
||||
|
@ -106,17 +104,6 @@ TransliterationRuleData::lookupReplacer(UChar32 standIn) const {
|
|||
return (f != 0) ? f->toReplacer() : 0;
|
||||
}
|
||||
|
||||
void
|
||||
TransliterationRuleData::lock() {
|
||||
umtx_lock(&fLock);
|
||||
}
|
||||
|
||||
void
|
||||
TransliterationRuleData::unlock() {
|
||||
umtx_unlock(&fLock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
|
|
|
@ -130,19 +130,9 @@ public:
|
|||
*/
|
||||
UnicodeReplacer* lookupReplacer(UChar32 standIn) const;
|
||||
|
||||
/**
|
||||
* Acquire the mutex lock for this data.
|
||||
*/
|
||||
void lock();
|
||||
|
||||
/**
|
||||
* Release the mutex lock for this data
|
||||
*/
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
TransliterationRuleData &operator=(const TransliterationRuleData &other); // forbid copying of this class
|
||||
UMTX fLock;
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,25 +11,6 @@
|
|||
#include "intltest.h"
|
||||
#include "mutex.h"
|
||||
|
||||
/*
|
||||
Test multithreading. Of course we need a thread class first..
|
||||
this wrapper has a ported implementation.
|
||||
*/
|
||||
|
||||
class SimpleThread
|
||||
{
|
||||
public:
|
||||
SimpleThread();
|
||||
virtual ~SimpleThread();
|
||||
int32_t start(void); // start the thread
|
||||
public: // should be private, but then we couldn't be asocial.
|
||||
virtual void run(void) = 0; // Override this to provide some real implementation
|
||||
private:
|
||||
void *fImplementation;
|
||||
|
||||
public:
|
||||
static void sleep(int32_t millis); // probably shouldn't go here but oh well.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
@ -58,7 +39,7 @@ public:
|
|||
void TestThreadedIntl(void);
|
||||
#endif
|
||||
void TestCollators(void);
|
||||
|
||||
void TestString();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue