2 * Copyright (c) 2015 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@
23 #if __cplusplus < 201103L
24 #error Must build with C++11 or later
27 #if __has_feature(cxx_exceptions)
28 #error Must build without C++ exceptions
35 #if DISPATCH_DEBUG && DISPATCH_BLOCK_PRIVATE_DATA_DEBUG
36 #define _dispatch_block_private_data_debug(msg, ...) \
37 _dispatch_debug("block_private[%p]: " msg, (this), ##__VA_ARGS__)
39 #define _dispatch_block_private_data_debug(msg, ...)
43 #pragma mark _dispatch_block_create
45 // rdar://20766742 C++ helpers to enable block capture of vouchers and groups
47 struct dispatch_block_private_data_s
{
48 DISPATCH_BLOCK_PRIVATE_DATA_HEADER();
49 static void* operator new(size_t) = delete;
50 static void* operator new [] (size_t) = delete;
51 explicit inline DISPATCH_ALWAYS_INLINE
dispatch_block_private_data_s(
52 dispatch_block_flags_t flags
, voucher_t voucher
,
53 pthread_priority_t priority
, dispatch_block_t block
) noexcept :
54 dbpd_magic(), dbpd_flags(flags
), dbpd_atomic_flags(),
55 dbpd_performed(), dbpd_priority(priority
), dbpd_voucher(voucher
),
56 dbpd_block(block
), dbpd_group(), dbpd_queue(), dbpd_thread()
58 // stack structure constructor, no releases on destruction
59 _dispatch_block_private_data_debug("create, block: %p", dbpd_block
);
61 inline DISPATCH_ALWAYS_INLINE
dispatch_block_private_data_s(
62 dispatch_block_private_data_s
const &o
) noexcept :
63 dbpd_magic(DISPATCH_BLOCK_PRIVATE_DATA_MAGIC
),
64 dbpd_flags(o
.dbpd_flags
), dbpd_atomic_flags(), dbpd_performed(),
65 dbpd_priority(o
.dbpd_priority
), dbpd_voucher(o
.dbpd_voucher
),
66 dbpd_block(), dbpd_group(), dbpd_queue(), dbpd_thread()
68 // copy constructor, create copy with retained references
69 if (dbpd_voucher
) voucher_retain(dbpd_voucher
);
70 if (o
.dbpd_block
) dbpd_block
= _dispatch_Block_copy(o
.dbpd_block
);
71 _dispatch_block_private_data_debug("copy from %p, block: %p from %p",
72 &o
, dbpd_block
, o
.dbpd_block
);
73 if (!o
.dbpd_magic
) return; // No group in initial copy of stack object
74 dbpd_group
= _dispatch_group_create_and_enter();
76 inline DISPATCH_ALWAYS_INLINE
~dispatch_block_private_data_s() noexcept
78 _dispatch_block_private_data_debug("destroy%s, block: %p",
79 dbpd_magic
? "" : " (stack)", dbpd_block
);
80 if (dbpd_magic
!= DISPATCH_BLOCK_PRIVATE_DATA_MAGIC
) return;
82 if (!dbpd_performed
) dispatch_group_leave(dbpd_group
);
83 ((void (*)(dispatch_group_t
))dispatch_release
)(dbpd_group
);
85 if (dbpd_block
) Block_release(dbpd_block
);
86 if (dbpd_voucher
) voucher_release(dbpd_voucher
);
91 _dispatch_block_create(dispatch_block_flags_t flags
, voucher_t voucher
,
92 pthread_priority_t pri
, dispatch_block_t block
)
94 struct dispatch_block_private_data_s
dbpds(flags
, voucher
, pri
, block
);
95 return _dispatch_Block_copy(^{
96 // Capture stack object: invokes copy constructor (17094902)
98 _dispatch_block_invoke(&dbpds
);
103 // The compiler hides the name of the function it generates, and changes it if
104 // we try to reference it directly, but the linker still sees it.
105 extern void DISPATCH_BLOCK_SPECIAL_INVOKE(void *)
106 asm("____dispatch_block_create_block_invoke");
107 void (*_dispatch_block_special_invoke
)(void*) = DISPATCH_BLOCK_SPECIAL_INVOKE
;