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 //const char* kDispatchQueueLogNameKey = "kDispatchQueueLogNameKey";
36 const char* kDispatchWarningArrayKey
= "kDispatchWarningArrayKey";
38 static dispatch_queue_t log_queue
;
39 static dispatch_once_t logQueueInit
= 0;
40 static dispatch_queue_t unique_queue
;
41 static dispatch_once_t uniqueQueueInit
= 0;
43 static uint32_t verbose
= 0;
44 static bool returnNonZeroIfTerminateCalled
= false;
45 static bool terminateCalled
= false;
47 static const char* warningPrefix
= "WARNING: ";
48 static const char* errorPrefix
= "ERROR: ";
50 LoggingContext::LoggingContext(const std::string
& N
)
56 LoggingContext::LoggingContext(const std::string
& N
, WarningTargets T
)
63 void LoggingContext::taint()
68 bool LoggingContext::isTainted()
73 const std::string
& LoggingContext::name()
78 const WarningTargets
& LoggingContext::targets()
85 pthread_key_t
getLoggingContextKey(void) {
86 static pthread_key_t logContextKey
;
87 static dispatch_once_t logContextToken
;
88 dispatch_once(&logContextToken
, ^{
89 pthread_key_create(&logContextKey
, nullptr);
95 void setLoggingContext(std::shared_ptr
<LoggingContext
>& context
)
97 pthread_setspecific(getLoggingContextKey(), (void*)&context
);
99 if (context
&& !context
->name().empty()) {
100 pthread_setname_np(context
->name().substr(0, MAXTHREADNAMESIZE
-1).c_str());
104 std::shared_ptr
<LoggingContext
> getLoggingContext()
106 if (void* val
= pthread_getspecific(getLoggingContextKey()))
107 return *((std::shared_ptr
<LoggingContext
>*)val
);
111 void runBody(void* Ctx
)
113 std::unique_ptr
<std::function
<void(void)>>
114 Body(reinterpret_cast<std::function
<void(void)>*>(Ctx
));
118 static dispatch_queue_t
getLogQueue()
120 dispatch_once(&logQueueInit
, ^{
121 log_queue
= dispatch_queue_create("com.apple.dyld.cache.logging", DISPATCH_QUEUE_SERIAL
);
126 void setVerbose(bool level
)
131 void setWarnAnErrorPrefixes(const char* warn
, const char* err
)
133 warningPrefix
= warn
;
137 void setReturnNonZeroOnTerminate()
139 returnNonZeroIfTerminateCalled
= true;
142 void queued_print(FILE* __restrict fd
, const char* str
)
144 dispatch_async(getLogQueue(), ^{
145 (void)fprintf(fd
, "%s", str
);
150 #define VLOG(header) \
152 va_start(list, format); \
153 char *temp, *temp2; \
154 vasprintf(&temp, format, list); \
155 auto ctx = getLoggingContext(); \
156 if (ctx && !ctx->name().empty()) { \
157 asprintf(&temp2, "[%s] %s%s\n", ctx->name().c_str(), header, temp); \
159 asprintf(&temp2, "%s%s\n", header, temp); \
162 queued_print(stderr, temp2); \
165 void log(const char* __restrict format
, ...)
170 void verboseLog(const char* format
, ...)
177 static std::set
<std::string
> warnings
;
179 void warning(const char* format
, ...)
181 dispatch_once(&uniqueQueueInit
, ^{
182 unique_queue
= dispatch_queue_create("com.apple.dyld.cache.logging", DISPATCH_QUEUE_SERIAL
);
186 va_start(list
, format
);
188 vasprintf(&blockTemp
, format
, list
);
190 auto ctx
= getLoggingContext();
192 for (auto& target
: ctx
->targets().second
) {
193 ctx
->targets().first
->configuration(target
.first
).architecture(target
.second
).results
.warnings
.push_back(blockTemp
);
197 dispatch_sync(unique_queue
, ^{
198 if (warnings
.count(blockTemp
) == 0) {
199 warnings
.insert(blockTemp
);
208 void terminate(const char* format
, ...)
212 terminateCalled
= true;
215 // We are a work in a logging context, throw
216 throw std::string(temp2
);
218 // We are in general handing, let the loggging queue darain and exit
219 dispatch_sync(getLogQueue(), ^{
220 for (auto& warning
: warnings
) {
221 (void)fprintf(stderr
, "%s%s\n", warningPrefix
, warning
.c_str());
223 if ( returnNonZeroIfTerminateCalled
) {
227 time_t endtime
= time(0);
228 (void)fprintf(stderr
, "Finished: %s\n", asctime(localtime(&endtime
)));
229 (void)fprintf(stderr
, "Exiting\n");
235 // clang can't reason out that we won't hit this due to the dispatch_sync in the exit path
236 __builtin_unreachable();
239 void dumpLogAndExit(bool logFinishTime
)
241 dispatch_async(getLogQueue(), ^{
242 for (auto& warning
: warnings
) {
243 (void)fprintf(stderr
, "%s%s\n", warningPrefix
, warning
.c_str());
245 if ( logFinishTime
) {
246 time_t endtime
= time(0);
247 (void)fprintf(stderr
, "Finished: %s\n", asctime(localtime(&endtime
)));
248 (void)fprintf(stderr
, "Exiting\n");
250 exit(returnNonZeroIfTerminateCalled
&& terminateCalled
? 1 : 0);