U_CDECL_BEGIN static UBool U_CALLCONV timeZone_cleanup(void) { #ifdef U_USE_TIMEZONE_OBSOLETE_2_8 delete []OLSON_IDS; OLSON_IDS = 0; #endif delete DEFAULT_ZONE; DEFAULT_ZONE = NULL; delete _GMT; _GMT = NULL; uprv_memset(TZDATA_VERSION, 0, sizeof(TZDATA_VERSION)); TZDataVersionInitialized = FALSE; if (LOCK) { umtx_destroy(&LOCK); LOCK = NULL; } if (TZSET_LOCK) { umtx_destroy(&TZSET_LOCK); TZSET_LOCK = NULL; } return TRUE; }
/** * Cleanup callback func */ static UBool U_CALLCONV zoneMeta_cleanup(void) { umtx_destroy(&gZoneMetaLock); if (gCanonicalMap != NULL) { uhash_close(gCanonicalMap); gCanonicalMap = NULL; } gCanonicalMapInitialized = FALSE; if (gOlsonToMeta != NULL) { uhash_close(gOlsonToMeta); gOlsonToMeta = NULL; } gOlsonToMetaInitialized = FALSE; if (gMetaToOlson != NULL) { uhash_close(gMetaToOlson); gMetaToOlson = NULL; } gMetaToOlsonInitialized = FALSE; freeUStringTable(); return TRUE; }
/* * Mutex Cleanup Function * * Destroy the global mutex(es), and reset the mutex function callback pointers. */ U_CFUNC UBool umtx_cleanup(void) { umtx_destroy(NULL); pMutexInitFn = NULL; pMutexDestroyFn = NULL; pMutexLockFn = NULL; pMutexUnlockFn = NULL; gMutexContext = NULL; gGlobalMutex = NULL; pIncFn = NULL; pDecFn = NULL; gIncDecContext = NULL; gIncDecMutex = NULL; #if (ICU_USE_THREADS == 1) if (gMutexPoolInitialized) { int i; for (i=0; i<MAX_MUTEXES; i++) { if (gMutexesInUse[i]) { #if defined (U_WINDOWS) DeleteCriticalSection(&gMutexes[i]); #elif defined (POSIX) pthread_mutex_destroy(&gMutexes[i]); #endif gMutexesInUse[i] = 0; } } } gMutexPoolInitialized = FALSE; #endif return TRUE; }
/** * Free static memory. */ void TransliteratorIDParser::cleanup() { if (SPECIAL_INVERSES) { delete SPECIAL_INVERSES; SPECIAL_INVERSES = NULL; } umtx_destroy(&LOCK); }
UBool timeZone_cleanup() { // Aliases into UDATA_MEMORY; do NOT delete DATA = NULL; INDEX_BY_ID = NULL; INDEX_BY_OFFSET = NULL; INDEX_BY_COUNTRY = NULL; delete []ZONE_IDS; ZONE_IDS = NULL; delete DEFAULT_ZONE; DEFAULT_ZONE = NULL; delete _GMT; _GMT = NULL; if (UDATA_MEMORY) { udata_close(UDATA_MEMORY); UDATA_MEMORY = NULL; } if (LOCK) { umtx_destroy(&LOCK); LOCK = NULL; } return TRUE; }
/* This doesn't need to be thread safe. It's for u_cleanup only. */ static void cleanup(void) { while (gCRegHead) { CReg* n = gCRegHead; gCRegHead = gCRegHead->next; delete n; } umtx_destroy(&gCRegLock); }
ICUNotifier::~ICUNotifier(void) { { Mutex lmx(¬ifyLock); delete listeners; listeners = NULL; } umtx_destroy(¬ifyLock); }
CollDataCache::~CollDataCache() { umtx_lock(&lock); uhash_close(cache); cache = NULL; umtx_unlock(&lock); umtx_destroy(&lock); }
ICUService::~ICUService() { { Mutex mutex(&lock); clearCaches(); delete factories; factories = NULL; } umtx_destroy(&lock); }
U_CDECL_BEGIN static UBool calendar_islamic_cleanup(void) { if (gMonthCache) { delete gMonthCache; gMonthCache = NULL; } if (gIslamicCalendarAstro) { delete gIslamicCalendarAstro; gIslamicCalendarAstro = NULL; } umtx_destroy(&astroLock); return TRUE; }
U_CFUNC UBool umtx_cleanup(void) { ICUMutex *thisMutex = NULL; ICUMutex *nextMutex = NULL; /* Extra, do-nothing function call to suppress compiler warnings on platforms where * mutexed_compare_and_swap is not otherwise used. */ mutexed_compare_and_swap(&globalUMTX, NULL, NULL); /* Delete all of the ICU mutexes. Do the global mutex last because it is used during * the umtx_destroy operation of other mutexes. */ for (thisMutex=mutexListHead; thisMutex!=NULL; thisMutex=nextMutex) { UMTX *umtx = thisMutex->owner; nextMutex = thisMutex->next; U_ASSERT(*umtx = (void *)thisMutex); if (umtx != &globalUMTX) { umtx_destroy(umtx); } } umtx_destroy(&globalUMTX); pMutexInitFn = NULL; pMutexDestroyFn = NULL; pMutexLockFn = NULL; pMutexUnlockFn = NULL; gMutexContext = NULL; pIncFn = NULL; pDecFn = NULL; gIncDecContext = NULL; gIncDecMutex = NULL; #if defined (POSIX) /* POSIX platforms must come out of u_cleanup() with a functioning global mutex * to permit the safe resumption of use of ICU in multi-threaded environments. */ umtx_init(&globalUMTX); #endif return TRUE; }
U_CAPI void U_EXPORT2 umtx_init(UMTX *mutex) { #if (ICU_USE_THREADS == 1) if (mutex == NULL) /* initialize the global mutex */ { /* Note: The initialization of the global mutex is NOT thread safe. */ if (gGlobalMutex != NULL) { return; } gGlobalMutex = umtx_raw_init(&gPlatformMutex); # ifdef POSIX_DEBUG_REENTRANCY gInMutex = FALSE; # endif #ifdef _DEBUG gRecursionCount = 0; #endif #ifdef POSIX umtx_raw_init(&gIncDecMutex); #endif } else { /* Not the global mutex. * Thread safe initialization, using the global mutex. */ UBool isInitialized; UMTX tMutex = NULL; umtx_lock(NULL); isInitialized = (*mutex != NULL); umtx_unlock(NULL); if (isInitialized) { return; } tMutex = umtx_raw_init(NULL); umtx_lock(NULL); if (*mutex == NULL) { *mutex = tMutex; tMutex = NULL; } umtx_unlock(NULL); umtx_destroy(&tMutex); /* NOP if (tmutex == NULL) */ } #endif /* ICU_USE_THREADS==1 */ }
U_NAMESPACE_END U_CFUNC UBool calendar_islamic_cleanup(void) { if (gMonthCache) { delete gMonthCache; gMonthCache = NULL; } if (gIslamicCalendarAstro) { delete gIslamicCalendarAstro; gIslamicCalendarAstro = NULL; } umtx_destroy(&astroLock); return TRUE; }
U_NAMESPACE_END // Defined in ucln_in.h: U_CFUNC UBool utrans_transliterator_cleanup(void) { U_NAMESPACE_USE TransliteratorIDParser::cleanup(); if (registry) { delete registry; registry = NULL; } umtx_destroy(®istryMutex); return TRUE; }
/* Not supported API. Marked U_CAPI only for use by test programs. */ U_CFUNC UBool U_EXPORT2 ucnv_cleanup(void) { if (SHARED_DATA_HASHTABLE != NULL) { ucnv_flushCache(); if (SHARED_DATA_HASHTABLE != NULL && uhash_count(SHARED_DATA_HASHTABLE) == 0) { uhash_close(SHARED_DATA_HASHTABLE); SHARED_DATA_HASHTABLE = NULL; } } umtx_destroy(&cnvCacheMutex); /* Don't worry about destroying the mutex even */ /* if the hash table still exists. The mutex */ /* will lazily re-init itself if needed. */ return (SHARED_DATA_HASHTABLE == NULL); }
static UBool U_CALLCONV usprep_cleanup(void){ if (SHARED_DATA_HASHTABLE != NULL) { usprep_internal_flushCache(TRUE); if (SHARED_DATA_HASHTABLE != NULL && uhash_count(SHARED_DATA_HASHTABLE) == 0) { uhash_close(SHARED_DATA_HASHTABLE); SHARED_DATA_HASHTABLE = NULL; } } umtx_destroy(&usprepMutex); /* Don't worry about destroying the mutex even */ /* if the hash table still exists. The mutex */ /* will lazily re-init itself if needed. */ return (SHARED_DATA_HASHTABLE == NULL); }
U_CDECL_BEGIN static UBool U_CALLCONV timeZone_cleanup(void) { delete DEFAULT_ZONE; DEFAULT_ZONE = NULL; delete _GMT; _GMT = NULL; uprv_memset(TZDATA_VERSION, 0, sizeof(TZDATA_VERSION)); TZDataVersionInitialized = FALSE; if (LOCK) { umtx_destroy(&LOCK); LOCK = NULL; } if (TZSET_LOCK) { umtx_destroy(&TZSET_LOCK); TZSET_LOCK = NULL; } return TRUE; }
/************************************************ The cleanup order is important in this function. Please be sure that you have read ucln.h ************************************************/ U_CAPI void U_EXPORT2 u_cleanup(void) { ECleanupLibraryType libType; UTRACE_ENTRY_OC(UTRACE_U_CLEANUP); umtx_lock(NULL); /* Force a memory barrier, so that we are sure to see */ umtx_unlock(NULL); /* all state left around by any other threads. */ for (libType = UCLN_START+1; libType<UCLN_COMMON; libType++) { if (gCleanupFunctions[libType]) { gCleanupFunctions[libType](); gCleanupFunctions[libType] = NULL; } } #if !UCONFIG_NO_IDNA usprep_cleanup(); #endif #if !UCONFIG_NO_BREAK_ITERATION breakiterator_cleanup(); #endif #if !UCONFIG_NO_SERVICE service_cleanup(); #endif ures_cleanup(); locale_cleanup(); uloc_cleanup(); #if !UCONFIG_NO_NORMALIZATION unorm_cleanup(); #endif uset_cleanup(); unames_cleanup(); pname_cleanup(); uchar_cleanup(); ucnv_cleanup(); ucnv_io_cleanup(); udata_cleanup(); putil_cleanup(); umtx_destroy(&gICUInitMutex); umtx_cleanup(); cmemory_cleanup(); /* undo any heap functions set by u_setMemoryFunctions(). */ gICUInitialized = FALSE; UTRACE_EXIT(); /* Must be before utrace_cleanup(), which turns off tracing. */ utrace_cleanup(); }
/************************************************ The cleanup order is important in this function. Please be sure that you have read ucln.h ************************************************/ U_CAPI void U_EXPORT2 u_cleanup(void) { UTRACE_ENTRY_OC(UTRACE_U_CLEANUP); umtx_lock(NULL); /* Force a memory barrier, so that we are sure to see */ umtx_unlock(NULL); /* all state left around by any other threads. */ ucln_lib_cleanup(); umtx_destroy(&gICUInitMutex); umtx_cleanup(); cmemory_cleanup(); /* undo any heap functions set by u_setMemoryFunctions(). */ gICUInitialized = FALSE; UTRACE_EXIT(); /* Must be before utrace_cleanup(), which turns off tracing. */ /*#if U_ENABLE_TRACING*/ utrace_cleanup(); /*#endif*/ }
U_CDECL_BEGIN /** * Cleanup callback func */ static UBool U_CALLCONV zoneMeta_cleanup(void) { umtx_destroy(&gZoneMetaLock); if (gOlsonToMeta != NULL) { uhash_close(gOlsonToMeta); gOlsonToMeta = NULL; } gOlsonToMetaInitialized = FALSE; delete gSingleZoneCountries; delete gMultiZonesCountries; gCountryInfoVectorsInitialized = FALSE; return TRUE; }
U_CAPI void U_EXPORT2 u_setMutexFunctions(const void *context, UMtxInitFn *i, UMtxFn *d, UMtxFn *l, UMtxFn *u, UErrorCode *status) { if (U_FAILURE(*status)) { return; } /* Can not set a mutex function to a NULL value */ if (i==NULL || d==NULL || l==NULL || u==NULL) { *status = U_ILLEGAL_ARGUMENT_ERROR; return; } /* If ICU is not in an initial state, disallow this operation. */ if (cmemory_inUse()) { *status = U_INVALID_STATE_ERROR; return; } /* Kill any existing global mutex. POSIX platforms have a global mutex * even before any other part of ICU is initialized. */ umtx_destroy(&globalUMTX); /* Swap in the mutex function pointers. */ pMutexInitFn = i; pMutexDestroyFn = d; pMutexLockFn = l; pMutexUnlockFn = u; gMutexContext = context; #if defined (POSIX) /* POSIX platforms must have a pre-initialized global mutex * to allow other mutexes to initialize safely. */ umtx_init(&globalUMTX); #endif }
/* * umtx_destroy. Un-initialize a mutex, releasing any underlying resources * that it may be holding. Destroying an already destroyed * mutex has no effect. Unlike umtx_init(), this function * is not thread safe; two threads must not concurrently try to * destroy the same mutex. */ U_CAPI void U_EXPORT2 umtx_destroy(UMTX *mutex) { if (mutex == NULL) { /* destroy the global mutex */ mutex = &gGlobalMutex; } if (*mutex == NULL) { /* someone already did it. */ return; } /* The life of the inc/dec mutex is tied to that of the global mutex. */ if (mutex == &gGlobalMutex) { umtx_destroy(&gIncDecMutex); } if (pMutexDestroyFn != NULL) { /* Mutexes are being managed by the app. Call back to it for the destroy. */ (*pMutexDestroyFn)(gMutexContext, mutex); } else { #if (ICU_USE_THREADS == 1) /* Return this mutex to the pool of available mutexes, if it came from the * pool in the first place. */ /* TODO use pointer math here, instead of iterating! */ int i; for (i=0; i<MAX_MUTEXES; i++) { if (*mutex == &gMutexes[i]) { gMutexesInUse[i] = 0; break; } } #endif } *mutex = NULL; }
ICULocaleService::~ICULocaleService() { umtx_destroy(&llock); }
int main (int argc, char **argv) { // // Parse the command line options, and create the specified kind of test. // parseCommandLine(argc, argv); // // Fire off the requested number of parallel threads // if (gRunInfo.numThreads == 0) exit(0); gRunInfo.exitFlag = FALSE; gRunInfo.stopFlag = TRUE; // Will cause the new threads to block umtx_lock(&gStopMutex); gThreadInfo = new ThreadInfo[gRunInfo.numThreads]; int threadNum; for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) { gThreadInfo[threadNum].fThreadNum = threadNum; ThreadFuncs::startThread(threadMain, &gThreadInfo[threadNum]); } unsigned long startTime = ThreadFuncs::getCurrentMillis(); int elapsedSeconds = 0; int timeSinceCheck = 0; // // Unblock the threads. // gRunInfo.stopFlag = FALSE; // Unblocks the worker threads. umtx_unlock(&gStopMutex); // // Loop, watching the heartbeat of the worker threads. // Each second, // display "+" if all threads have completed at least one loop // display "." if some thread hasn't since previous "+" // Each "ctime" seconds, // Stop all the worker threads at the top of their loop, then // call the test's check function. // while (gRunInfo.totalTime == 0 || gRunInfo.totalTime > elapsedSeconds) { ThreadFuncs::Sleep(1000); // We sleep while threads do their work ... if (gRunInfo.quiet == false && gRunInfo.verbose == false) { char c = '+'; int threadNum; umtx_lock(&gInfoMutex); for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) { if (gThreadInfo[threadNum].fHeartBeat == false) { c = '.'; break; }; } umtx_unlock(&gInfoMutex); fputc(c, stdout); fflush(stdout); if (c == '+') for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) gThreadInfo[threadNum].fHeartBeat = false; } // // Update running times. // timeSinceCheck -= elapsedSeconds; elapsedSeconds = (ThreadFuncs::getCurrentMillis() - startTime) / 1000; timeSinceCheck += elapsedSeconds; // // Call back to the test to let it check its internal validity // if (timeSinceCheck >= gRunInfo.checkTime) { if (gRunInfo.verbose) { fprintf(stderr, "Main: suspending all threads\n"); } umtx_lock(&gStopMutex); // Block the worker threads at the top of their loop gRunInfo.stopFlag = TRUE; for (;;) { umtx_lock(&gInfoMutex); UBool done = gRunInfo.runningThreads == 0; umtx_unlock(&gInfoMutex); if (done) { break;} ThreadFuncs::yield(); } gRunInfo.fTest->check(); if (gRunInfo.quiet == false && gRunInfo.verbose == false) { fputc('C', stdout); } if (gRunInfo.verbose) { fprintf(stderr, "Main: starting all threads.\n"); } gRunInfo.stopFlag = FALSE; // Unblock the worker threads. umtx_unlock(&gStopMutex); timeSinceCheck = 0; } }; // // Time's up, we are done. (We only get here if this was a timed run) // Tell the threads to exit. // gRunInfo.exitFlag = true; for (;;) { umtx_lock(&gInfoMutex); UBool done = gRunInfo.runningThreads == 0; umtx_unlock(&gInfoMutex); if (done) { break;} ThreadFuncs::yield(); } // // Tally up the total number of cycles completed by each of the threads. // double totalCyclesCompleted = 0; for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) { totalCyclesCompleted += gThreadInfo[threadNum].fCycles; } double cyclesPerMinute = totalCyclesCompleted / (double(gRunInfo.totalTime) / double(60)); printf("\n%8.1f cycles per minute.", cyclesPerMinute); // // Memory should be clean coming out // delete gRunInfo.fTest; delete [] gThreadInfo; umtx_destroy(&gInfoMutex); umtx_destroy(&gStopMutex); u_cleanup(); return 0; }
void MultithreadTest::TestMutex() { // Start up the test threads. They should all pile up waiting on // gTestMutexA, which we (the main thread) hold until the test threads // all get there. gThreadsStarted = 0; gThreadsInMiddle = 0; gThreadsDone = 0; umtx_lock(&gTestMutexA); TestMutexThread *threads[TESTMUTEX_THREAD_COUNT]; int i; int32_t numThreadsStarted = 0; for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) { threads[i] = new TestMutexThread; if (threads[i]->start() != 0) { errln("Error starting thread %d", i); } else { numThreadsStarted++; } } if (numThreadsStarted == 0) { errln("No threads could be started for testing!"); return; } int patience = 0; while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) { if (patience++ > 24) { TSMTHREAD_FAIL("Patience Exceeded"); return; } SimpleThread::sleep(500); } // None of the test threads should have advanced past the first mutex. TSMTHREAD_ASSERT(gThreadsInMiddle==0); TSMTHREAD_ASSERT(gThreadsDone==0); // All of the test threads have made it to the first mutex. // We (the main thread) now let them advance to the second mutex, // where they should all pile up again. umtx_lock(&gTestMutexB); umtx_unlock(&gTestMutexA); patience = 0; while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) { if (patience++ > 24) { TSMTHREAD_FAIL("Patience Exceeded"); return; } SimpleThread::sleep(500); } TSMTHREAD_ASSERT(gThreadsDone==0); // All test threads made it to the second mutex. // Now let them proceed from there. They will all terminate. umtx_unlock(&gTestMutexB); patience = 0; while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) { if (patience++ > 24) { TSMTHREAD_FAIL("Patience Exceeded"); return; } SimpleThread::sleep(500); } // All threads made it by both mutexes. // Destroy the test mutexes. umtx_destroy(&gTestMutexA); umtx_destroy(&gTestMutexB); gTestMutexA=NULL; gTestMutexB=NULL; for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) { delete threads[i]; } }