diff --git a/icu4c/source/common/ucln_cmn.c b/icu4c/source/common/ucln_cmn.c index 9a06d2ae82..827e4828c2 100644 --- a/icu4c/source/common/ucln_cmn.c +++ b/icu4c/source/common/ucln_cmn.c @@ -15,6 +15,7 @@ */ #include "unicode/uclean.h" +#include "unicode/uchar.h" #include "ucln_cmn.h" #include "umutex.h" #include "ucln.h" @@ -82,3 +83,46 @@ u_cleanup(void) umtx_destroy(NULL); } + +static UMTX InitMutex = NULL; + +U_CAPI void U_EXPORT2 +u_init(UErrorCode *status) { + /* + * Lock and unlock the global mutex, thus forcing into existence + * if it hasn't already been created. + */ + umtx_lock(NULL); + umtx_unlock(NULL); + + + /* Lock a private mutex for the duration of the initialization, + * ensuring that there are no races through here, and to serve as + * a memory barrier. Don't use the global mutex, because of the + * possibility that some of the functions called within here might + * use it. + */ + umtx_lock(&InitMutex); + + /* + * Do a simple operation using each of the data-requiring APIs that do + * not have a service object, ensuring that the required data is loaded. + */ + + + /* Char Properties */ + u_hasBinaryProperty(0x20, UCHAR_WHITE_SPACE); + + /* Char Names */ + { + char buf[100]; + u_charName(0x20, U_UNICODE_CHAR_NAME, buf, 100, status); + } + + + /* TODO: the rest of 'em */ + + + umtx_unlock(&InitMutex); + +} diff --git a/icu4c/source/common/unicode/uclean.h b/icu4c/source/common/unicode/uclean.h index f0319cb3f2..70cd8fe555 100644 --- a/icu4c/source/common/unicode/uclean.h +++ b/icu4c/source/common/unicode/uclean.h @@ -19,6 +19,31 @@ #include "unicode/utypes.h" +/** + * Initialize ICU. This function loads and initializes data items + * that are required internally by various ICU functions. Use of this explicit + * initialization is required in multi-threaded applications; in + * single threaded apps, use is optional, but incurs little additional + * cost, and is thus recommended. + *

+ * In multi-threaded applications, u_init() should be called in the + * main thread before starting additional threads, or, alternatively + * it can be called in each individual thread once, before other ICU + * functions are called in that thread. In this second scenario, the + * application must guarantee that the first call to u_init() happen + * without contention, in a single thread only. + *

+ * Extra, repeated, or otherwise unneeded calls to u_init() do no harm, + * other taking a small amount of time. + * + * @param pErrorCode An ICU UErrorCode parameter. It must not be NULL. + * An Error will be retuned if some required part of ICU data can not + * be loaded or initialized. + * + */ +U_CAPI void U_EXPORT2 +u_init(UErrorCode *status); + /** * Clean up the system resources, such as allocated memory or open files, * used in all ICU libraries. This will free/delete all memory owned by the @@ -39,10 +64,10 @@ * results. *

* After calling u_cleanup(), an application may continue to use ICU by - * creating an ICU C++ object or opening new items (converters, collators, - * etc.) and using them. An application must use ICU from one single - * thread before allowing other threads or processes from using ICU. This - * is so that the ICU libraries can reinitialize in a thread safe manner. + * calling u_init(). An application must invoke u_init() first from one single + * thread before allowing other threads call u_init(). All threads existing + * at the time of the first thread's call to u_init() must also call + * u_init() themselves before continuing with other ICU operations. *

* The use of u_cleanup() just before an application terminates is optional, * but it should be called only once for performance reasons. The primary diff --git a/icu4c/source/test/intltest/intltest.cpp b/icu4c/source/test/intltest/intltest.cpp index e69f3ad7dc..7bb44d8b3d 100644 --- a/icu4c/source/test/intltest/intltest.cpp +++ b/icu4c/source/test/intltest/intltest.cpp @@ -1064,6 +1064,19 @@ main(int argc, char* argv[]) fprintf(stdout, " Leaks (l) : %s\n", (leaks? "On" : "Off")); fprintf(stdout, "-----------------------------------------------\n"); + // Check that u_init() works + errorCode = U_ZERO_ERROR; + u_init(&errorCode); + if (U_FAILURE(errorCode)) { + fprintf(stdout, + "*** u_init() failed with error code = %s\n" + "*** Check the ICU_DATA environment variable and\n" + "*** check that the data files are present.\n", + u_errorName(errorCode)); + return 1; + } + + // initial check for the default converter errorCode = U_ZERO_ERROR; cnv = ucnv_open(0, &errorCode);