]> git.saurik.com Git - apple/libdispatch.git/blob - src/block.cpp
libdispatch-913.30.4.tar.gz
[apple/libdispatch.git] / src / block.cpp
1 /*
2 * Copyright (c) 2015 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 #ifdef __BLOCKS__
22
23 #if __cplusplus < 201103L
24 #error Must build with C++11 or later
25 #endif
26
27 #if __has_feature(cxx_exceptions)
28 #error Must build without C++ exceptions
29 #endif
30
31 extern "C" {
32 #include "internal.h"
33 }
34
35 // NOTE: this file must not contain any atomic operations
36
37 #if DISPATCH_DEBUG && DISPATCH_BLOCK_PRIVATE_DATA_DEBUG
38 #define _dispatch_block_private_data_debug(msg, ...) \
39 _dispatch_debug("block_private[%p]: " msg, (this), ##__VA_ARGS__)
40 #else
41 #define _dispatch_block_private_data_debug(msg, ...)
42 #endif
43
44 #pragma mark -
45 #pragma mark _dispatch_block_create
46
47 // rdar://20766742 C++ helpers to enable block capture of vouchers and groups
48
49 struct dispatch_block_private_data_s {
50 DISPATCH_BLOCK_PRIVATE_DATA_HEADER();
51 static void* operator new(size_t) = delete;
52 static void* operator new [] (size_t) = delete;
53 explicit inline DISPATCH_ALWAYS_INLINE dispatch_block_private_data_s(
54 dispatch_block_flags_t flags, voucher_t voucher,
55 pthread_priority_t priority, dispatch_block_t block) noexcept :
56 dbpd_magic(), dbpd_flags(flags), dbpd_atomic_flags(),
57 dbpd_performed(), dbpd_priority(priority), dbpd_voucher(voucher),
58 dbpd_block(block), dbpd_group(), dbpd_queue(), dbpd_thread()
59 {
60 // stack structure constructor, no releases on destruction
61 _dispatch_block_private_data_debug("create, block: %p", dbpd_block);
62 }
63 inline DISPATCH_ALWAYS_INLINE dispatch_block_private_data_s(
64 dispatch_block_private_data_s const &o) noexcept :
65 dbpd_magic(DISPATCH_BLOCK_PRIVATE_DATA_MAGIC),
66 dbpd_flags(o.dbpd_flags), dbpd_atomic_flags(), dbpd_performed(),
67 dbpd_priority(o.dbpd_priority), dbpd_voucher(o.dbpd_voucher),
68 dbpd_block(), dbpd_group(), dbpd_queue(), dbpd_thread()
69 {
70 // copy constructor, create copy with retained references
71 if (dbpd_voucher) voucher_retain(dbpd_voucher);
72 if (o.dbpd_block) dbpd_block = _dispatch_Block_copy(o.dbpd_block);
73 _dispatch_block_private_data_debug("copy from %p, block: %p from %p",
74 &o, dbpd_block, o.dbpd_block);
75 if (!o.dbpd_magic) return; // No group in initial copy of stack object
76 dbpd_group = _dispatch_group_create_and_enter();
77 }
78 inline DISPATCH_ALWAYS_INLINE ~dispatch_block_private_data_s() noexcept
79 {
80 _dispatch_block_private_data_debug("destroy%s, block: %p",
81 dbpd_magic ? "" : " (stack)", dbpd_block);
82 if (dbpd_magic != DISPATCH_BLOCK_PRIVATE_DATA_MAGIC) return;
83 if (dbpd_group) {
84 if (!dbpd_performed) dispatch_group_leave(dbpd_group);
85 ((void (*)(dispatch_group_t))dispatch_release)(dbpd_group);
86 }
87 if (dbpd_queue) {
88 ((void (*)(os_mpsc_queue_t, uint16_t))
89 _os_object_release_internal_n)(dbpd_queue, 2);
90 }
91 if (dbpd_block) Block_release(dbpd_block);
92 if (dbpd_voucher) voucher_release(dbpd_voucher);
93 }
94 };
95
96 dispatch_block_t
97 _dispatch_block_create(dispatch_block_flags_t flags, voucher_t voucher,
98 pthread_priority_t pri, dispatch_block_t block)
99 {
100 struct dispatch_block_private_data_s dbpds(flags, voucher, pri, block);
101 return _dispatch_Block_copy(^{
102 // Capture stack object: invokes copy constructor (17094902)
103 (void)dbpds;
104 _dispatch_block_invoke_direct(&dbpds);
105 });
106 }
107
108 extern "C" {
109 // The compiler hides the name of the function it generates, and changes it if
110 // we try to reference it directly, but the linker still sees it.
111 extern void DISPATCH_BLOCK_SPECIAL_INVOKE(void *)
112 #ifdef __linux__
113 asm("___dispatch_block_create_block_invoke");
114 #else
115 asm("____dispatch_block_create_block_invoke");
116 #endif
117 void (*_dispatch_block_special_invoke)(void*) = DISPATCH_BLOCK_SPECIAL_INVOKE;
118 }
119
120 #endif // __BLOCKS__