1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
3 * Copyright (c) 2016 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <dispatch/dispatch.h>
31 #include "mega-dylib-utils.h"
35 #define MAX_LOG_STR_LEN (512)
36 //const char* kDispatchQueueLogNameKey = "kDispatchQueueLogNameKey";
37 const char* kDispatchWarningArrayKey
= "kDispatchWarningArrayKey";
39 static dispatch_queue_t log_queue
;
40 static dispatch_once_t logQueueInit
= 0;
41 static dispatch_queue_t unique_queue
;
42 static dispatch_once_t uniqueQueueInit
= 0;
44 static uint32_t verbose
= 0;
45 static bool returnNonZeroIfTerminateCalled
= false;
46 static bool terminateCalled
= false;
48 static const char* warningPrefix
= "WARNING: ";
49 static const char* errorPrefix
= "ERROR: ";
51 LoggingContext::LoggingContext(const std::string
& N
)
57 LoggingContext::LoggingContext(const std::string
& N
, WarningTargets T
)
64 void LoggingContext::taint()
69 bool LoggingContext::isTainted()
74 const std::string
& LoggingContext::name()
79 const WarningTargets
& LoggingContext::targets()
86 pthread_key_t
getLoggingContextKey(void) {
87 static pthread_key_t logContextKey
;
88 static dispatch_once_t logContextToken
;
89 dispatch_once(&logContextToken
, ^{
90 pthread_key_create(&logContextKey
, nullptr);
96 void setLoggingContext(std::shared_ptr
<LoggingContext
>& context
)
98 pthread_setspecific(getLoggingContextKey(), (void*)&context
);
100 if (context
&& !context
->name().empty()) {
101 pthread_setname_np(context
->name().substr(0, MAXTHREADNAMESIZE
-1).c_str());
105 std::shared_ptr
<LoggingContext
> getLoggingContext()
107 if (void* val
= pthread_getspecific(getLoggingContextKey()))
108 return *((std::shared_ptr
<LoggingContext
>*)val
);
112 void runBody(void* Ctx
)
114 std::unique_ptr
<std::function
<void(void)>>
115 Body(reinterpret_cast<std::function
<void(void)>*>(Ctx
));
119 static dispatch_queue_t
getLogQueue()
121 dispatch_once(&logQueueInit
, ^{
122 log_queue
= dispatch_queue_create("com.apple.dyld.cache.logging", DISPATCH_QUEUE_SERIAL
);
127 void setVerbose(bool level
)
132 void setWarnAnErrorPrefixes(const char* warn
, const char* err
)
134 warningPrefix
= warn
;
138 void setReturnNonZeroOnTerminate()
140 returnNonZeroIfTerminateCalled
= true;
143 void queued_print(FILE* __restrict fd
, const char* str
)
145 const char* qstr
= strdup(str
);
147 dispatch_async(getLogQueue(), ^{
148 (void)fprintf(fd
, "%s", qstr
);
153 #define VLOG(header) \
155 va_start(list, format); \
156 char temp[MAX_LOG_STR_LEN]; \
157 vsprintf(temp, format, list); \
158 auto ctx = getLoggingContext(); \
159 char temp2[MAX_LOG_STR_LEN]; \
160 if (ctx && !ctx->name().empty()) { \
161 snprintf(temp2, MAX_LOG_STR_LEN, "[%s] %s%s\n", ctx->name().c_str(), header, \
164 snprintf(temp2, MAX_LOG_STR_LEN, "%s%s\n", header, temp); \
166 queued_print(stderr, temp2); \
169 void log(const char* __restrict format
, ...)
174 void verboseLog(const char* format
, ...)
181 static std::set
<std::string
> warnings
;
183 void warning(const char* format
, ...)
185 dispatch_once(&uniqueQueueInit
, ^{
186 unique_queue
= dispatch_queue_create("com.apple.dyld.cache.logging", DISPATCH_QUEUE_SERIAL
);
190 va_start(list
, format
);
191 char temp
[MAX_LOG_STR_LEN
];
192 vsprintf(temp
, format
, list
);
193 char* blockTemp
= strdup(temp
);
195 auto ctx
= getLoggingContext();
197 for (auto& target
: ctx
->targets().second
) {
198 ctx
->targets().first
->configurations
[target
.first
].architectures
[target
.second
].results
.warnings
.push_back(blockTemp
);
202 dispatch_sync(unique_queue
, ^{
203 if (warnings
.count(blockTemp
) == 0) {
204 warnings
.insert(blockTemp
);
213 void terminate(const char* format
, ...)
217 terminateCalled
= true;
220 // We are a work in a logging context, throw
221 throw std::string(temp
);
223 // We are in general handing, let the loggging queue darain and exit
224 dispatch_sync(getLogQueue(), ^{
225 for (auto& warning
: warnings
) {
226 (void)fprintf(stderr
, "%s%s\n", warningPrefix
, warning
.c_str());
228 if ( returnNonZeroIfTerminateCalled
) {
232 time_t endtime
= time(0);
233 (void)fprintf(stderr
, "Finished: %s\n", asctime(localtime(&endtime
)));
234 (void)fprintf(stderr
, "Exiting\n");
240 // clang can't reason out that we won't hit this due to the dispatch_sync in the exit path
241 __builtin_unreachable();
244 void dumpLogAndExit(bool logFinishTime
)
246 dispatch_async(getLogQueue(), ^{
247 for (auto& warning
: warnings
) {
248 (void)fprintf(stderr
, "%s%s\n", warningPrefix
, warning
.c_str());
250 if ( logFinishTime
) {
251 time_t endtime
= time(0);
252 (void)fprintf(stderr
, "Finished: %s\n", asctime(localtime(&endtime
)));
253 (void)fprintf(stderr
, "Exiting\n");
255 exit(returnNonZeroIfTerminateCalled
&& terminateCalled
? 1 : 0);