2 * Copyright (c) 2008-2013 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@
24 #undef dispatch_once_f
27 typedef struct _dispatch_once_waiter_s
{
28 volatile struct _dispatch_once_waiter_s
*volatile dow_next
;
29 dispatch_thread_event_s dow_event
;
30 mach_port_t dow_thread
;
31 } *_dispatch_once_waiter_t
;
33 #define DISPATCH_ONCE_DONE ((_dispatch_once_waiter_t)~0l)
37 dispatch_once(dispatch_once_t
*val
, dispatch_block_t block
)
39 dispatch_once_f(val
, block
, _dispatch_Block_invoke(block
));
43 #if DISPATCH_ONCE_INLINE_FASTPATH
44 #define DISPATCH_ONCE_SLOW_INLINE inline DISPATCH_ALWAYS_INLINE
46 #define DISPATCH_ONCE_SLOW_INLINE DISPATCH_NOINLINE
47 #endif // DISPATCH_ONCE_INLINE_FASTPATH
49 DISPATCH_ONCE_SLOW_INLINE
51 dispatch_once_f_slow(dispatch_once_t
*val
, void *ctxt
, dispatch_function_t func
)
53 #if DISPATCH_GATE_USE_FOR_DISPATCH_ONCE
54 dispatch_once_gate_t l
= (dispatch_once_gate_t
)val
;
56 if (_dispatch_once_gate_tryenter(l
)) {
57 _dispatch_client_callout(ctxt
, func
);
58 _dispatch_once_gate_broadcast(l
);
60 _dispatch_once_gate_wait(l
);
63 _dispatch_once_waiter_t
volatile *vval
= (_dispatch_once_waiter_t
*)val
;
64 struct _dispatch_once_waiter_s dow
= { };
65 _dispatch_once_waiter_t tail
= &dow
, next
, tmp
;
66 dispatch_thread_event_t event
;
68 if (os_atomic_cmpxchg(vval
, NULL
, tail
, acquire
)) {
69 dow
.dow_thread
= _dispatch_tid_self();
70 _dispatch_client_callout(ctxt
, func
);
72 next
= (_dispatch_once_waiter_t
)_dispatch_once_xchg_done(val
);
73 while (next
!= tail
) {
74 tmp
= (_dispatch_once_waiter_t
)_dispatch_wait_until(next
->dow_next
);
75 event
= &next
->dow_event
;
77 _dispatch_thread_event_signal(event
);
80 _dispatch_thread_event_init(&dow
.dow_event
);
83 if (next
== DISPATCH_ONCE_DONE
) {
86 if (os_atomic_cmpxchgv(vval
, next
, tail
, &next
, release
)) {
87 dow
.dow_thread
= next
->dow_thread
;
90 pthread_priority_t pp
= _dispatch_get_priority();
91 _dispatch_thread_override_start(dow
.dow_thread
, pp
, val
);
93 _dispatch_thread_event_wait(&dow
.dow_event
);
95 _dispatch_thread_override_end(dow
.dow_thread
, val
);
100 _dispatch_thread_event_destroy(&dow
.dow_event
);
107 dispatch_once_f(dispatch_once_t
*val
, void *ctxt
, dispatch_function_t func
)
109 #if !DISPATCH_ONCE_INLINE_FASTPATH
110 if (likely(os_atomic_load(val
, acquire
) == DLOCK_ONCE_DONE
)) {
113 #endif // !DISPATCH_ONCE_INLINE_FASTPATH
114 return dispatch_once_f_slow(val
, ctxt
, func
);