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