2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
21 #include <dispatch/dispatch.h>
26 #include <libkern/OSAtomic.h>
27 #include <sys/types.h>
28 #include <sys/sysctl.h>
31 #include "dispatch_test.h"
33 static volatile int32_t busy_threads_started, busy_threads_finished;
36 * Keep a thread busy, spinning on the CPU.
38 #if TARGET_OS_EMBEDDED
40 #define ITERS_PER_SECOND 50000000UL
42 // On a 2.7 4-core i5 iMac12,2, one thread of this loop runs at ROUGHLY:
43 #define ITERS_PER_SECOND 1000000000UL
46 /* Fiddling with j in the middle and hitting this global will hopefully keep
47 * the optimizer from cutting the whole thing out as dead code.
49 static volatile unsigned int busythread_useless;
50 void busythread(void *ignored)
53 uint64_t i = 0, j = 0;
55 OSAtomicIncrement32(&busy_threads_started);
57 for(i = 0; i < 2*ITERS_PER_SECOND; i++)
59 if(i == 500000) { j -= busythread_useless; }
63 OSAtomicIncrement32(&busy_threads_finished);
67 * Test that dispatch_apply can make progress and finish, even if there are
68 * so many other running and unblocked workqueue threads that the apply's
69 * helper threads never get a chance to come up.
71 * <rdar://problem/10718199> dispatch_apply should not block waiting on other
72 * threads while calling thread is available
74 void test_apply_contended(dispatch_queue_t dq)
77 size_t s = sizeof(activecpu);
78 sysctlbyname("hw.activecpu", &activecpu, &s, NULL, 0);
79 int tIndex, n_threads = activecpu;
80 dispatch_group_t grp = dispatch_group_create();
82 for(tIndex = 0; tIndex < n_threads; tIndex++) {
83 dispatch_group_async_f(grp, dq, NULL, busythread);
86 // Spin until all the threads have actually started
87 while(busy_threads_started < n_threads) {
91 volatile __block int32_t count = 0;
92 const int32_t final = 32;
94 unsigned int before = busy_threads_started;
95 dispatch_apply(final, dq, ^(size_t i __attribute__((unused))) {
96 OSAtomicIncrement32(&count);
98 unsigned int after = busy_threads_finished;
100 test_long("contended: threads started before apply", before, n_threads);
101 test_long("contended: count", count, final);
102 test_long("contended: threads finished before apply", after, 0);
104 dispatch_group_wait(grp, DISPATCH_TIME_FOREVER);
105 dispatch_release(grp);
112 dispatch_test_start("Dispatch Apply");
114 volatile __block int32_t count = 0;
115 const int32_t final = 32;
117 dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
118 test_ptr_notnull("dispatch_get_global_queue", queue);
120 dispatch_apply(final, queue, ^(size_t i __attribute__((unused))) {
121 OSAtomicIncrement32(&count);
123 test_long("count", count, final);
125 count = 0; // rdar://problem/9294578
126 dispatch_apply(final, queue, ^(size_t i __attribute__((unused))) {
127 dispatch_apply(final, queue, ^(size_t ii __attribute__((unused))) {
128 dispatch_apply(final, queue, ^(size_t iii __attribute__((unused))) {
129 OSAtomicIncrement32(&count);
133 test_long("nested count", count, final * final * final);
135 test_apply_contended(queue);