diff --git a/Frameworks/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c b/Frameworks/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c
index 6ca3a0d0c3..546673b52c 100644
--- a/Frameworks/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c
+++ b/Frameworks/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c
@@ -531,6 +531,10 @@ CF_PRIVATE CFArrayRef _CFBundleCopyUserLanguages() {
static CFArrayRef _CFBundleUserLanguages = NULL;
static dispatch_once_t once = 0;
dispatch_once(&once, ^{
+// WINOBJC: __CFAppleLanguages does not exist on Windows
+#if DEPLOYMENT_TARGET_WINDOWS
+ _CFBundleUserLanguages = CFLocaleCopyPreferredLanguages();
+#else
CFArrayRef preferencesArray = NULL;
if (__CFAppleLanguages) {
CFDataRef data;
@@ -555,6 +559,7 @@ CF_PRIVATE CFArrayRef _CFBundleCopyUserLanguages() {
_CFBundleUserLanguages = NULL;
}
if (preferencesArray) CFRelease(preferencesArray);
+#endif
});
if (_CFBundleUserLanguages) {
@@ -663,8 +668,66 @@ static CFStringRef _CFBundleCopyLanguageFoundInLocalizations(CFArrayRef localiza
return NULL;
}
+// WINOBJC: Helper functions for workaround in _CFBundleCreateMutableArrayOfFallbackLanguages
+static CFStringRef _copyStringTruncated(CFStringRef localization, CFRange cutoff) {
+ return CFStringCreateWithSubstring(NULL, localization, CFRangeMake(0, cutoff.location));
+}
+
+static CFStringRef _copyStringWithUnderscores(CFStringRef localization) {
+ CFMutableStringRef underscoredString = CFStringCreateMutableCopy(NULL, 0, localization);
+ CFStringFindAndReplace(underscoredString, CFSTR("-"), CFSTR("_"), CFRangeMake(0, CFStringGetLength(underscoredString)), 0);
+ return underscoredString;
+}
+
// Given a list of localizations (e.g., provided as argument to API, or present as .lproj directories), return a mutable array of localizations in preferred order. Returns NULL if nothing is found.
static CFMutableArrayRef _CFBundleCreateMutableArrayOfFallbackLanguages(CFArrayRef availableLocalizations, CFArrayRef preferredLocalizations) {
+// WINOBJC: The API that performs the work described below does not exist in our 3rd party libraries. ualoc_ is an Apple ICU addition.
+#if DEPLOYMENT_TARGET_WINDOWS
+ // Here we need to intersect the preferred languages with the available localizations
+ // We know the user languages are in preferred order, add to this list in this order
+ // Prefer the full language locale, attempt to convert any hyphens to underscores as
+ // Windows language settings are retrieved with hyphens while underscores are commonly used for localization.
+ // Finally, attempt to truncate any underscores from the language to find a base localization.
+ // For example, an english locale will appear as "en-US" and a German locale will appear as "de-DE".
+ // A localization for "en-US" may be set up as "en-US", "en_US", or even just "en".
+
+ CFMutableArrayRef resultArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
+
+ for (CFIndex i = 0, preferredCount = CFArrayGetCount(preferredLocalizations); i < preferredCount; i++) {
+ CFStringRef preferredLocalization = (CFStringRef)CFArrayGetValueAtIndex(preferredLocalizations, i);
+ for (CFIndex j = 0, availableCount = CFArrayGetCount(availableLocalizations); j < availableCount; j++) {
+ CFStringRef availableLocalization = (CFStringRef)CFArrayGetValueAtIndex(availableLocalizations, j);
+ if(CFStringCompare(preferredLocalization, availableLocalization, 0) == kCFCompareEqualTo) {
+ CFArrayAppendValue(resultArray, preferredLocalization);
+ }
+ CFRange hyphenation;
+ if (CFStringFindWithOptions(preferredLocalization, CFSTR("-"), CFRangeMake(0, CFStringGetLength(preferredLocalization)), kCFCompareCaseInsensitive, &hyphenation) == true) {
+ CFStringRef underscoreNotationLocalization = _copyStringWithUnderscores(preferredLocalization);
+ if (CFStringCompare(underscoreNotationLocalization, availableLocalization, 0) == kCFCompareEqualTo) {
+ CFArrayAppendValue(resultArray, underscoreNotationLocalization);
+ }
+
+ CFStringRef truncatedLocalization = _copyStringTruncated(underscoreNotationLocalization, hyphenation);
+ if (CFStringCompare(truncatedLocalization, availableLocalization, 0) == kCFCompareEqualTo) {
+ CFArrayAppendValue(resultArray, truncatedLocalization);
+ }
+
+ CFRelease(underscoreNotationLocalization);
+ CFRelease(truncatedLocalization);
+ } else if (CFStringFindWithOptions(preferredLocalization, CFSTR("_"), CFRangeMake(0, CFStringGetLength(preferredLocalization)), kCFCompareCaseInsensitive, &hyphenation) == true) {
+ CFStringRef truncatedLocalization = _copyStringTruncated(preferredLocalization, hyphenation);
+ if (CFStringCompare(truncatedLocalization, availableLocalization, 0) == kCFCompareEqualTo) {
+ CFArrayAppendValue(resultArray, truncatedLocalization);
+ }
+ CFRelease(truncatedLocalization);
+ }
+ }
+ }
+ if (CFArrayGetCount(resultArray) > 0) {
+ return resultArray;
+ }
+ return NULL;
+#endif
// stringPointers must be the length of list
char * (^makeBuffer)(CFArrayRef, char **) = ^(CFArrayRef list, char *stringPointers[]) {
#if !__HAS_APPLE_ICU__
diff --git a/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj b/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj
index 3841c533be..377163b715 100644
--- a/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj
+++ b/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj
@@ -237,10 +237,11 @@
+
-
+
\ No newline at end of file
diff --git a/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj.filters b/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj.filters
index a1a6943b2e..3e01426aff 100644
--- a/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj.filters
+++ b/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj.filters
@@ -27,5 +27,6 @@
+
-
+
\ No newline at end of file
diff --git a/build/Tests/UnitTests/Foundation/Foundation.UnitTests.vcxproj b/build/Tests/UnitTests/Foundation/Foundation.UnitTests.vcxproj
index e73754a956..84debf020f 100644
--- a/build/Tests/UnitTests/Foundation/Foundation.UnitTests.vcxproj
+++ b/build/Tests/UnitTests/Foundation/Foundation.UnitTests.vcxproj
@@ -317,6 +317,7 @@
+
@@ -349,4 +350,4 @@
-
+
\ No newline at end of file
diff --git a/build/Tests/UnitTests/Foundation/Foundation.UnitTests.vcxproj.filters b/build/Tests/UnitTests/Foundation/Foundation.UnitTests.vcxproj.filters
index 3f3df23daf..0a5fe798d5 100644
--- a/build/Tests/UnitTests/Foundation/Foundation.UnitTests.vcxproj.filters
+++ b/build/Tests/UnitTests/Foundation/Foundation.UnitTests.vcxproj.filters
@@ -152,6 +152,7 @@
+
@@ -162,4 +163,4 @@
{1beaf0a2-ff8a-415b-ac31-aeb41c89f25d}
-
+
\ No newline at end of file
diff --git a/build/Tests/UnitTests/WOCStdLib/WOCStdLib.UnitTests.vcxproj b/build/Tests/UnitTests/WOCStdLib/WOCStdLib.UnitTests.vcxproj
index a6a8f3c3b5..d707c23e45 100644
--- a/build/Tests/UnitTests/WOCStdLib/WOCStdLib.UnitTests.vcxproj
+++ b/build/Tests/UnitTests/WOCStdLib/WOCStdLib.UnitTests.vcxproj
@@ -204,7 +204,8 @@
+
-
+
\ No newline at end of file
diff --git a/deps/3rdparty/libdispatch/build/libdispatch.vcxproj b/deps/3rdparty/libdispatch/build/libdispatch.vcxproj
index 440bf501df..0d0d5ff6fe 100644
--- a/deps/3rdparty/libdispatch/build/libdispatch.vcxproj
+++ b/deps/3rdparty/libdispatch/build/libdispatch.vcxproj
@@ -1,5 +1,5 @@
-
+
Debug
@@ -37,27 +37,27 @@
DynamicLibrary
true
Unicode
- v140
+ v141
DynamicLibrary
true
Unicode
- v140
+ v141
DynamicLibrary
false
true
Unicode
- v140
+ v141
DynamicLibrary
false
true
Unicode
- v140
+ v141
@@ -82,13 +82,11 @@
$(SolutionDir)obj\$(Platform)\$(TargetOsAndVersion)\$(Configuration)\
.;$(IncludePath)
-
libdispatch
$(SolutionDir)obj\$(Platform)\$(TargetOsAndVersion)\$(Configuration)\
.;$(IncludePath)
-
libdispatch
@@ -100,13 +98,11 @@
$(SolutionDir)obj\$(Platform)\$(TargetOsAndVersion)\$(Configuration)\
.;$(IncludePath)
-
libdispatch
$(SolutionDir)obj\$(Platform)\$(TargetOsAndVersion)\$(Configuration)\
.;$(IncludePath)
-
libdispatch
@@ -220,6 +216,7 @@
+
@@ -249,19 +246,13 @@
-
- $(WINOBJC_SDK_ROOT)\deps\prebuilt\Universal Windows\$(PlatformTarget)\$(Configuration)\\
+ $(WINOBJC_SDK_ROOT)\tools\deps\prebuilt\\
+ $(PrebuiltRoot)\Universal Windows\$(PlatformTarget)\$(Configuration)\\
-
+
-
-
-
-
-
+
-
-
\ No newline at end of file
diff --git a/deps/3rdparty/libdispatch/build/project.json b/deps/3rdparty/libdispatch/build/project.json
new file mode 100644
index 0000000000..985688eb16
--- /dev/null
+++ b/deps/3rdparty/libdispatch/build/project.json
@@ -0,0 +1,16 @@
+{
+ "dependencies": {
+ "WinObjC.Language": "*",
+ },
+ "frameworks": {
+ "uap10.0": {
+ "imports": "native"
+ }
+ },
+ "runtimes": {
+ "win10-arm": {},
+ "win10-x86": {},
+ "win10-arm-aot": {},
+ "win10-x86-aot": {}
+ }
+}
diff --git a/deps/3rdparty/libdispatch/dispatch/queue.h b/deps/3rdparty/libdispatch/dispatch/queue.h
index 08f5bc3833..e4625e8df4 100644
--- a/deps/3rdparty/libdispatch/dispatch/queue.h
+++ b/deps/3rdparty/libdispatch/dispatch/queue.h
@@ -179,6 +179,133 @@ dispatch_async_f(dispatch_queue_t queue,
void *context,
dispatch_function_t work);
+/*!
+ * @function dispatch_barrier_async
+ *
+ * @abstract
+ * Submits a barrier block for asynchronous execution on a dispatch queue.
+ *
+ * @discussion
+ * Submits a block to a dispatch queue like dispatch_async(), but marks that
+ * block as a barrier (relevant only on DISPATCH_QUEUE_CONCURRENT queues).
+ *
+ * See dispatch_async() for details.
+ *
+ * @param queue
+ * The target dispatch queue to which the block is submitted.
+ * The system will hold a reference on the target queue until the block
+ * has finished.
+ * The result of passing NULL in this parameter is undefined.
+ *
+ * @param block
+ * The block to submit to the target dispatch queue. This function performs
+ * Block_copy() and Block_release() on behalf of callers.
+ * The result of passing NULL in this parameter is undefined.
+ */
+
+#ifdef __BLOCKS__
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_4_0)
+DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
+void
+dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
+#endif
+
+/*!
+ * @function dispatch_barrier_async_f
+ *
+ * @abstract
+ * Submits a barrier function for asynchronous execution on a dispatch queue.
+ *
+ * @discussion
+ * Submits a function to a dispatch queue like dispatch_async_f(), but marks
+ * that function as a barrier (relevant only on DISPATCH_QUEUE_CONCURRENT
+ * queues).
+ *
+ * See dispatch_async_f() for details.
+ *
+ * @param queue
+ * The target dispatch queue to which the function is submitted.
+ * The system will hold a reference on the target queue until the function
+ * has returned.
+ * The result of passing NULL in this parameter is undefined.
+ *
+ * @param context
+ * The application-defined context parameter to pass to the function.
+ *
+ * @param work
+ * The application-defined function to invoke on the target queue. The first
+ * parameter passed to this function is the context provided to
+ * dispatch_barrier_async_f().
+ * The result of passing NULL in this parameter is undefined.
+ */
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_4_0)
+DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NONNULL3 DISPATCH_NOTHROW
+void
+dispatch_barrier_async_f(dispatch_queue_t queue,
+ void *_Nullable context,
+ dispatch_function_t work);
+
+/*!
+ * @function dispatch_barrier_sync_f
+ *
+ * @abstract
+ * Submits a barrier function for synchronous execution on a dispatch queue.
+ *
+ * @discussion
+ * Submits a function to a dispatch queue like dispatch_sync_f(), but marks that
+ * fuction as a barrier (relevant only on DISPATCH_QUEUE_CONCURRENT queues).
+ *
+ * See dispatch_sync_f() for details.
+ *
+ * @param queue
+ * The target dispatch queue to which the function is submitted.
+ * The result of passing NULL in this parameter is undefined.
+ *
+ * @param context
+ * The application-defined context parameter to pass to the function.
+ *
+ * @param work
+ * The application-defined function to invoke on the target queue. The first
+ * parameter passed to this function is the context provided to
+ * dispatch_barrier_sync_f().
+ * The result of passing NULL in this parameter is undefined.
+ */
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_4_0)
+DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NONNULL3 DISPATCH_NOTHROW
+void
+dispatch_barrier_sync_f(dispatch_queue_t queue,
+ void *_Nullable context,
+ dispatch_function_t work);
+
+/*!
+ * @function dispatch_barrier_sync
+ *
+ * @abstract
+ * Submits a barrier block for synchronous execution on a dispatch queue.
+ *
+ * @discussion
+ * Submits a block to a dispatch queue like dispatch_sync(), but marks that
+ * block as a barrier (relevant only on DISPATCH_QUEUE_CONCURRENT queues).
+ *
+ * See dispatch_sync() for details.
+ *
+ * @param queue
+ * The target dispatch queue to which the block is submitted.
+ * The result of passing NULL in this parameter is undefined.
+ *
+ * @param block
+ * The block to be invoked on the target dispatch queue.
+ * The result of passing NULL in this parameter is undefined.
+ */
+#ifdef __BLOCKS__
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_4_0)
+DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
+void
+dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
+#endif
+
/*!
* @function dispatch_sync
*
@@ -592,6 +719,92 @@ DISPATCH_EXPORT DISPATCH_PURE DISPATCH_WARN_RESULT DISPATCH_NOTHROW
dispatch_queue_t
dispatch_get_current_thread_queue();
+/*!
+* @function dispatch_queue_set_specific
+*
+* @abstract
+* Sets the key/value data for the specified dispatch queue.
+*
+* @discussion
+* Use this method to associate custom context data with a dispatch queue.
+* Blocks executing on the queue can use the dispatch_get_specific function
+* to retrieve this data while they are running.
+*
+* @param queue
+* The queue on which to set the specified key/value data. This parameter must not be NULL.
+*
+* @param key
+* The key you want to use to identify the associated context data. Keys are only compared
+* as pointers and are never dereferenced. Thus, you can use a pointer to a static variable
+* for a specific subsystem or any other value that allows you to identify the value uniquely.
+* Specifying a pointer to a string constant is not recommended. NULL is not a valid value
+* for the key and attempts to set context data with a NULL key are ignored.
+*
+* @param context
+* The context data to associate with key. This parameter may be NULL.
+*
+* @param destructor
+* A destructor function that you can use to release your context data. This parameter may be
+* NULL. If context is NULL, your destructor function is ignored.
+*/
+
+__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
+DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NOTHROW
+void dispatch_queue_set_specific(dispatch_queue_t queue, const void *key, void *context, dispatch_function_t destructor);
+
+/*!
+* @function dispatch_queue_get_specific
+*
+* @abstract
+* Gets the value for the key associated with the specified dispatch queue.
+*
+* @discussion
+* You can use this method to get the context data associated with a specific dispatch queue.
+* Blocks executing on a queue can use the dispatch_get_specific function to retrieve the
+* context associated with that specific queue instead.
+*
+* @param queue
+* The queue containing the desired context data. This parameter must not be NULL.
+*
+* @param key
+* The key that identifies the associated context data. Keys are only compared as
+* pointers and are never dereferenced. Thus, you can use a pointer to a static variable
+* for a specific subsystem or any other value that allows you to identify the value uniquely.
+* Specifying a pointer to a string constant is not recommended.
+*
+* @result
+* The context data associated with key or NULL if no context was found.
+*/
+__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
+DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_PURE DISPATCH_WARN_RESULT
+DISPATCH_NOTHROW
+void * dispatch_queue_get_specific(dispatch_queue_t queue, const void *key);
+
+/*!
+* @function dispatch_get_specific
+*
+* @abstract
+* Returns the value for the key associated with the current dispatch queue.
+*
+* @discussion
+* This function is intended to be called from a block executing in a dispatch queue.
+* You use it to obtain context data associated with the queue. Calling this method
+* from code not running in a dispatch queue returns NULL because there is no queue
+* to provide context.
+*
+* @param key
+* The key associated with the dispatch queue on which the current block is executing.
+* Keys are only compared as pointers and never dereferenced. Passing a string constant
+* directly is not recommended.
+*
+* @result
+* The context value for the specified key; otherwise NULL if the key was not set for
+* the queue (or its target queue) or the queue is a global concurrent queue.
+*/
+__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
+DISPATCH_EXPORT DISPATCH_PURE DISPATCH_WARN_RESULT DISPATCH_NOTHROW
+void * dispatch_get_specific(const void *key);
+
__DISPATCH_END_DECLS
-#endif
+#endif
\ No newline at end of file
diff --git a/deps/3rdparty/libdispatch/src/interop.c b/deps/3rdparty/libdispatch/src/interop.c
index 6c1b3073e1..7f912726b3 100644
--- a/deps/3rdparty/libdispatch/src/interop.c
+++ b/deps/3rdparty/libdispatch/src/interop.c
@@ -42,6 +42,8 @@ struct dispatch_queue_s _dispatch_main_q = {
/*.dq_items_head = */ 0,
/*.dq_serialnum = */ 1,
/*.dq_finalizer_ctxt = */ 0,
+ /*.dq_specific_q = */ NULL,
+ /*.dq_specific_list = */ NULL,
/*.dq_manually_drained = */ 0,
/*.dq_is_manually_draining = */ false,
/*.dq_label = */ "com.apple.main-thread",
diff --git a/deps/3rdparty/libdispatch/src/queue.c b/deps/3rdparty/libdispatch/src/queue.c
index 81e8a50544..0d0e8f6add 100644
--- a/deps/3rdparty/libdispatch/src/queue.c
+++ b/deps/3rdparty/libdispatch/src/queue.c
@@ -262,6 +262,8 @@ struct dispatch_queue_s _dispatch_root_queues[] = {
/*.dq_items_head = */ 0,
/*.dq_serialnum = */ 4,
/*.dq_finalizer_ctxt = */ 0,
+ /*.dq_specific_q = */ NULL,
+ /*.dq_specific_list = */ NULL,
/*.dq_manually_drained = */ 0,
/*.dq_is_manually_draining = */ false,
/*.dq_label = */ "com.apple.root.low-priority",
@@ -281,6 +283,8 @@ struct dispatch_queue_s _dispatch_root_queues[] = {
/*.dq_items_head = */ 0,
/*.dq_serialnum = */ 5,
/*.dq_finalizer_ctxt = */ 0,
+ /*.dq_specific_q = */ NULL,
+ /*.dq_specific_list = */ NULL,
/*.dq_manually_drained = */ 0,
/*.dq_is_manually_draining = */ false,
/*.dq_label = */ "com.apple.root.low-overcommit-priority",
@@ -300,6 +304,8 @@ struct dispatch_queue_s _dispatch_root_queues[] = {
/*.dq_items_head = */ 0,
/*.dq_serialnum = */ 6,
/*.dq_finalizer_ctxt = */ 0,
+ /*.dq_specific_q = */ NULL,
+ /*.dq_specific_list = */ NULL,
/*.dq_manually_drained = */ 0,
/*.dq_is_manually_draining = */ false,
/*.dq_label = */ "com.apple.root.default-priority",
@@ -319,6 +325,8 @@ struct dispatch_queue_s _dispatch_root_queues[] = {
/*.dq_items_head = */ 0,
/*.dq_serialnum = */ 7,
/*.dq_finalizer_ctxt = */ 0,
+ /*.dq_specific_q = */ NULL,
+ /*.dq_specific_list = */ NULL,
/*.dq_manually_drained = */ 0,
/*.dq_is_manually_draining = */ false,
/*.dq_label = */ "com.apple.root.default-overcommit-priority",
@@ -338,6 +346,8 @@ struct dispatch_queue_s _dispatch_root_queues[] = {
/*.dq_items_head = */ 0,
/*.dq_serialnum = */ 8,
/*.dq_finalizer_ctxt = */ 0,
+ /*.dq_specific_q = */ NULL,
+ /*.dq_specific_list = */ NULL,
/*.dq_manually_drained = */ 0,
/*.dq_is_manually_draining = */ false,
/*.dq_label = */ "com.apple.root.high-priority",
@@ -357,6 +367,8 @@ struct dispatch_queue_s _dispatch_root_queues[] = {
/*.dq_items_head = */ 0,
/*.dq_serialnum = */ 9,
/*.dq_finalizer_ctxt = */ 0,
+ /*.dq_specific_q = */ NULL,
+ /*.dq_specific_list = */ NULL,
/*.dq_manually_drained = */ 0,
/*.dq_is_manually_draining = */ false,
/*.dq_label = */ "com.apple.root.high-overcommit-priority",
@@ -609,6 +621,8 @@ _dispatch_queue_init(dispatch_queue_t dq)
dq->dq_running = 0;
dq->dq_width = 1;
dq->dq_serialnum = dispatch_atomic_inc(&_dispatch_queue_serial_numbers) - 1;
+ dq->dq_specific_q = NULL;
+ dq->dq_specific_list = NULL,
dq->dq_manually_drained = 0;
dq->dq_is_manually_draining = false;
}
@@ -665,6 +679,26 @@ dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
#endif
}
+void _dispatch_queue_specific_list_release(dispatch_queue_specific_list_t dqsl) {
+ dispatch_queue_specific_t lastvar = NULL;
+ dispatch_queue_specific_t var;
+
+ TAILQ_FOREACH(var, &dqsl->context_list, specific) {
+ if (lastvar) {
+ free(lastvar);
+ }
+ if (var->destructor) {
+ var->destructor(var->context);
+ }
+ lastvar = var;
+ }
+ if (lastvar) {
+ free(lastvar);
+ }
+
+ free(dqsl);
+}
+
// 6618342 Contact the team that owns the Instrument DTrace probe before renaming this symbol
void
_dispatch_queue_dispose(dispatch_queue_t dq)
@@ -682,6 +716,13 @@ _dispatch_queue_dispose(dispatch_queue_t dq)
}
#endif
+ if (slowpath(dq->dq_specific_q)) {
+ dispatch_release(dq->dq_specific_q);
+ }
+ if (slowpath(dq->dq_specific_list)) {
+ _dispatch_queue_specific_list_release(dq->dq_specific_list);
+ }
+
// trash the tail queue so that use after free will crash
dq->dq_items_tail = (void *)(uintptr_t)0x200;
@@ -1978,3 +2019,91 @@ dispatch_after_f(dispatch_time_t when, dispatch_queue_t queue, void *ctxt, void
dispatch_resume(as_do(ds));
}
+static void _dispatch_queue_init_specific_list(dispatch_queue_t dq) {
+ dispatch_queue_t newQueue = dispatch_queue_create("SpecificQueue", NULL);
+ dispatch_queue_specific_list_t dqsl;
+ dqsl = calloc(1, sizeof(struct dispatch_queue_specific_list_s));
+ TAILQ_INIT(&dqsl->context_list);
+ newQueue->dq_specific_list = dqsl;
+
+ if(slowpath(!dispatch_atomic_cmpxchg_pointer(&dq->dq_specific_q, NULL, newQueue))) {
+ dispatch_release(newQueue);
+ }
+}
+
+static void _dispatch_queue_insert_specific(dispatch_queue_specific_t dqs) {
+ dispatch_queue_t dq = _dispatch_queue_get_current();
+ dispatch_queue_specific_list_t dqsl = dq->dq_specific_list;
+ dispatch_queue_specific_t var;
+
+ TAILQ_FOREACH(var, &dqsl->context_list, specific) {
+ if (var->key == dqs->key) {
+ if(var->destructor) {
+ dispatch_async_f(_dispatch_get_root_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, false), var->context, var->destructor);
+ }
+
+ // If a specific exists with this key, simply update the context on that specific
+ if(dqs->context) {
+ var->context = dqs->context;
+ var->destructor = dqs->destructor;
+ } else {
+ TAILQ_REMOVE(&dqsl->context_list, var, specific);
+ free(var);
+ }
+ free(dqs);
+ return;
+ }
+ }
+
+ if(dqs->context) {
+ TAILQ_INSERT_TAIL(&dqsl->context_list, dqs, specific);
+ }
+}
+
+void dispatch_queue_set_specific(dispatch_queue_t queue, const void *key, void *_Nullable context, dispatch_function_t _Nullable destructor) {
+ if (slowpath(!key)) {
+ return;
+ }
+ dispatch_queue_specific_t specific = calloc(1, sizeof(struct dispatch_queue_specific_s));
+ specific->key = key;
+ specific->context = context;
+ specific->destructor = destructor;
+
+ // Delayed initialization
+ if (slowpath(!queue->dq_specific_q)) {
+ _dispatch_queue_init_specific_list(queue);
+ }
+
+ dispatch_barrier_sync_f(queue->dq_specific_q, specific, _dispatch_queue_insert_specific);
+}
+
+static void _dispatch_queue_get_specific(void* context) {
+ dispatch_queue_t dq = _dispatch_queue_get_current();
+ dispatch_queue_specific_list_t dqsl = dq->dq_specific_list;
+ dispatch_queue_specific_t var;
+
+ // The parameter passed in is reference to a void* key
+ void** ctxt = context;
+ void* key = *ctxt;
+
+ TAILQ_FOREACH(var, &dqsl->context_list, specific) {
+ if (var->key == key) {
+ *ctxt = var->context;
+ return;
+ }
+ }
+ *ctxt = NULL;
+}
+
+void* _Nullable dispatch_queue_get_specific(dispatch_queue_t queue, const void *key) {
+ void* context = NULL;
+ if (queue->dq_specific_q) {
+ context = key;
+ dispatch_sync_f(queue->dq_specific_q, &context, _dispatch_queue_get_specific);
+ }
+ return context;
+}
+
+void* _Nullable dispatch_get_specific(const void *key) {
+ return dispatch_queue_get_specific(_dispatch_queue_get_current(), key);
+}
\ No newline at end of file
diff --git a/deps/3rdparty/libdispatch/src/queue_internal.h b/deps/3rdparty/libdispatch/src/queue_internal.h
index e1954819e1..e1eef4378f 100644
--- a/deps/3rdparty/libdispatch/src/queue_internal.h
+++ b/deps/3rdparty/libdispatch/src/queue_internal.h
@@ -46,6 +46,9 @@ extern const struct dispatch_queue_vtable_s _dispatch_queue_vtable;
#define DISPATCH_QUEUE_MIN_LABEL_SIZE 64
+DISPATCH_DECL(dispatch_queue_specific_list);
+DISPATCH_DECL(dispatch_queue_specific);
+
#ifndef DISPATCH_NO_LEGACY
#define DISPATCH_QUEUE_HEADER \
intptr_t dq_running; \
@@ -54,6 +57,8 @@ extern const struct dispatch_queue_vtable_s _dispatch_queue_vtable;
struct dispatch_object_s *volatile dq_items_head; \
intptr_t dq_serialnum; \
void *dq_finalizer_ctxt; \
+ struct dispatch_queue_s *dq_specific_q; \
+ struct dispatch_queue_specific_list_s *dq_specific_list; \
dispatch_queue_finalizer_function_t dq_finalizer_func
#else
#define DISPATCH_QUEUE_HEADER \
@@ -63,10 +68,23 @@ extern const struct dispatch_queue_vtable_s _dispatch_queue_vtable;
struct dispatch_object_s *volatile dq_items_head; \
intptr_t dq_serialnum; \
void *dq_finalizer_ctxt; \
+ struct dispatch_queue_s *dq_specific_q; \
+ struct dispatch_queue_specific_list_s *dq_specific_list; \
void* dq_manually_drained; \
bool dq_is_manually_draining
#endif
+struct dispatch_queue_specific_list_s {
+ TAILQ_HEAD(dispatch_queue_specific_head_s, dispatch_queue_specific_s) context_list;
+};
+
+struct dispatch_queue_specific_s {
+ const void *key;
+ void *context;
+ dispatch_function_t destructor;
+ TAILQ_ENTRY(dispatch_queue_specific_s) specific;
+};
+
struct dispatch_queue_s {
DISPATCH_STRUCT_HEADER(dispatch_queue_s, dispatch_queue_vtable_s);
DISPATCH_QUEUE_HEADER;
@@ -121,4 +139,4 @@ _dispatch_queue_get_current(void)
return _dispatch_thread_getspecific(dispatch_queue_key);
}
-#endif
+#endif
\ No newline at end of file
diff --git a/deps/3rdparty/libdispatch/src/queue_kevent.c b/deps/3rdparty/libdispatch/src/queue_kevent.c
index e903ba413a..3d738edd90 100644
--- a/deps/3rdparty/libdispatch/src/queue_kevent.c
+++ b/deps/3rdparty/libdispatch/src/queue_kevent.c
@@ -512,6 +512,8 @@ struct dispatch_queue_s _dispatch_mgr_q = {
/*.dq_items_head = */ 0,
/*.dq_serialnum = */ 2,
/*.dq_finalizer_ctxt = */ 0,
+ /*.dq_specific_q = */ NULL,
+ /*.dq_specific_list = */ NULL,
/*.dq_manually_drained = */ 0,
/*.dq_is_manually_draining = */ false,
/*.dq_label = */ "com.apple.libdispatch-manager",
diff --git a/msvc/sdk-build.props b/msvc/sdk-build.props
index 30ed61a228..6a07eaa27d 100644
--- a/msvc/sdk-build.props
+++ b/msvc/sdk-build.props
@@ -97,7 +97,7 @@
true
-Werror -Wno-microsoft --system-header-prefix=winrt/ %(AdditionalOptions)
_WINOBJC_DO_NOT_USE_NSLOG=;%(PreprocessorDefinitions)
- %(InternalSystemIncludePaths);$(IncludePath);$(MSBuildThisFileDirectory)..\include\;$(MSBuildThisFileDirectory)..\include\xplat;$(MSBuildThisFileDirectory)..\deps\prebuilt\include\;$(MSBuildThisFileDirectory)..\deps\prebuilt\include\icu;$([System.IO.Path]::Combine('$(MSBuildThisFileDirectory)..\include\Platform', '$(TargetOsAndVersion)'))
+ %(InternalSystemIncludePaths);$(IncludePath);$(MSBuildThisFileDirectory)..\include\;$(MSBuildThisFileDirectory)..\include\xplat;$(MSBuildThisFileDirectory)..\deps\prebuilt\include\;$(MSBuildThisFileDirectory)..\tools\deps\prebuilt\include\;$(MSBuildThisFileDirectory)..\deps\prebuilt\include\icu;$([System.IO.Path]::Combine('$(MSBuildThisFileDirectory)..\include\Platform', '$(TargetOsAndVersion)'))
%(IncludePaths);$(MSBuildThisFileDirectory)..\Frameworks\include\;
%(InternalForceIncludes);StubIncludes.h;
diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/Base.lproj/Localizable.strings b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/Base.lproj/Localizable.strings
new file mode 100644
index 0000000000..2fe0fcfe5a
--- /dev/null
+++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/Base.lproj/Localizable.strings
@@ -0,0 +1,11 @@
+"a" = "z";
+"b" = "y";
+"c" = "x";
+"d" = "w";
+"e" = "v";
+"f" = "u";
+"g" = "t";
+"h" = "s";
+"i" = "r";
+"j" = "q";
+"Hello World" = "English: Hello World";
\ No newline at end of file
diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj
index 29f397cd22..d7622a3a4d 100644
--- a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj
+++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj
@@ -1,4 +1,4 @@
-
+
@@ -212,6 +212,7 @@
+
@@ -248,6 +249,7 @@
+
@@ -274,6 +276,26 @@
WOCCatalog-Debug-xcvars.txt
WOCCatalog-Release-xcvars.txt
+
+ Document
+ Base.lproj
+
+
+ Document
+ de.lproj
+
+
+ Document
+ zh.lproj
+
+
+ Document
+ zh-Hant-TW.lproj
+
+
+ Document
+ es_MX.lproj
+
@@ -303,7 +325,6 @@
-
uap10.0
@@ -316,6 +337,5 @@
-
-
-
+
+
\ No newline at end of file
diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters
index c4f5fe296f..344291f793 100644
--- a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters
+++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters
@@ -1,4 +1,4 @@
-
+
@@ -99,6 +99,9 @@
WOCCatalog
+
+ WOCCatalog
+
WOCCatalog
@@ -207,6 +210,9 @@
WOCCatalog
+
+ WOCCatalog
+
WOCCatalog
@@ -332,4 +338,21 @@
WOCCatalog
-
+
+
+
+
+
+
+
+
+
+
+ WOCCatalog
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/de.lproj/Localizable.strings b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/de.lproj/Localizable.strings
new file mode 100644
index 0000000000..07ae7d03e6
--- /dev/null
+++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/de.lproj/Localizable.strings
@@ -0,0 +1,11 @@
+"a" = "1";
+"b" = "2";
+"c" = "3";
+"d" = "4";
+"e" = "5";
+"f" = "6";
+"g" = "7";
+"h" = "8";
+"i" = "9";
+"j" = "10";
+"Hello World" = "German: Hallo Welt";
\ No newline at end of file
diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/es_MX.lproj/Localizable.strings b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/es_MX.lproj/Localizable.strings
new file mode 100644
index 0000000000..014451d3e7
--- /dev/null
+++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/es_MX.lproj/Localizable.strings
@@ -0,0 +1,11 @@
+"a" = "z";
+"b" = "x";
+"c" = "c";
+"d" = "v";
+"e" = "b";
+"f" = "n";
+"g" = "m";
+"h" = ",";
+"i" = ".";
+"j" = "/";
+"Hello World" = "Spanish _: Hola Mundo";
\ No newline at end of file
diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh-Hant-TW.lproj/Localizable.strings b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh-Hant-TW.lproj/Localizable.strings
new file mode 100644
index 0000000000..4978c25d48
--- /dev/null
+++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh-Hant-TW.lproj/Localizable.strings
@@ -0,0 +1,11 @@
+"a" = "q";
+"b" = "w";
+"c" = "e";
+"d" = "r";
+"e" = "t";
+"f" = "y";
+"g" = "u";
+"h" = "i";
+"i" = "o";
+"j" = "p";
+"Hello World" = "zh-Hant-TW: 世界您好";
\ No newline at end of file
diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh.lproj/Localizable.strings b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh.lproj/Localizable.strings
new file mode 100644
index 0000000000..5a8405fe6f
--- /dev/null
+++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh.lproj/Localizable.strings
@@ -0,0 +1,11 @@
+"a" = "a";
+"b" = "s";
+"c" = "d";
+"d" = "f";
+"e" = "g";
+"f" = "h";
+"g" = "j";
+"h" = "k";
+"i" = "l";
+"j" = ";";
+"Hello World" = "zh-Hans-CN truncated: 世界您好";
\ No newline at end of file
diff --git a/samples/WOCCatalog/WOCCatalog/LocalizationViewController.h b/samples/WOCCatalog/WOCCatalog/LocalizationViewController.h
new file mode 100644
index 0000000000..1e9b1143b5
--- /dev/null
+++ b/samples/WOCCatalog/WOCCatalog/LocalizationViewController.h
@@ -0,0 +1,21 @@
+//******************************************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+//
+// This code is licensed under the MIT License (MIT).
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+//******************************************************************************
+
+#import
+#import
+
+@interface LocalizationViewController : UITableViewController
+@end
\ No newline at end of file
diff --git a/samples/WOCCatalog/WOCCatalog/LocalizationViewController.m b/samples/WOCCatalog/WOCCatalog/LocalizationViewController.m
new file mode 100644
index 0000000000..209a3c3e29
--- /dev/null
+++ b/samples/WOCCatalog/WOCCatalog/LocalizationViewController.m
@@ -0,0 +1,82 @@
+//******************************************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+//
+// This code is licensed under the MIT License (MIT).
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+//******************************************************************************
+
+#import "LocalizationViewController.h"
+
+static const CGFloat c_originX = 5;
+static const CGFloat c_originY = 8;
+static const CGFloat c_width = 260;
+static const CGFloat c_height = 50;
+
+@implementation LocalizationViewController {
+@private
+ UITableViewCell* _cell;
+ UITextField* _copyTextField;
+ UILabel* _pasteTextLabel;
+}
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ self.tableView.allowsSelection = YES;
+}
+
+- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {
+ return 2;
+}
+
+- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {
+ return 70;
+}
+
+- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
+ _cell = [tableView dequeueReusableCellWithIdentifier:@"MenuCell"];
+ if (nil == _cell) {
+ _cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"];
+ _cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ }
+
+ CGRect frame = CGRectMake(c_originX, c_originY, c_width, c_height);
+
+ if (indexPath.row == 0) {
+ _copyTextField = [[UITextField alloc] initWithFrame:frame];
+ _copyTextField.textColor = [UIColor blackColor];
+ _copyTextField.font = [UIFont systemFontOfSize:17.0];
+ _copyTextField.text = @"Hello World";
+ [_copyTextField addTarget:self action:@selector(onCopyTextChanged:) forControlEvents:UIControlEventEditingChanged];
+
+ _cell.accessoryView = _copyTextField;
+ _cell.textLabel.text = @"Enter Text";
+ } else if (indexPath.row == 1) {
+ _pasteTextLabel = [[UILabel alloc] initWithFrame:frame];
+ _pasteTextLabel.textColor = [UIColor blackColor];
+ _pasteTextLabel.font = [UIFont systemFontOfSize:17.0];
+ _pasteTextLabel.textAlignment = NSTextAlignmentLeft;
+ _pasteTextLabel.text = NSLocalizedString(_copyTextField.text, nil);
+ _cell.accessoryView = _pasteTextLabel;
+ _cell.textLabel.text = @"Localized Text";
+ }
+ return _cell;
+}
+
+- (void)viewDidLayoutSubviews {
+ [(UIScrollView*)self.view setContentSize:[self.view.subviews[0] bounds].size];
+}
+
+- (void)onCopyTextChanged:(UITextField*)textField {
+ _pasteTextLabel.text = NSLocalizedString(textField.text, nil);
+ [[self tableView] setNeedsLayout];
+}
+
+@end
diff --git a/samples/WOCCatalog/WOCCatalog/MainViewController.m b/samples/WOCCatalog/WOCCatalog/MainViewController.m
index 781ac814ad..ed371d655e 100644
--- a/samples/WOCCatalog/WOCCatalog/MainViewController.m
+++ b/samples/WOCCatalog/WOCCatalog/MainViewController.m
@@ -44,6 +44,7 @@
#import "GeocodingViewController.h"
#import "CoreLocationViewController.h"
#import "GesturesViewController.h"
+#import "LocalizationViewController.h"
#ifdef WINOBJC
#import "XamlViewController.h"
@@ -138,12 +139,15 @@ - (void)viewDidLoad {
// Accelerate 2
[self addMenuItemViewController:[[AccelerateViewController2 alloc] init] andTitle:@"Accelerate 2"];
-
+
// Shadow
[self addMenuItemViewController:[[ShadowViewController alloc] init] andTitle:@"Shadow"];
// UIPasteboard
[self addMenuItemViewController:[[UIPasteboardViewController alloc] init] andTitle:@"Copy And Paste"];
+
+ // Localization
+ [self addMenuItemViewController:[[LocalizationViewController alloc] init] andTitle:@"Localization"];
}
- (void)didReceiveMemoryWarning {
diff --git a/tests/UnitTests/Foundation/DispatchTests.mm b/tests/UnitTests/Foundation/DispatchTests.mm
new file mode 100644
index 0000000000..b47c5c7c9d
--- /dev/null
+++ b/tests/UnitTests/Foundation/DispatchTests.mm
@@ -0,0 +1,210 @@
+//******************************************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+//
+// This code is licensed under the MIT License (MIT).
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+//******************************************************************************
+
+#import
+#import
+#import
+
+static const char* key = "Specific Key";
+static const char* key2 = "Specific Key2";
+static const char* key3 = "Specific Key3";
+static char* context = "Specific Context 1";
+static char* context2 = "Specific Context 2";
+static char* context3 = "Specific Context 3";
+static int destructorCount = 0;
+
+// Create a 1 second end time for the test to timeout.
+static dispatch_time_t _createEndTestTime() {
+ return dispatch_time(DISPATCH_TIME_NOW, 1000000000);
+}
+
+static dispatch_semaphore_t destructorSemaphore;
+static void destructor(void* x) {
+ destructorCount++;
+ if (destructorSemaphore) {
+ dispatch_semaphore_signal(destructorSemaphore);
+ }
+}
+
+TEST(DispatchTests, SimpleSpecific) {
+ dispatch_queue_t queue = dispatch_queue_create("queue", nullptr);
+ dispatch_group_t group = dispatch_group_create();
+
+ dispatch_queue_set_specific(queue, key, context, nullptr);
+
+ dispatch_group_async(group, queue, ^{
+ EXPECT_EQ(context, dispatch_get_specific(key));
+ dispatch_queue_set_specific(queue, key, context2, nullptr);
+ });
+
+ ASSERT_EQ(0, dispatch_group_wait(group, _createEndTestTime()));
+
+ EXPECT_EQ(context2, dispatch_queue_get_specific(queue, key));
+
+ dispatch_group_async(group, queue, ^{
+ EXPECT_EQ(context2, dispatch_get_specific(key));
+ });
+ ASSERT_EQ(0, dispatch_group_wait(group, _createEndTestTime()));
+
+ dispatch_release(group);
+ dispatch_release(queue);
+}
+
+TEST(DispatchTests, MultipleSpecificKeys) {
+ dispatch_queue_t queue = dispatch_queue_create("queue", nullptr);
+ dispatch_group_t group = dispatch_group_create();
+
+ dispatch_queue_set_specific(queue, key, context, nullptr);
+ dispatch_queue_set_specific(queue, key2, context2, nullptr);
+
+ dispatch_group_async(group, queue, ^{
+ EXPECT_EQ(context, dispatch_get_specific(key));
+ EXPECT_EQ(context2, dispatch_get_specific(key2));
+ dispatch_queue_set_specific(queue, key, context2, nullptr);
+ dispatch_queue_set_specific(queue, key2, context, nullptr);
+ });
+ ASSERT_EQ(0, dispatch_group_wait(group, _createEndTestTime()));
+
+ EXPECT_EQ(context2, dispatch_queue_get_specific(queue, key));
+ EXPECT_EQ(context, dispatch_queue_get_specific(queue, key2));
+
+ dispatch_queue_set_specific(queue, key3, context3, nullptr);
+
+ dispatch_group_async(group, queue, ^{
+ EXPECT_EQ(context2, dispatch_get_specific(key));
+ EXPECT_EQ(context, dispatch_get_specific(key2));
+ EXPECT_EQ(context3, dispatch_get_specific(key3));
+ });
+ ASSERT_EQ(0, dispatch_group_wait(group, _createEndTestTime()));
+
+ dispatch_release(queue);
+ dispatch_release(group);
+}
+
+TEST(DispatchTests, SpecificDestructor) {
+ dispatch_queue_t queue = dispatch_queue_create("queue", nullptr);
+ dispatch_group_t group = dispatch_group_create();
+ destructorSemaphore = dispatch_semaphore_create(0);
+
+ dispatch_queue_set_specific(queue, key, context, destructor);
+
+ EXPECT_EQ(0, destructorCount);
+
+ dispatch_group_async(group, queue, ^{
+ EXPECT_EQ(dispatch_get_specific(key), context);
+ dispatch_queue_set_specific(queue, key, context2, destructor);
+ // Destructor can be called asynchrounously. Wait for deestructor to be called.
+ dispatch_semaphore_wait(destructorSemaphore, _createEndTestTime());
+ EXPECT_EQ(1, destructorCount);
+ });
+ ASSERT_EQ(dispatch_group_wait(group, _createEndTestTime()), 0);
+
+ EXPECT_EQ(context2, dispatch_queue_get_specific(queue, key));
+ dispatch_queue_set_specific(queue, key, context, destructor);
+ dispatch_semaphore_wait(destructorSemaphore, _createEndTestTime());
+ EXPECT_EQ(2, destructorCount);
+
+ dispatch_group_async(group, queue, ^{
+ EXPECT_EQ(context, dispatch_get_specific(key));
+ EXPECT_EQ(2, destructorCount);
+ });
+ ASSERT_EQ(0, dispatch_group_wait(group, _createEndTestTime()));
+
+ dispatch_release(queue);
+ dispatch_release(group);
+ dispatch_release(destructorSemaphore);
+ destructorSemaphore = nullptr;
+}
+
+TEST(DispatchTests, RemoveSpecific) {
+ dispatch_queue_t queue = dispatch_queue_create("queue", nullptr);
+ dispatch_group_t group = dispatch_group_create();
+
+ dispatch_queue_set_specific(queue, key, context, nullptr);
+
+ dispatch_group_async(group, queue, ^{
+ EXPECT_EQ(context, dispatch_get_specific(key));
+ dispatch_queue_set_specific(queue, key, nullptr, nullptr);
+ });
+ ASSERT_EQ(0, dispatch_group_wait(group, _createEndTestTime()));
+
+ EXPECT_EQ(nullptr, dispatch_queue_get_specific(queue, key));
+
+ dispatch_release(queue);
+ dispatch_release(group);
+}
+
+TEST(DispatchTests, MultipleQueues) {
+ dispatch_queue_t queue1 = dispatch_queue_create("queue1", nullptr);
+ dispatch_queue_t queue2 = dispatch_queue_create("queue2", nullptr);
+ dispatch_queue_t queue3 = dispatch_queue_create("queue3", nullptr);
+ dispatch_group_t group = dispatch_group_create();
+
+ dispatch_queue_set_specific(queue1, key, context, nullptr);
+ dispatch_queue_set_specific(queue2, key, context2, nullptr);
+ dispatch_queue_set_specific(queue3, key, context3, nullptr);
+
+ dispatch_group_async(group, queue1, ^{
+ EXPECT_EQ(context, dispatch_get_specific(key));
+ dispatch_queue_set_specific(queue1, key, context2, nullptr);
+ });
+ dispatch_group_async(group, queue2, ^{
+ EXPECT_EQ(context2, dispatch_get_specific(key));
+ dispatch_queue_set_specific(queue2, key, context3, nullptr);
+ });
+ dispatch_group_async(group, queue3, ^{
+ EXPECT_EQ(context3, dispatch_get_specific(key));
+ dispatch_queue_set_specific(queue3, key, context, nullptr);
+ });
+ ASSERT_EQ(0, dispatch_group_wait(group, _createEndTestTime()));
+
+ EXPECT_EQ(context2, dispatch_queue_get_specific(queue1, key));
+ EXPECT_EQ(context3, dispatch_queue_get_specific(queue2, key));
+ EXPECT_EQ(context, dispatch_queue_get_specific(queue3, key));
+
+ dispatch_group_async(group, queue1, ^{
+ EXPECT_EQ(context2, dispatch_get_specific(key));
+ });
+ dispatch_group_async(group, queue2, ^{
+ EXPECT_EQ(context3, dispatch_get_specific(key));
+ });
+ dispatch_group_async(group, queue3, ^{
+ EXPECT_EQ(context, dispatch_get_specific(key));
+ });
+ ASSERT_EQ(0, dispatch_group_wait(group, _createEndTestTime()));
+
+ dispatch_queue_set_specific(queue1, key2, context, nullptr);
+ dispatch_queue_set_specific(queue1, key2, context3, nullptr);
+ dispatch_queue_set_specific(queue3, key3, context3, nullptr);
+
+ dispatch_group_async(group, queue1, ^{
+ EXPECT_EQ(context2, dispatch_get_specific(key));
+ EXPECT_EQ(context3, dispatch_get_specific(key2));
+ });
+ dispatch_group_async(group, queue2, ^{
+ EXPECT_EQ(context3, dispatch_get_specific(key));
+ });
+ dispatch_group_async(group, queue3, ^{
+ EXPECT_EQ(context, dispatch_get_specific(key));
+ EXPECT_EQ(context3, dispatch_get_specific(key3));
+ });
+ ASSERT_EQ(0, dispatch_group_wait(group, _createEndTestTime()));
+
+ dispatch_release(queue1);
+ dispatch_release(queue2);
+ dispatch_release(queue3);
+ dispatch_release(group);
+}
\ No newline at end of file
diff --git a/tests/UnitTests/Foundation/WindowsOnly/BundleInternalTests.mm b/tests/UnitTests/Foundation/WindowsOnly/BundleInternalTests.mm
new file mode 100644
index 0000000000..bbe9c2e026
--- /dev/null
+++ b/tests/UnitTests/Foundation/WindowsOnly/BundleInternalTests.mm
@@ -0,0 +1,77 @@
+//******************************************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+//
+// This code is licensed under the MIT License (MIT).
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+//******************************************************************************
+
+#import
+#import
+#import
+
+class NSBundleLocalization : public ::testing::Test {
+public:
+ explicit NSBundleLocalization() : ::testing::Test() {
+ }
+
+protected:
+ virtual void SetUp() {
+ NSString* _subDirectory = @"en.lproj";
+ NSString* localizationResourceName = @"Localizable.strings";
+ // Create a unique test directory
+ _playground = [@"./tmp_TestFoundation" stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
+ _bundlePath = [_playground stringByAppendingPathComponent:@"MyBundle.bundle"];
+ NSError* error = nil;
+
+ NSString* localizationPath = [NSString stringWithFormat:@"%@/%@", _bundlePath.get(), _subDirectory];
+ [[NSFileManager defaultManager] createDirectoryAtPath:localizationPath
+ withIntermediateDirectories:true
+ attributes:nil
+ error:&error];
+ ASSERT_EQ(nil, error);
+
+ // Full path to the file name
+ NSString* filepath = [NSString stringWithFormat:@"%@/%@", localizationPath, localizationResourceName];
+ [[NSFileManager defaultManager] createFileAtPath:filepath contents:nil attributes:nil];
+
+ // As translated by Bing translate using unicode escapes to properly write to file
+ NSString* localization = @"\"Hello World\" = \"Hallo Welt\";\n\"Coding\" = \"\u7f16\u7801\";";
+ [localization writeToFile:filepath atomically:YES encoding:NSUnicodeStringEncoding error:&error];
+ }
+
+ virtual void TearDown() {
+ NSError* error;
+ [[NSFileManager defaultManager] removeItemAtPath:_playground error:&error];
+ if (error) {
+ // Oh well, temporary directories in taef are cleaned up automatically anyway
+ }
+ }
+
+ StrongId _playground;
+ StrongId _bundlePath;
+};
+
+TEST_F(NSBundleLocalization, LocalizedString) {
+ if (!_playground) {
+ ASSERT_TRUE_MSG(false, @"Unable to create bundle resources");
+ }
+
+ NSBundle* bundle = [NSBundle bundleWithPath:_bundlePath];
+ ASSERT_OBJCNE(bundle, nil);
+
+ NSString* helloWorld = @"Hello World";
+ NSString* coding = @"Coding";
+ NSString* helloWorldInGerman = NSLocalizedStringFromTableInBundle(helloWorld, nil, bundle, nil);
+ NSString* codingInChinese = NSLocalizedStringFromTableInBundle(coding, nil, bundle, nil);
+ ASSERT_OBJCEQ(@"Hallo Welt", helloWorldInGerman);
+ ASSERT_OBJCEQ(@"编码", codingInChinese);
+}
\ No newline at end of file
diff --git a/tests/UnitTests/WOCStdLib/OSSpinLockTest.mm b/tests/UnitTests/WOCStdLib/OSSpinLockTest.mm
new file mode 100644
index 0000000000..3d3c4fed21
--- /dev/null
+++ b/tests/UnitTests/WOCStdLib/OSSpinLockTest.mm
@@ -0,0 +1,79 @@
+//******************************************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+//
+// This code is licensed under the MIT License (MIT).
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+//******************************************************************************
+
+#import
+#import
+#import
+#import
+
+// Create a 1 second end time for the test to timeout.
+static dispatch_time_t _createEndTestTime() {
+ return dispatch_time(DISPATCH_TIME_NOW, 1000000000);
+}
+
+TEST(OSSpinLock, SpinLockTests) {
+ // Use two queues for concurrency as DISPATCH_QUEUE_CONCURRENT is not yet supported.
+ dispatch_queue_t queue1 = dispatch_queue_create("queue", nullptr);
+ dispatch_queue_t queue2 = dispatch_queue_create("queue", nullptr);
+ dispatch_semaphore_t semaphore1 = dispatch_semaphore_create(0);
+ dispatch_semaphore_t semaphore2 = dispatch_semaphore_create(0);
+
+ __block OSSpinLock lock1 = OS_SPINLOCK_INIT;
+ __block OSSpinLock lock2 = OS_SPINLOCK_INIT;
+ __block OSSpinLock lock3 = OS_SPINLOCK_INIT;
+ __block int spinValue = 0;
+
+ OSSpinLockLock(&lock1);
+ OSSpinLockLock(&lock2);
+ OSSpinLockLock(&lock3);
+
+ dispatch_async(queue1, ^{
+ dispatch_semaphore_wait(semaphore1, _createEndTestTime());
+
+ ASSERT_EQ(false, OSSpinLockTry(&lock1));
+ ASSERT_EQ(0, spinValue);
+ spinValue++;
+ ASSERT_EQ(1, spinValue);
+ OSSpinLockUnlock(&lock2);
+ dispatch_semaphore_signal(semaphore2);
+ });
+
+ dispatch_async(queue2, ^{
+ dispatch_semaphore_signal(semaphore1);
+
+ OSSpinLockLock(&lock2);
+ ASSERT_EQ(false, OSSpinLockTry(&lock1));
+ ASSERT_EQ(1, spinValue);
+ spinValue++;
+ ASSERT_EQ(2, spinValue);
+ OSSpinLockUnlock(&lock1);
+ OSSpinLockUnlock(&lock2);
+ OSSpinLockUnlock(&lock3);
+ dispatch_semaphore_signal(semaphore2);
+ });
+
+ dispatch_semaphore_wait(semaphore2, _createEndTestTime());
+ dispatch_semaphore_wait(semaphore2, _createEndTestTime());
+
+ ASSERT_EQ(true, OSSpinLockTry(&lock3));
+ ASSERT_EQ(false, OSSpinLockTry(&lock3));
+ OSSpinLockUnlock(&lock3);
+
+ dispatch_release(queue1);
+ dispatch_release(queue2);
+ dispatch_release(semaphore1);
+ dispatch_release(semaphore2);
+}
\ No newline at end of file
diff --git a/tests/unittests/Foundation/NSNullTests.mm b/tests/unittests/Foundation/NSNullTests.mm
index b0b07a28bb..181a2b464f 100644
--- a/tests/unittests/Foundation/NSNullTests.mm
+++ b/tests/unittests/Foundation/NSNullTests.mm
@@ -18,7 +18,7 @@
#import
TEST(NSNull, Bridged) {
- ASSERT_EQ([NSNull null], kCFNull); // Pointer equality required.
+ ASSERT_EQ((void*)[NSNull null], (void*)kCFNull); // Pointer equality required.
}
TEST(NSNull, Singleton) {
diff --git a/tools/WOCStdLib/dll/WOCStdLib.def b/tools/WOCStdLib/dll/WOCStdLib.def
index 915b9d08cd..f9fcf04695 100644
--- a/tools/WOCStdLib/dll/WOCStdLib.def
+++ b/tools/WOCStdLib/dll/WOCStdLib.def
@@ -33,6 +33,9 @@ LIBRARY WOCStdLib
OSSwapInt16
OSSwapInt32
OSSwapLittleToHostInt32
+ OSSpinLockLock
+ OSSpinLockUnlock
+ OSSpinLockTry
arc4random
arc4random_uniform
mach_timebase_info
diff --git a/tools/WOCStdLib/lib/OSSpinLock.cpp b/tools/WOCStdLib/lib/OSSpinLock.cpp
new file mode 100644
index 0000000000..653585e3e7
--- /dev/null
+++ b/tools/WOCStdLib/lib/OSSpinLock.cpp
@@ -0,0 +1,35 @@
+//******************************************************************************
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// This code is licensed under the MIT License (MIT).
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+//******************************************************************************
+
+#include
+#include "windows.h"
+#ifdef _MSC_VER
+#include
+#endif
+
+extern "C" void OSSpinLockLock(volatile OSSpinLock* lock) {
+ while (_InterlockedCompareExchange((volatile long*)lock, ~0, 0) != 0) {
+ Sleep(0);
+ }
+}
+
+extern "C" void OSSpinLockUnlock(volatile OSSpinLock* lock) {
+ _InterlockedExchange((volatile long*)lock, 0);
+}
+
+extern "C" bool OSSpinLockTry(volatile OSSpinLock* lock) {
+ return (_InterlockedCompareExchange((volatile long*)lock, ~0, 0) == 0);
+}
\ No newline at end of file
diff --git a/tools/WOCStdLib/lib/WOCStdLibLib.vcxproj b/tools/WOCStdLib/lib/WOCStdLibLib.vcxproj
index 586c1c7135..1819a32c68 100644
--- a/tools/WOCStdLib/lib/WOCStdLibLib.vcxproj
+++ b/tools/WOCStdLib/lib/WOCStdLibLib.vcxproj
@@ -1,6 +1,5 @@
-
Debug
@@ -18,13 +17,11 @@
Release
Win32
-
-
+
StaticLibrary
-
@@ -40,6 +37,7 @@
+
{17D1A01F-08ED-4903-BAE1-D446150CC7D5}
diff --git a/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.dll b/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.dll
index 177ac32218..19d8789f29 100644
--- a/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.dll
+++ b/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.dll
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:047e427337bca9a2a73e2c462ef7a92aefab1efefda28153ac99948fbdd5c765
-size 190464
+oid sha256:c1075c6a3bec34145967a1383296b7ec59196234fdb3612e766811613a0cc113
+size 194560
diff --git a/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.lib b/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.lib
index 602b72042c..af6458c730 100644
--- a/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.lib
+++ b/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.lib
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:468c6a10c86e545d6ff405aeb08122e179dcaee2d2f6587ec6fdef60ca3b63f5
-size 19764
+oid sha256:7c5b287c058a55c9e9d281bf24caa9ca9f62aacf70e886231929f9f402c060f8
+size 20776
diff --git a/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.pdb b/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.pdb
index 78e4e0832c..ea11e6d2b0 100644
--- a/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.pdb
+++ b/tools/deps/prebuilt/Universal Windows/ARM/Debug/libdispatch.pdb
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:519d29ec418c22157d047a76b682f2640e8d8cac2de5878c78f1f0222019542c
-size 2240512
+oid sha256:d1788f4ad5521ad3a857bca4014265df6df60e7d3ca24ad918037eb0cbcaef51
+size 1634304
diff --git a/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.dll b/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.dll
index bc2b1476e6..5c94578c7e 100644
--- a/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.dll
+++ b/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.dll
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:efbc9789aab69064e8dbbebae406717c4d407db5ec50a59216dbdf0c3cf54e5a
-size 57344
+oid sha256:e323881420bc89aec34878e7e23623b6f0f2330ea39ae424c8669c30c3c3c8df
+size 56320
diff --git a/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.lib b/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.lib
index 159f7a983d..af6458c730 100644
--- a/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.lib
+++ b/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.lib
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:31b1386a8d8e6b493a10a58359fd19f3d1542b4a079f0333e6227bba8514fda2
-size 19764
+oid sha256:7c5b287c058a55c9e9d281bf24caa9ca9f62aacf70e886231929f9f402c060f8
+size 20776
diff --git a/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.pdb b/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.pdb
index e45f082c38..d4ab968124 100644
--- a/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.pdb
+++ b/tools/deps/prebuilt/Universal Windows/ARM/Release/libdispatch.pdb
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:27d3c365a731678aba136597787384cddd5f16b9d85435d7761b185420d17273
-size 1609728
+oid sha256:3e1145d21fd9a613b9dd619782b6482e9866bbcc9a028002f4d3a7d7e9f32ea4
+size 1626112
diff --git a/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.dll b/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.dll
index 2de0107607..f369516af4 100644
--- a/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.dll
+++ b/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.dll
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:63944e6091d708d0ae10d93c68cd297da77ed25df62b1686f7d5cb7a3c9b0576
-size 137216
+oid sha256:d83fd6b9fa8c9477dd0d38b83c65af29307ea67b64a1b79d74c5bdb88a819ae3
+size 136192
diff --git a/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.lib b/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.lib
index 8994fdba74..10dea5a488 100644
--- a/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.lib
+++ b/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.lib
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ab5c2ed2b8f58a24ee41a62ebdf81a2a66423df52fb9eaef5bf73ec4b64ec30e
-size 20120
+oid sha256:c076d0174b382f58b43a2cdfcf79d30897b820a532da2fa84d47f7fc37775380
+size 21150
diff --git a/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.pdb b/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.pdb
index 476600f56e..3a4f1a2401 100644
--- a/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.pdb
+++ b/tools/deps/prebuilt/Universal Windows/x86/Debug/libdispatch.pdb
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2807d53d92db40b7d2b80f8732e58eb8b23acd92b6ead882bef1b6e5b6261d3d
-size 2207744
+oid sha256:646dbcc1614f9572c3acbf33ee917b2c654e00a5d4dfd376929d40380d6d92d3
+size 1617920
diff --git a/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.dll b/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.dll
index c8d247706f..8f9c599534 100644
--- a/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.dll
+++ b/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.dll
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:72cfcf9acd7aaa92d620d23a81ae56b15c958eb1984652c557fadcee15fc22b4
-size 53248
+oid sha256:4e6413e8b8df9a36a49c42243c654543778cb19f8645a087b6d32059b412c52c
+size 52736
diff --git a/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.lib b/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.lib
index f018667225..10dea5a488 100644
--- a/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.lib
+++ b/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.lib
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:9032c4fd2931519af723de703b0f6cd0cc07cc4ab869f6daaddc901e1a8b43a6
-size 20120
+oid sha256:c076d0174b382f58b43a2cdfcf79d30897b820a532da2fa84d47f7fc37775380
+size 21150
diff --git a/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.pdb b/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.pdb
index 00beecd0a5..1cf8ba5cdb 100644
--- a/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.pdb
+++ b/tools/deps/prebuilt/Universal Windows/x86/Release/libdispatch.pdb
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:7958100ed7fd752b7ce30c7e5cb13364402e6746bb37babf25dc6aef876373a1
-size 1642496
+oid sha256:f6b58c29d9da77f542b4aa55383260b7a538af962d120d8c31e7c61a1eb68d01
+size 1658880
diff --git a/tools/deps/prebuilt/include/dispatch/queue.h b/tools/deps/prebuilt/include/dispatch/queue.h
index 08f5bc3833..e4625e8df4 100644
--- a/tools/deps/prebuilt/include/dispatch/queue.h
+++ b/tools/deps/prebuilt/include/dispatch/queue.h
@@ -179,6 +179,133 @@ dispatch_async_f(dispatch_queue_t queue,
void *context,
dispatch_function_t work);
+/*!
+ * @function dispatch_barrier_async
+ *
+ * @abstract
+ * Submits a barrier block for asynchronous execution on a dispatch queue.
+ *
+ * @discussion
+ * Submits a block to a dispatch queue like dispatch_async(), but marks that
+ * block as a barrier (relevant only on DISPATCH_QUEUE_CONCURRENT queues).
+ *
+ * See dispatch_async() for details.
+ *
+ * @param queue
+ * The target dispatch queue to which the block is submitted.
+ * The system will hold a reference on the target queue until the block
+ * has finished.
+ * The result of passing NULL in this parameter is undefined.
+ *
+ * @param block
+ * The block to submit to the target dispatch queue. This function performs
+ * Block_copy() and Block_release() on behalf of callers.
+ * The result of passing NULL in this parameter is undefined.
+ */
+
+#ifdef __BLOCKS__
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_4_0)
+DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
+void
+dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
+#endif
+
+/*!
+ * @function dispatch_barrier_async_f
+ *
+ * @abstract
+ * Submits a barrier function for asynchronous execution on a dispatch queue.
+ *
+ * @discussion
+ * Submits a function to a dispatch queue like dispatch_async_f(), but marks
+ * that function as a barrier (relevant only on DISPATCH_QUEUE_CONCURRENT
+ * queues).
+ *
+ * See dispatch_async_f() for details.
+ *
+ * @param queue
+ * The target dispatch queue to which the function is submitted.
+ * The system will hold a reference on the target queue until the function
+ * has returned.
+ * The result of passing NULL in this parameter is undefined.
+ *
+ * @param context
+ * The application-defined context parameter to pass to the function.
+ *
+ * @param work
+ * The application-defined function to invoke on the target queue. The first
+ * parameter passed to this function is the context provided to
+ * dispatch_barrier_async_f().
+ * The result of passing NULL in this parameter is undefined.
+ */
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_4_0)
+DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NONNULL3 DISPATCH_NOTHROW
+void
+dispatch_barrier_async_f(dispatch_queue_t queue,
+ void *_Nullable context,
+ dispatch_function_t work);
+
+/*!
+ * @function dispatch_barrier_sync_f
+ *
+ * @abstract
+ * Submits a barrier function for synchronous execution on a dispatch queue.
+ *
+ * @discussion
+ * Submits a function to a dispatch queue like dispatch_sync_f(), but marks that
+ * fuction as a barrier (relevant only on DISPATCH_QUEUE_CONCURRENT queues).
+ *
+ * See dispatch_sync_f() for details.
+ *
+ * @param queue
+ * The target dispatch queue to which the function is submitted.
+ * The result of passing NULL in this parameter is undefined.
+ *
+ * @param context
+ * The application-defined context parameter to pass to the function.
+ *
+ * @param work
+ * The application-defined function to invoke on the target queue. The first
+ * parameter passed to this function is the context provided to
+ * dispatch_barrier_sync_f().
+ * The result of passing NULL in this parameter is undefined.
+ */
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_4_0)
+DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NONNULL3 DISPATCH_NOTHROW
+void
+dispatch_barrier_sync_f(dispatch_queue_t queue,
+ void *_Nullable context,
+ dispatch_function_t work);
+
+/*!
+ * @function dispatch_barrier_sync
+ *
+ * @abstract
+ * Submits a barrier block for synchronous execution on a dispatch queue.
+ *
+ * @discussion
+ * Submits a block to a dispatch queue like dispatch_sync(), but marks that
+ * block as a barrier (relevant only on DISPATCH_QUEUE_CONCURRENT queues).
+ *
+ * See dispatch_sync() for details.
+ *
+ * @param queue
+ * The target dispatch queue to which the block is submitted.
+ * The result of passing NULL in this parameter is undefined.
+ *
+ * @param block
+ * The block to be invoked on the target dispatch queue.
+ * The result of passing NULL in this parameter is undefined.
+ */
+#ifdef __BLOCKS__
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_4_0)
+DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
+void
+dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
+#endif
+
/*!
* @function dispatch_sync
*
@@ -592,6 +719,92 @@ DISPATCH_EXPORT DISPATCH_PURE DISPATCH_WARN_RESULT DISPATCH_NOTHROW
dispatch_queue_t
dispatch_get_current_thread_queue();
+/*!
+* @function dispatch_queue_set_specific
+*
+* @abstract
+* Sets the key/value data for the specified dispatch queue.
+*
+* @discussion
+* Use this method to associate custom context data with a dispatch queue.
+* Blocks executing on the queue can use the dispatch_get_specific function
+* to retrieve this data while they are running.
+*
+* @param queue
+* The queue on which to set the specified key/value data. This parameter must not be NULL.
+*
+* @param key
+* The key you want to use to identify the associated context data. Keys are only compared
+* as pointers and are never dereferenced. Thus, you can use a pointer to a static variable
+* for a specific subsystem or any other value that allows you to identify the value uniquely.
+* Specifying a pointer to a string constant is not recommended. NULL is not a valid value
+* for the key and attempts to set context data with a NULL key are ignored.
+*
+* @param context
+* The context data to associate with key. This parameter may be NULL.
+*
+* @param destructor
+* A destructor function that you can use to release your context data. This parameter may be
+* NULL. If context is NULL, your destructor function is ignored.
+*/
+
+__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
+DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NOTHROW
+void dispatch_queue_set_specific(dispatch_queue_t queue, const void *key, void *context, dispatch_function_t destructor);
+
+/*!
+* @function dispatch_queue_get_specific
+*
+* @abstract
+* Gets the value for the key associated with the specified dispatch queue.
+*
+* @discussion
+* You can use this method to get the context data associated with a specific dispatch queue.
+* Blocks executing on a queue can use the dispatch_get_specific function to retrieve the
+* context associated with that specific queue instead.
+*
+* @param queue
+* The queue containing the desired context data. This parameter must not be NULL.
+*
+* @param key
+* The key that identifies the associated context data. Keys are only compared as
+* pointers and are never dereferenced. Thus, you can use a pointer to a static variable
+* for a specific subsystem or any other value that allows you to identify the value uniquely.
+* Specifying a pointer to a string constant is not recommended.
+*
+* @result
+* The context data associated with key or NULL if no context was found.
+*/
+__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
+DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_PURE DISPATCH_WARN_RESULT
+DISPATCH_NOTHROW
+void * dispatch_queue_get_specific(dispatch_queue_t queue, const void *key);
+
+/*!
+* @function dispatch_get_specific
+*
+* @abstract
+* Returns the value for the key associated with the current dispatch queue.
+*
+* @discussion
+* This function is intended to be called from a block executing in a dispatch queue.
+* You use it to obtain context data associated with the queue. Calling this method
+* from code not running in a dispatch queue returns NULL because there is no queue
+* to provide context.
+*
+* @param key
+* The key associated with the dispatch queue on which the current block is executing.
+* Keys are only compared as pointers and never dereferenced. Passing a string constant
+* directly is not recommended.
+*
+* @result
+* The context value for the specified key; otherwise NULL if the key was not set for
+* the queue (or its target queue) or the queue is a global concurrent queue.
+*/
+__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
+DISPATCH_EXPORT DISPATCH_PURE DISPATCH_WARN_RESULT DISPATCH_NOTHROW
+void * dispatch_get_specific(const void *key);
+
__DISPATCH_END_DECLS
-#endif
+#endif
\ No newline at end of file
diff --git a/tools/deps/prebuilt/include/dispatch/queue_internal.h b/tools/deps/prebuilt/include/dispatch/queue_internal.h
index 3a332dfa80..e1eef4378f 100644
--- a/tools/deps/prebuilt/include/dispatch/queue_internal.h
+++ b/tools/deps/prebuilt/include/dispatch/queue_internal.h
@@ -2,19 +2,19 @@
* Copyright (c) 2008-2009 Apple Inc. All rights reserved.
*
* @APPLE_APACHE_LICENSE_HEADER_START@
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
+ *
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
@@ -32,45 +32,63 @@
#include // for HeaderDoc
#endif
-#define DISPATCH_OBJ_ASYNC_BIT 0x1
-#define DISPATCH_OBJ_BARRIER_BIT 0x2
-#define DISPATCH_OBJ_GROUP_BIT 0x4
+#define DISPATCH_OBJ_ASYNC_BIT 0x1
+#define DISPATCH_OBJ_BARRIER_BIT 0x2
+#define DISPATCH_OBJ_GROUP_BIT 0x4
// vtables are pointers far away from the low page in memory
-#define DISPATCH_OBJ_IS_VTABLE(x) ((uintptr_t)(x)->do_vtable > 127ul)
+#define DISPATCH_OBJ_IS_VTABLE(x) ((uintptr_t)(x)->do_vtable > 127ul)
struct dispatch_queue_vtable_s {
- DISPATCH_VTABLE_HEADER(dispatch_queue_s);
+ DISPATCH_VTABLE_HEADER(dispatch_queue_s);
};
extern const struct dispatch_queue_vtable_s _dispatch_queue_vtable;
-#define DISPATCH_QUEUE_MIN_LABEL_SIZE 64
+#define DISPATCH_QUEUE_MIN_LABEL_SIZE 64
+
+DISPATCH_DECL(dispatch_queue_specific_list);
+DISPATCH_DECL(dispatch_queue_specific);
#ifndef DISPATCH_NO_LEGACY
-#define DISPATCH_QUEUE_HEADER \
- intptr_t dq_running; \
- intptr_t dq_width; \
- struct dispatch_object_s* dq_items_tail; \
- struct dispatch_object_s* volatile dq_items_head; \
- intptr_t dq_serialnum; \
- void* dq_finalizer_ctxt; \
- dispatch_queue_finalizer_function_t dq_finalizer_func
+#define DISPATCH_QUEUE_HEADER \
+ intptr_t dq_running; \
+ intptr_t dq_width; \
+ struct dispatch_object_s *dq_items_tail; \
+ struct dispatch_object_s *volatile dq_items_head; \
+ intptr_t dq_serialnum; \
+ void *dq_finalizer_ctxt; \
+ struct dispatch_queue_s *dq_specific_q; \
+ struct dispatch_queue_specific_list_s *dq_specific_list; \
+ dispatch_queue_finalizer_function_t dq_finalizer_func
#else
-#define DISPATCH_QUEUE_HEADER \
- intptr_t dq_running; \
- intptr_t dq_width; \
- struct dispatch_object_s* dq_items_tail; \
- struct dispatch_object_s* volatile dq_items_head; \
- intptr_t dq_serialnum; \
- void* dq_finalizer_ctxt; \
- void* dq_manually_drained; \
- bool dq_is_manually_draining
+#define DISPATCH_QUEUE_HEADER \
+ intptr_t dq_running; \
+ intptr_t dq_width; \
+ struct dispatch_object_s *dq_items_tail; \
+ struct dispatch_object_s *volatile dq_items_head; \
+ intptr_t dq_serialnum; \
+ void *dq_finalizer_ctxt; \
+ struct dispatch_queue_s *dq_specific_q; \
+ struct dispatch_queue_specific_list_s *dq_specific_list; \
+ void* dq_manually_drained; \
+ bool dq_is_manually_draining
#endif
+struct dispatch_queue_specific_list_s {
+ TAILQ_HEAD(dispatch_queue_specific_head_s, dispatch_queue_specific_s) context_list;
+};
+
+struct dispatch_queue_specific_s {
+ const void *key;
+ void *context;
+ dispatch_function_t destructor;
+ TAILQ_ENTRY(dispatch_queue_specific_s) specific;
+};
+
struct dispatch_queue_s {
- DISPATCH_STRUCT_HEADER(dispatch_queue_s, dispatch_queue_vtable_s);
- DISPATCH_QUEUE_HEADER;
- char dq_label[DISPATCH_QUEUE_MIN_LABEL_SIZE]; // must be last
+ DISPATCH_STRUCT_HEADER(dispatch_queue_s, dispatch_queue_vtable_s);
+ DISPATCH_QUEUE_HEADER;
+ char dq_label[DISPATCH_QUEUE_MIN_LABEL_SIZE]; // must be last
};
extern struct dispatch_queue_s _dispatch_mgr_q;
@@ -81,23 +99,25 @@ extern struct dispatch_queue_s _dispatch_root_queues[];
void _dispatch_queue_init(dispatch_queue_t dq);
void _dispatch_queue_drain(dispatch_queue_t dq);
void _dispatch_queue_dispose(dispatch_queue_t dq);
-void _dispatch_queue_push_list_slow(dispatch_queue_t dq, struct dispatch_object_s* obj);
+void _dispatch_queue_push_list_slow(dispatch_queue_t dq, struct dispatch_object_s *obj);
void _dispatch_queue_serial_drain_till_empty(dispatch_queue_t dq);
void _dispatch_force_cache_cleanup(void);
DISPATCH_INLINE
-static void _dispatch_queue_push_list(dispatch_queue_t dq, dispatch_object_t _head, dispatch_object_t _tail) {
- struct dispatch_object_s *prev, *head = _head._do, *tail = _tail._do;
-
- tail->do_next = NULL;
- prev = fastpath(dispatch_atomic_xchg_pointer(&dq->dq_items_tail, tail));
- if (prev) {
- // if we crash here with a value less than 0x1000, then we are at a known bug in client code
- // for example, see _dispatch_queue_dispose or _dispatch_atfork_child
- prev->do_next = head;
- } else {
- _dispatch_queue_push_list_slow(dq, head);
- }
+static void
+_dispatch_queue_push_list(dispatch_queue_t dq, dispatch_object_t _head, dispatch_object_t _tail)
+{
+ struct dispatch_object_s *prev, *head = _head._do, *tail = _tail._do;
+
+ tail->do_next = NULL;
+ prev = fastpath(dispatch_atomic_xchg_pointer(&dq->dq_items_tail, tail));
+ if (prev) {
+ // if we crash here with a value less than 0x1000, then we are at a known bug in client code
+ // for example, see _dispatch_queue_dispose or _dispatch_atfork_child
+ prev->do_next = head;
+ } else {
+ _dispatch_queue_push_list_slow(dq, head);
+ }
}
#define _dispatch_queue_push(x, y) _dispatch_queue_push_list((x), (y), (y))
@@ -107,15 +127,16 @@ static void _dispatch_queue_push_list(dispatch_queue_t dq, dispatch_object_t _he
#if DISPATCH_DEBUG
void dispatch_debug_queue(dispatch_queue_t dq, const char* str);
#else
-static DISPATCH_INLINE void dispatch_debug_queue(dispatch_queue_t dq DISPATCH_UNUSED, const char* str DISPATCH_UNUSED) {
-}
+static DISPATCH_INLINE void dispatch_debug_queue(dispatch_queue_t dq DISPATCH_UNUSED, const char* str DISPATCH_UNUSED) {}
#endif
size_t dispatch_queue_debug(dispatch_queue_t dq, char* buf, size_t bufsiz);
size_t dispatch_queue_debug_attr(dispatch_queue_t dq, char* buf, size_t bufsiz);
-static DISPATCH_INLINE dispatch_queue_t _dispatch_queue_get_current(void) {
- return _dispatch_thread_getspecific(dispatch_queue_key);
+static DISPATCH_INLINE dispatch_queue_t
+_dispatch_queue_get_current(void)
+{
+ return _dispatch_thread_getspecific(dispatch_queue_key);
}
-#endif
+#endif
\ No newline at end of file
diff --git a/tools/include/WOCStdLib/libkern/OSAtomic.h b/tools/include/WOCStdLib/libkern/OSAtomic.h
index 97d97a23a0..5b80248c34 100644
--- a/tools/include/WOCStdLib/libkern/OSAtomic.h
+++ b/tools/include/WOCStdLib/libkern/OSAtomic.h
@@ -19,7 +19,13 @@
#ifndef _OSATOMIC_H_
#define _OSATOMIC_H_
+#define OS_SPINLOCK_INIT 0
+
+#include
+#include
+
typedef int __int32_t;
+typedef __int32_t OSSpinLock;
__BEGIN_DECLS
@@ -50,6 +56,10 @@ static __inline __int32_t OSAtomicDecrement32Barrier(volatile __int32_t *val)
return OSAtomicAdd32Barrier(-1, val);
}
+void OSSpinLockLock(volatile OSSpinLock *lock);
+void OSSpinLockUnlock(volatile OSSpinLock *lock);
+bool OSSpinLockTry(volatile OSSpinLock *lock);
+
__END_DECLS
#endif
\ No newline at end of file