]>
git.saurik.com Git - apple/icu.git/blob - icuSources/test/cintltst/hpmufn.c
1 /********************************************************************
3 * Copyright (c) 200-20043, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
11 #include "unicode/utypes.h"
12 #include "unicode/putil.h"
13 #include "unicode/uclean.h"
14 #include "unicode/uchar.h"
15 #include "unicode/ures.h"
18 #include "unicode/utrace.h"
23 * This should align the memory properly on any machine.
29 } ctest_AlignedMemory
;
31 static void TestHeapFunctions(void);
32 static void TestMutexFunctions(void);
33 static void TestIncDecFunctions(void);
35 void addHeapMutexTest(TestNode
**root
);
39 addHeapMutexTest(TestNode
** root
)
41 addTest(root
, &TestHeapFunctions
, "tsutil/hpmufn/TestHeapFunctions" );
42 addTest(root
, &TestMutexFunctions
, "tsutil/hpmufn/TestMutexFunctions" );
43 addTest(root
, &TestIncDecFunctions
, "tsutil/hpmufn/TestIncDecFunctions");
46 static int32_t gMutexFailures
= 0;
48 #define TEST_STATUS(status, expected) \
49 if (status != expected) { \
50 log_err("FAIL at %s:%d. Actual status = \"%s\"; Expected status = \"%s\"\n", \
51 __FILE__, __LINE__, u_errorName(status), u_errorName(expected)); gMutexFailures++; }
54 #define TEST_ASSERT(expr) \
56 log_err("FAILED Assertion \"" #expr "\" at %s:%d.\n", __FILE__, __LINE__); \
61 /* These tests do cleanup and reinitialize ICU in the course of their operation.
62 * The ICU data directory must be preserved across these operations.
63 * Here is a helper function to assist with that.
65 static char *safeGetICUDataDirectory() {
66 const char *dataDir
= u_getDataDirectory(); /* Returned string vanashes with u_cleanup */
68 if (dataDir
!= NULL
) {
69 retStr
= (char *)malloc(strlen(dataDir
)+1);
70 strcpy(retStr
, dataDir
);
78 * Test Heap Functions.
79 * Implemented on top of the standard malloc heap.
80 * All blocks increased in size by 8 to 16 bytes, and the poiner returned to ICU is
81 * offset up by 8 to 16, which should cause a good heap corruption if one of our "blocks"
82 * ends up being freed directly, without coming through us.
83 * Allocations are counted, to check that ICU actually does call back to us.
88 static void * U_CALLCONV
myMemAlloc(const void *context
, size_t size
) {
89 char *retPtr
= (char *)malloc(size
+sizeof(ctest_AlignedMemory
));
91 retPtr
+= sizeof(ctest_AlignedMemory
);
97 static void U_CALLCONV
myMemFree(const void *context
, void *mem
) {
98 char *freePtr
= (char *)mem
;
99 if (freePtr
!= NULL
) {
100 freePtr
-= sizeof(ctest_AlignedMemory
);
107 static void * U_CALLCONV
myMemRealloc(const void *context
, void *mem
, size_t size
) {
108 char *p
= (char *)mem
;
112 p
-= sizeof(ctest_AlignedMemory
);
114 retPtr
= realloc(p
, size
+sizeof(ctest_AlignedMemory
));
115 if (retPtr
!= NULL
) {
116 p
+= sizeof(ctest_AlignedMemory
);
122 static void TestHeapFunctions() {
123 UErrorCode status
= U_ZERO_ERROR
;
124 UResourceBundle
*rb
= NULL
;
127 UTraceEntry
*traceEntryFunc
; /* Tracing function ptrs. We need to save */
128 UTraceExit
*traceExitFunc
; /* and restore them across calls to */
129 UTraceData
*traceDataFunc
; /* u_cleanup() that we make in this test. */
130 const void *traceContext
;
133 icuDataDir
= safeGetICUDataDirectory(); /* save icu data dir, so we can put it back
134 * after doing u_cleanup(). */
136 utrace_getFunctions(&traceContext
, &traceEntryFunc
, &traceExitFunc
, &traceDataFunc
);
137 traceLevel
= utrace_getLevel();
139 /* Can not set memory functions if ICU is already initialized */
140 u_setMemoryFunctions(&gContext
, myMemAlloc
, myMemRealloc
, myMemFree
, &status
);
141 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
143 /* Un-initialize ICU */
145 utrace_setFunctions(traceContext
, traceEntryFunc
, traceExitFunc
, traceDataFunc
);
146 utrace_setLevel(traceLevel
);
148 /* Can not set memory functions with NULL values */
149 status
= U_ZERO_ERROR
;
150 u_setMemoryFunctions(&gContext
, NULL
, myMemRealloc
, myMemFree
, &status
);
151 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
152 status
= U_ZERO_ERROR
;
153 u_setMemoryFunctions(&gContext
, myMemAlloc
, NULL
, myMemFree
, &status
);
154 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
155 status
= U_ZERO_ERROR
;
156 u_setMemoryFunctions(&gContext
, myMemAlloc
, myMemRealloc
, NULL
, &status
);
157 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
159 /* u_setMemoryFunctions() should work with null or non-null context pointer */
160 status
= U_ZERO_ERROR
;
161 u_setMemoryFunctions(NULL
, myMemAlloc
, myMemRealloc
, myMemFree
, &status
);
162 TEST_STATUS(status
, U_ZERO_ERROR
);
163 u_setMemoryFunctions(&gContext
, myMemAlloc
, myMemRealloc
, myMemFree
, &status
);
164 TEST_STATUS(status
, U_ZERO_ERROR
);
167 /* After reinitializing ICU, we should not be able to set the memory funcs again. */
168 status
= U_ZERO_ERROR
;
169 u_setDataDirectory(icuDataDir
);
171 TEST_STATUS(status
, U_ZERO_ERROR
);
172 u_setMemoryFunctions(NULL
, myMemAlloc
, myMemRealloc
, myMemFree
, &status
);
173 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
175 /* Doing ICU operations should cause allocations to come through our test heap */
177 status
= U_ZERO_ERROR
;
178 rb
= ures_open(NULL
, "es", &status
);
179 TEST_STATUS(status
, U_ZERO_ERROR
);
180 if (gBlockCount
== 0) {
181 log_err("Heap functions are not being called from ICU.\n");
185 /* Cleanup should put the heap back to its default implementation. */
187 utrace_setFunctions(traceContext
, traceEntryFunc
, traceExitFunc
, traceDataFunc
);
188 utrace_setLevel(traceLevel
);
189 u_setDataDirectory(icuDataDir
);
190 status
= U_ZERO_ERROR
;
192 TEST_STATUS(status
, U_ZERO_ERROR
);
194 /* ICU operations should no longer cause allocations to come through our test heap */
196 status
= U_ZERO_ERROR
;
197 rb
= ures_open(NULL
, "fr", &status
);
198 TEST_STATUS(status
, U_ZERO_ERROR
);
199 if (gBlockCount
!= 0) {
200 log_err("Heap functions did not reset after u_cleanup.\n");
208 * Test u_setMutexFunctions()
211 int gTotalMutexesInitialized
= 0; /* Total number of mutexes created */
212 int gTotalMutexesActive
= 0; /* Total mutexes created, but not destroyed */
213 int gAccumulatedLocks
= 0;
214 const void *gMutexContext
;
216 typedef struct DummyMutex
{
222 static void U_CALLCONV
myMutexInit(const void *context
, UMTX
*mutex
, UErrorCode
*status
) {
223 DummyMutex
*theMutex
;
225 TEST_STATUS(*status
, U_ZERO_ERROR
);
226 theMutex
= (DummyMutex
*)malloc(sizeof(DummyMutex
));
227 theMutex
->fLockCount
= 0;
228 theMutex
->fMagic
= 123456;
229 gTotalMutexesInitialized
++;
230 gTotalMutexesActive
++;
231 gMutexContext
= context
;
236 static void U_CALLCONV
myMutexDestroy(const void *context
, UMTX
*mutex
) {
237 DummyMutex
*This
= *(DummyMutex
**)mutex
;
239 gTotalMutexesActive
--;
240 TEST_ASSERT(This
->fLockCount
== 0);
241 TEST_ASSERT(This
->fMagic
== 123456);
243 This
->fLockCount
= 0;
247 static void U_CALLCONV
myMutexLock(const void *context
, UMTX
*mutex
) {
248 DummyMutex
*This
= *(DummyMutex
**)mutex
;
250 TEST_ASSERT(This
->fMagic
== 123456);
255 static void U_CALLCONV
myMutexUnlock(const void *context
, UMTX
*mutex
) {
256 DummyMutex
*This
= *(DummyMutex
**)mutex
;
258 TEST_ASSERT(This
->fMagic
== 123456);
260 TEST_ASSERT(This
->fLockCount
>= 0);
265 static void TestMutexFunctions() {
266 UErrorCode status
= U_ZERO_ERROR
;
267 UResourceBundle
*rb
= NULL
;
270 UTraceEntry
*traceEntryFunc
; /* Tracing function ptrs. We need to save */
271 UTraceExit
*traceExitFunc
; /* and restore them across calls to */
272 UTraceData
*traceDataFunc
; /* u_cleanup() that we make in this test. */
273 const void *traceContext
;
278 /* Save initial ICU state so that it can be restored later.
279 * u_cleanup(), which is called in this test, resets ICU's state.
281 icuDataDir
= safeGetICUDataDirectory();
282 utrace_getFunctions(&traceContext
, &traceEntryFunc
, &traceExitFunc
, &traceDataFunc
);
283 traceLevel
= utrace_getLevel();
285 /* Can not set mutex functions if ICU is already initialized */
286 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, myMutexLock
, myMutexUnlock
, &status
);
287 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
289 /* Un-initialize ICU */
291 utrace_setFunctions(traceContext
, traceEntryFunc
, traceExitFunc
, traceDataFunc
);
292 utrace_setLevel(traceLevel
);
294 /* Can not set Mutex functions with NULL values */
295 status
= U_ZERO_ERROR
;
296 u_setMutexFunctions(&gContext
, NULL
, myMutexDestroy
, myMutexLock
, myMutexUnlock
, &status
);
297 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
298 status
= U_ZERO_ERROR
;
299 u_setMutexFunctions(&gContext
, myMutexInit
, NULL
, myMutexLock
, myMutexUnlock
, &status
);
300 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
301 status
= U_ZERO_ERROR
;
302 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, NULL
, myMutexUnlock
, &status
);
303 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
304 status
= U_ZERO_ERROR
;
305 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, myMutexLock
, NULL
, &status
);
306 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
308 /* u_setMutexFunctions() should work with null or non-null context pointer */
309 status
= U_ZERO_ERROR
;
310 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, myMutexLock
, myMutexUnlock
, &status
);
311 TEST_STATUS(status
, U_ZERO_ERROR
);
312 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, myMutexLock
, myMutexUnlock
, &status
);
313 TEST_STATUS(status
, U_ZERO_ERROR
);
316 /* After reinitializing ICU, we should not be able to set the mutex funcs again. */
317 status
= U_ZERO_ERROR
;
318 u_setDataDirectory(icuDataDir
);
320 TEST_STATUS(status
, U_ZERO_ERROR
);
321 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, myMutexLock
, myMutexUnlock
, &status
);
322 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
324 /* Doing ICU operations should cause allocations to come through our test mutexes */
326 status
= U_ZERO_ERROR
;
327 rb
= ures_open(NULL
, "es", &status
);
328 TEST_STATUS(status
, U_ZERO_ERROR
);
329 TEST_ASSERT(gTotalMutexesInitialized
> 0);
330 TEST_ASSERT(gTotalMutexesActive
> 0);
334 /* Cleanup should destroy all of the mutexes. */
336 u_setDataDirectory(icuDataDir
);
337 utrace_setFunctions(traceContext
, traceEntryFunc
, traceExitFunc
, traceDataFunc
);
338 utrace_setLevel(traceLevel
);
339 status
= U_ZERO_ERROR
;
340 TEST_ASSERT(gTotalMutexesInitialized
> 0);
341 TEST_ASSERT(gTotalMutexesActive
== 0);
344 /* Additional ICU operations should no longer use our dummy test mutexes */
345 gTotalMutexesInitialized
= 0;
346 gTotalMutexesActive
= 0;
348 TEST_STATUS(status
, U_ZERO_ERROR
);
350 status
= U_ZERO_ERROR
;
351 rb
= ures_open(NULL
, "fr", &status
);
352 TEST_STATUS(status
, U_ZERO_ERROR
);
353 TEST_ASSERT(gTotalMutexesInitialized
== 0);
354 TEST_ASSERT(gTotalMutexesActive
== 0);
360 log_info("Note: these failures may be caused by ICU failing to initialize/uninitialize properly.\n");
361 log_verbose("Check for prior tests which may not have closed all open resources. See the internal function ures_flushCache()\n");
369 * Test Atomic Increment & Decrement Functions
374 const void *gIncDecContext
;
377 static int32_t U_CALLCONV
myIncFunc(const void *context
, int32_t *p
) {
379 TEST_ASSERT(context
== gIncDecContext
);
385 static int32_t U_CALLCONV
myDecFunc(const void *context
, int32_t *p
) {
387 TEST_ASSERT(context
== gIncDecContext
);
396 static void TestIncDecFunctions() {
397 UErrorCode status
= U_ZERO_ERROR
;
398 int32_t t
= 1; /* random value to make sure that Inc/dec works */
401 UTraceEntry
*traceEntryFunc
; /* Tracing function ptrs. We need to save */
402 UTraceExit
*traceExitFunc
; /* and restore them across calls to */
403 UTraceData
*traceDataFunc
; /* u_cleanup() that we make in this test. */
404 const void *traceContext
;
407 /* Can not set mutex functions if ICU is already initialized */
408 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, myDecFunc
, &status
);
409 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
411 /* Un-initialize ICU */
412 dataDir
= safeGetICUDataDirectory();
413 utrace_getFunctions(&traceContext
, &traceEntryFunc
, &traceExitFunc
, &traceDataFunc
);
414 traceLevel
= utrace_getLevel();
416 utrace_setFunctions(traceContext
, traceEntryFunc
, traceExitFunc
, traceDataFunc
);
417 utrace_setLevel(traceLevel
);
419 /* Can not set functions with NULL values */
420 status
= U_ZERO_ERROR
;
421 u_setAtomicIncDecFunctions(&gIncDecContext
, NULL
, myDecFunc
, &status
);
422 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
423 status
= U_ZERO_ERROR
;
424 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, NULL
, &status
);
425 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
427 /* u_setIncDecFunctions() should work with null or non-null context pointer */
428 status
= U_ZERO_ERROR
;
429 u_setAtomicIncDecFunctions(NULL
, myIncFunc
, myDecFunc
, &status
);
430 TEST_STATUS(status
, U_ZERO_ERROR
);
431 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, myDecFunc
, &status
);
432 TEST_STATUS(status
, U_ZERO_ERROR
);
435 /* After reinitializing ICU, we should not be able to set the inc/dec funcs again. */
436 status
= U_ZERO_ERROR
;
437 u_setDataDirectory(dataDir
);
439 TEST_STATUS(status
, U_ZERO_ERROR
);
440 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, myDecFunc
, &status
);
441 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
443 /* Doing ICU operations should cause our functions to be called */
450 TEST_ASSERT(gIncCount
> 0);
451 TEST_ASSERT(gDecCount
> 0);
454 /* Cleanup should cancel use of our inc/dec functions. */
455 /* Additional ICU operations should not use them */
457 utrace_setFunctions(traceContext
, traceEntryFunc
, traceExitFunc
, traceDataFunc
);
458 utrace_setLevel(traceLevel
);
461 status
= U_ZERO_ERROR
;
462 u_setDataDirectory(dataDir
);
464 TEST_ASSERT(gIncCount
== 0);
465 TEST_ASSERT(gDecCount
== 0);
467 status
= U_ZERO_ERROR
;
470 TEST_STATUS(status
, U_ZERO_ERROR
);
471 TEST_ASSERT(gIncCount
== 0);
472 TEST_ASSERT(gDecCount
== 0);