libdispatch update
[platform/upstream/gcd.git] / dispatch-1.0 / testing / dispatch_apply.c
1 /*
2  * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
3  *
4  * @APPLE_APACHE_LICENSE_HEADER_START@
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  * @APPLE_APACHE_LICENSE_HEADER_END@
19  */
20
21 #include <dispatch/dispatch.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <libkern/OSAtomic.h>
27 #include <sys/types.h>
28 #include <sys/sysctl.h>
29
30 #include <bsdtests.h>
31 #include "dispatch_test.h"
32
33 static volatile int32_t busy_threads_started, busy_threads_finished;
34
35 /*
36  * Keep a thread busy, spinning on the CPU.
37  */
38 #if TARGET_OS_EMBEDDED
39 // iPhone 4
40 #define ITERS_PER_SECOND 50000000UL
41 #else
42 // On a 2.7 4-core i5 iMac12,2, one thread of this loop runs at ROUGHLY:
43 #define ITERS_PER_SECOND 1000000000UL
44 #endif
45
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.
48  */
49 static volatile unsigned int busythread_useless;
50 void busythread(void *ignored)
51 {
52         (void)ignored;
53         uint64_t i = 0, j = 0;
54
55         OSAtomicIncrement32(&busy_threads_started);
56
57         for(i = 0; i < 2*ITERS_PER_SECOND; i++)
58         {
59                 if(i == 500000) { j -= busythread_useless; }
60                 j += i;
61         }
62
63         OSAtomicIncrement32(&busy_threads_finished);
64 }
65
66 /*
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.
70  *
71  * <rdar://problem/10718199> dispatch_apply should not block waiting on other
72  * threads while calling thread is available
73  */
74 void test_apply_contended(dispatch_queue_t dq)
75 {
76         uint32_t activecpu;
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();
81
82         for(tIndex = 0; tIndex < n_threads; tIndex++) {
83                 dispatch_group_async_f(grp, dq, NULL, busythread);
84         }
85
86         // Spin until all the threads have actually started
87         while(busy_threads_started < n_threads) {
88                 usleep(1);
89         }
90
91         volatile __block int32_t count = 0;
92         const int32_t final = 32;
93
94         unsigned int before = busy_threads_started;
95         dispatch_apply(final, dq, ^(size_t i __attribute__((unused))) {
96                 OSAtomicIncrement32(&count);
97         });
98         unsigned int after = busy_threads_finished;
99
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);
103
104         dispatch_group_wait(grp, DISPATCH_TIME_FOREVER);
105         dispatch_release(grp);
106
107 }
108
109 int
110 main(void)
111 {
112         dispatch_test_start("Dispatch Apply");
113
114         volatile __block int32_t count = 0;
115         const int32_t final = 32;
116
117         dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
118         test_ptr_notnull("dispatch_get_global_queue", queue);
119
120         dispatch_apply(final, queue, ^(size_t i __attribute__((unused))) {
121                 OSAtomicIncrement32(&count);
122         });
123         test_long("count", count, final);
124
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);
130                         });
131                 });
132         });
133         test_long("nested count", count, final * final * final);
134
135         test_apply_contended(queue);
136
137         test_stop();
138
139         return 0;
140 }