hpmufn.c revision 6d5deb12725f146643d443090dfa11b206df528a
1f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling/******************************************************************** 2f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling * COPYRIGHT: 3f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling * Copyright (c) 2003-2009, International Business Machines Corporation and 4f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling * others. All Rights Reserved. 5f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling ********************************************************************/ 6f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling/* 7f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling* File hpmufn.c 8f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling* 9f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling*/ 10f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling 11f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling#include "unicode/utypes.h" 12f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling#include "unicode/putil.h" 13f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling#include "unicode/uclean.h" 14f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling#include "unicode/uchar.h" 15f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling#include "unicode/ures.h" 16f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling#include "cintltst.h" 17f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling#include "umutex.h" 18f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling#include "unicode/utrace.h" 19f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling#include <stdlib.h> 20f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling#include <string.h> 218a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong 22f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling/** 238e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberling * This should align the memory properly on any machine. 24f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling */ 25f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberlingtypedef union { 26f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling long t1; 27f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling double t2; 28f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling void *t3; 29f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling} ctest_AlignedMemory; 308a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong 318a2350a3d557465b53445685db0f9ac838cf90c5Angus Kongstatic void TestHeapFunctions(void); 32f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberlingstatic void TestMutexFunctions(void); 338a2350a3d557465b53445685db0f9ac838cf90c5Angus Kongstatic void TestIncDecFunctions(void); 347190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling 358a2350a3d557465b53445685db0f9ac838cf90c5Angus Kongvoid addHeapMutexTest(TestNode **root); 368a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong 377190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling 387190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberlingvoid 398a2350a3d557465b53445685db0f9ac838cf90c5Angus KongaddHeapMutexTest(TestNode** root) 408a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong{ 41f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling addTest(root, &TestHeapFunctions, "hpmufn/TestHeapFunctions" ); 42f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling addTest(root, &TestMutexFunctions, "hpmufn/TestMutexFunctions" ); 437190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling addTest(root, &TestIncDecFunctions, "hpmufn/TestIncDecFunctions"); 447190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling} 457190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling 467190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberlingstatic int32_t gMutexFailures = 0; 477190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling 487190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling#define TEST_STATUS(status, expected) \ 498a2350a3d557465b53445685db0f9ac838cf90c5Angus Kongif (status != expected) { \ 50f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberlinglog_err_status(status, "FAIL at %s:%d. Actual status = \"%s\"; Expected status = \"%s\"\n", \ 518a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong __FILE__, __LINE__, u_errorName(status), u_errorName(expected)); gMutexFailures++; } 527190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling 537190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling 547190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling#define TEST_ASSERT(expr) \ 557190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberlingif (!(expr)) { \ 567190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling log_err("FAILED Assertion \"" #expr "\" at %s:%d.\n", __FILE__, __LINE__); \ 577190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling gMutexFailures++; \ 587190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling} 597190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling 608a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong 61f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling/* These tests do cleanup and reinitialize ICU in the course of their operation. 62f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling * The ICU data directory must be preserved across these operations. 63f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling * Here is a helper function to assist with that. 648a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong */ 65f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberlingstatic char *safeGetICUDataDirectory() { 668a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong const char *dataDir = u_getDataDirectory(); /* Returned string vanashes with u_cleanup */ 678a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong char *retStr = NULL; 68f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (dataDir != NULL) { 69f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling retStr = (char *)malloc(strlen(dataDir)+1); 70f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling strcpy(retStr, dataDir); 717190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling } 727190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling return retStr; 73f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling} 748a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong 758a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong 768a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong 778a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong/* 788a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong * Test Heap Functions. 798a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong * Implemented on top of the standard malloc heap. 80f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling * All blocks increased in size by 8 to 16 bytes, and the poiner returned to ICU is 817190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling * offset up by 8 to 16, which should cause a good heap corruption if one of our "blocks" 827190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling * ends up being freed directly, without coming through us. 837190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling * Allocations are counted, to check that ICU actually does call back to us. 847190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberling */ 857190c6a9018e95ff0c49642442c7a069e16a6a7aSascha Haeberlingint gBlockCount = 0; 868a2350a3d557465b53445685db0f9ac838cf90c5Angus Kongconst void *gContext; 878a2350a3d557465b53445685db0f9ac838cf90c5Angus Kong 888a2350a3d557465b53445685db0f9ac838cf90c5Angus Kongstatic void * U_CALLCONV myMemAlloc(const void *context, size_t size) { 89f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling char *retPtr = (char *)malloc(size+sizeof(ctest_AlignedMemory)); 90f1f5186f7d3fd8bf35009d9e65a43914c664d82bSascha Haeberling if (retPtr != NULL) { 91 retPtr += sizeof(ctest_AlignedMemory); 92 } 93 gBlockCount ++; 94 return retPtr; 95} 96 97static void U_CALLCONV myMemFree(const void *context, void *mem) { 98 char *freePtr = (char *)mem; 99 if (freePtr != NULL) { 100 freePtr -= sizeof(ctest_AlignedMemory); 101 } 102 free(freePtr); 103} 104 105 106 107static void * U_CALLCONV myMemRealloc(const void *context, void *mem, size_t size) { 108 char *p = (char *)mem; 109 char *retPtr; 110 111 if (p!=NULL) { 112 p -= sizeof(ctest_AlignedMemory); 113 } 114 retPtr = realloc(p, size+sizeof(ctest_AlignedMemory)); 115 if (retPtr != NULL) { 116 p += sizeof(ctest_AlignedMemory); 117 } 118 return retPtr; 119} 120 121 122static void TestHeapFunctions() { 123 UErrorCode status = U_ZERO_ERROR; 124 UResourceBundle *rb = NULL; 125 char *icuDataDir; 126 UVersionInfo unicodeVersion = {0,0,0,0}; 127 128 icuDataDir = safeGetICUDataDirectory(); /* save icu data dir, so we can put it back 129 * after doing u_cleanup(). */ 130 131 132 /* Verify that ICU can be cleaned up and reinitialized successfully. 133 * Failure here usually means that some ICU service didn't clean up successfully, 134 * probably because some earlier test accidently left something open. */ 135 ctest_resetICU(); 136 137 /* Can not set memory functions if ICU is already initialized */ 138 u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, myMemFree, &status); 139 TEST_STATUS(status, U_INVALID_STATE_ERROR); 140 141 /* Un-initialize ICU */ 142 u_cleanup(); 143 144 /* Can not set memory functions with NULL values */ 145 status = U_ZERO_ERROR; 146 u_setMemoryFunctions(&gContext, NULL, myMemRealloc, myMemFree, &status); 147 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); 148 status = U_ZERO_ERROR; 149 u_setMemoryFunctions(&gContext, myMemAlloc, NULL, myMemFree, &status); 150 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); 151 status = U_ZERO_ERROR; 152 u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, NULL, &status); 153 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); 154 155 /* u_setMemoryFunctions() should work with null or non-null context pointer */ 156 status = U_ZERO_ERROR; 157 u_setMemoryFunctions(NULL, myMemAlloc, myMemRealloc, myMemFree, &status); 158 TEST_STATUS(status, U_ZERO_ERROR); 159 u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, myMemFree, &status); 160 TEST_STATUS(status, U_ZERO_ERROR); 161 162 163 /* After reinitializing ICU, we should not be able to set the memory funcs again. */ 164 status = U_ZERO_ERROR; 165 u_setDataDirectory(icuDataDir); 166 u_init(&status); 167 TEST_STATUS(status, U_ZERO_ERROR); 168 u_setMemoryFunctions(NULL, myMemAlloc, myMemRealloc, myMemFree, &status); 169 TEST_STATUS(status, U_INVALID_STATE_ERROR); 170 171 /* Doing ICU operations should cause allocations to come through our test heap */ 172 gBlockCount = 0; 173 status = U_ZERO_ERROR; 174 rb = ures_open(NULL, "es", &status); 175 TEST_STATUS(status, U_ZERO_ERROR); 176 if (gBlockCount == 0) { 177 log_err("Heap functions are not being called from ICU.\n"); 178 } 179 ures_close(rb); 180 181 /* Cleanup should put the heap back to its default implementation. */ 182 ctest_resetICU(); 183 u_getUnicodeVersion(unicodeVersion); 184 if (unicodeVersion[0] <= 0) { 185 log_err("Properties doesn't reinitialize without u_init.\n"); 186 } 187 status = U_ZERO_ERROR; 188 u_init(&status); 189 TEST_STATUS(status, U_ZERO_ERROR); 190 191 /* ICU operations should no longer cause allocations to come through our test heap */ 192 gBlockCount = 0; 193 status = U_ZERO_ERROR; 194 rb = ures_open(NULL, "fr", &status); 195 TEST_STATUS(status, U_ZERO_ERROR); 196 if (gBlockCount != 0) { 197 log_err("Heap functions did not reset after u_cleanup.\n"); 198 } 199 ures_close(rb); 200 free(icuDataDir); 201 202 ctest_resetICU(); 203} 204 205 206/* 207 * Test u_setMutexFunctions() 208 */ 209 210int gTotalMutexesInitialized = 0; /* Total number of mutexes created */ 211int gTotalMutexesActive = 0; /* Total mutexes created, but not destroyed */ 212int gAccumulatedLocks = 0; 213const void *gMutexContext; 214 215typedef struct DummyMutex { 216 int fLockCount; 217 int fMagic; 218} DummyMutex; 219 220 221static void U_CALLCONV myMutexInit(const void *context, UMTX *mutex, UErrorCode *status) { 222 DummyMutex *theMutex; 223 224 TEST_STATUS(*status, U_ZERO_ERROR); 225 theMutex = (DummyMutex *)malloc(sizeof(DummyMutex)); 226 theMutex->fLockCount = 0; 227 theMutex->fMagic = 123456; 228 gTotalMutexesInitialized++; 229 gTotalMutexesActive++; 230 gMutexContext = context; 231 *mutex = theMutex; 232} 233 234 235static void U_CALLCONV myMutexDestroy(const void *context, UMTX *mutex) { 236 DummyMutex *This = *(DummyMutex **)mutex; 237 238 gTotalMutexesActive--; 239 TEST_ASSERT(This->fLockCount == 0); 240 TEST_ASSERT(This->fMagic == 123456); 241 This->fMagic = 0; 242 This->fLockCount = 0; 243 free(This); 244} 245 246static void U_CALLCONV myMutexLock(const void *context, UMTX *mutex) { 247 DummyMutex *This = *(DummyMutex **)mutex; 248 249 TEST_ASSERT(This->fMagic == 123456); 250 This->fLockCount++; 251 gAccumulatedLocks++; 252} 253 254static void U_CALLCONV myMutexUnlock(const void *context, UMTX *mutex) { 255 DummyMutex *This = *(DummyMutex **)mutex; 256 257 TEST_ASSERT(This->fMagic == 123456); 258 This->fLockCount--; 259 TEST_ASSERT(This->fLockCount >= 0); 260} 261 262 263 264static void TestMutexFunctions() { 265 UErrorCode status = U_ZERO_ERROR; 266 UResourceBundle *rb = NULL; 267 char *icuDataDir; 268 269 gMutexFailures = 0; 270 271 /* Save initial ICU state so that it can be restored later. 272 * u_cleanup(), which is called in this test, resets ICU's state. 273 */ 274 icuDataDir = safeGetICUDataDirectory(); 275 276 /* Verify that ICU can be cleaned up and reinitialized successfully. 277 * Failure here usually means that some ICU service didn't clean up successfully, 278 * probably because some earlier test accidently left something open. */ 279 ctest_resetICU(); 280 281 /* Can not set mutex functions if ICU is already initialized */ 282 u_setMutexFunctions(&gContext, myMutexInit, myMutexDestroy, myMutexLock, myMutexUnlock, &status); 283 TEST_STATUS(status, U_INVALID_STATE_ERROR); 284 285 /* Un-initialize ICU */ 286 u_cleanup(); 287 288 /* Can not set Mutex functions with NULL values */ 289 status = U_ZERO_ERROR; 290 u_setMutexFunctions(&gContext, NULL, myMutexDestroy, myMutexLock, myMutexUnlock, &status); 291 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); 292 status = U_ZERO_ERROR; 293 u_setMutexFunctions(&gContext, myMutexInit, NULL, myMutexLock, myMutexUnlock, &status); 294 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); 295 status = U_ZERO_ERROR; 296 u_setMutexFunctions(&gContext, myMutexInit, myMutexDestroy, NULL, myMutexUnlock, &status); 297 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); 298 status = U_ZERO_ERROR; 299 u_setMutexFunctions(&gContext, myMutexInit, myMutexDestroy, myMutexLock, NULL, &status); 300 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); 301 302 /* u_setMutexFunctions() should work with null or non-null context pointer */ 303 status = U_ZERO_ERROR; 304 u_setMutexFunctions(&gContext, myMutexInit, myMutexDestroy, myMutexLock, myMutexUnlock, &status); 305 TEST_STATUS(status, U_ZERO_ERROR); 306 u_setMutexFunctions(&gContext, myMutexInit, myMutexDestroy, myMutexLock, myMutexUnlock, &status); 307 TEST_STATUS(status, U_ZERO_ERROR); 308 309 310 /* After reinitializing ICU, we should not be able to set the mutex funcs again. */ 311 status = U_ZERO_ERROR; 312 u_setDataDirectory(icuDataDir); 313 u_init(&status); 314 TEST_STATUS(status, U_ZERO_ERROR); 315 u_setMutexFunctions(&gContext, myMutexInit, myMutexDestroy, myMutexLock, myMutexUnlock, &status); 316 TEST_STATUS(status, U_INVALID_STATE_ERROR); 317 318 /* Doing ICU operations should cause allocations to come through our test mutexes */ 319 gBlockCount = 0; 320 status = U_ZERO_ERROR; 321 rb = ures_open(NULL, "es", &status); 322 TEST_STATUS(status, U_ZERO_ERROR); 323 TEST_ASSERT(gTotalMutexesInitialized > 0); 324 TEST_ASSERT(gTotalMutexesActive > 0); 325 326 ures_close(rb); 327 328 /* Cleanup should destroy all of the mutexes. */ 329 ctest_resetICU(); 330 status = U_ZERO_ERROR; 331 TEST_ASSERT(gTotalMutexesInitialized > 0); 332 TEST_ASSERT(gTotalMutexesActive == 0); 333 334 335 /* Additional ICU operations should no longer use our dummy test mutexes */ 336 gTotalMutexesInitialized = 0; 337 gTotalMutexesActive = 0; 338 u_init(&status); 339 TEST_STATUS(status, U_ZERO_ERROR); 340 341 status = U_ZERO_ERROR; 342 rb = ures_open(NULL, "fr", &status); 343 TEST_STATUS(status, U_ZERO_ERROR); 344 TEST_ASSERT(gTotalMutexesInitialized == 0); 345 TEST_ASSERT(gTotalMutexesActive == 0); 346 347 ures_close(rb); 348 free(icuDataDir); 349 350 if(gMutexFailures) { 351 log_info("Note: these failures may be caused by ICU failing to initialize/uninitialize properly.\n"); 352 log_verbose("Check for prior tests which may not have closed all open resources. See the internal function ures_flushCache()\n"); 353 } 354} 355 356 357 358 359/* 360 * Test Atomic Increment & Decrement Functions 361 */ 362 363int gIncCount = 0; 364int gDecCount = 0; 365const void *gIncDecContext; 366const void *gExpectedContext = &gIncDecContext; 367 368 369static int32_t U_CALLCONV myIncFunc(const void *context, int32_t *p) { 370 int32_t retVal; 371 TEST_ASSERT(context == gExpectedContext); 372 gIncCount++; 373 retVal = ++(*p); 374 return retVal; 375} 376 377static int32_t U_CALLCONV myDecFunc(const void *context, int32_t *p) { 378 int32_t retVal; 379 TEST_ASSERT(context == gExpectedContext); 380 gDecCount++; 381 retVal = --(*p); 382 return retVal; 383} 384 385 386 387 388static void TestIncDecFunctions() { 389 UErrorCode status = U_ZERO_ERROR; 390 int32_t t = 1; /* random value to make sure that Inc/dec works */ 391 char *dataDir; 392 393 /* Save ICU's data dir and tracing functions so that they can be resored 394 after cleanup and reinit. */ 395 dataDir = safeGetICUDataDirectory(); 396 397 /* Verify that ICU can be cleaned up and reinitialized successfully. 398 * Failure here usually means that some ICU service didn't clean up successfully, 399 * probably because some earlier test accidently left something open. */ 400 ctest_resetICU(); 401 402 /* Can not set mutex functions if ICU is already initialized */ 403 u_setAtomicIncDecFunctions(&gIncDecContext, myIncFunc, myDecFunc, &status); 404 TEST_STATUS(status, U_INVALID_STATE_ERROR); 405 406 /* Clean up ICU */ 407 u_cleanup(); 408 409 /* Can not set functions with NULL values */ 410 status = U_ZERO_ERROR; 411 u_setAtomicIncDecFunctions(&gIncDecContext, NULL, myDecFunc, &status); 412 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); 413 status = U_ZERO_ERROR; 414 u_setAtomicIncDecFunctions(&gIncDecContext, myIncFunc, NULL, &status); 415 TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR); 416 417 /* u_setIncDecFunctions() should work with null or non-null context pointer */ 418 status = U_ZERO_ERROR; 419 gExpectedContext = NULL; 420 u_setAtomicIncDecFunctions(NULL, myIncFunc, myDecFunc, &status); 421 TEST_STATUS(status, U_ZERO_ERROR); 422 gExpectedContext = &gIncDecContext; 423 u_setAtomicIncDecFunctions(&gIncDecContext, myIncFunc, myDecFunc, &status); 424 TEST_STATUS(status, U_ZERO_ERROR); 425 426 427 /* After reinitializing ICU, we should not be able to set the inc/dec funcs again. */ 428 status = U_ZERO_ERROR; 429 u_setDataDirectory(dataDir); 430 u_init(&status); 431 TEST_STATUS(status, U_ZERO_ERROR); 432 gExpectedContext = &gIncDecContext; 433 u_setAtomicIncDecFunctions(&gIncDecContext, myIncFunc, myDecFunc, &status); 434 TEST_STATUS(status, U_INVALID_STATE_ERROR); 435 436 /* Doing ICU operations should cause our functions to be called */ 437 gIncCount = 0; 438 gDecCount = 0; 439 umtx_atomic_inc(&t); 440 TEST_ASSERT(t == 2); 441 umtx_atomic_dec(&t); 442 TEST_ASSERT(t == 1); 443 TEST_ASSERT(gIncCount > 0); 444 TEST_ASSERT(gDecCount > 0); 445 446 447 /* Cleanup should cancel use of our inc/dec functions. */ 448 /* Additional ICU operations should not use them */ 449 ctest_resetICU(); 450 gIncCount = 0; 451 gDecCount = 0; 452 status = U_ZERO_ERROR; 453 u_setDataDirectory(dataDir); 454 u_init(&status); 455 TEST_ASSERT(gIncCount == 0); 456 TEST_ASSERT(gDecCount == 0); 457 458 status = U_ZERO_ERROR; 459 umtx_atomic_inc(&t); 460 umtx_atomic_dec(&t); 461 TEST_STATUS(status, U_ZERO_ERROR); 462 TEST_ASSERT(gIncCount == 0); 463 TEST_ASSERT(gDecCount == 0); 464 465 free(dataDir); 466} 467 468