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@
30 #include "mega-dylib-utils.h"
32 void verboseLog(const char* format
, ...) __printflike(1, 2);
33 void log(const char* __restrict format
, ...) __printflike(1, 2);
34 void alwaysLog(const char* __restrict format
, ...) __printflike(1, 2);
36 void warning(const char* format
, ...) __printflike(1, 2);
37 void terminate(const char* format
, ...) __printflike(1, 2) __attribute__((noreturn
));
38 void dumpLogAndExit(bool logFinishTime
=true);
40 void setVerbose(bool level
);
41 void setReturnNonZeroOnTerminate();
42 void setWarnAnErrorPrefixes(const char* warn
, const char* err
);
44 struct LoggingContext
{
45 LoggingContext(const std::string
& N
);
46 LoggingContext(const std::string
& N
, WarningTargets T
);
49 const std::string
& name();
50 const WarningTargets
& targets();
53 const std::string _name
;
54 const WarningTargets _warnings
;
58 void setLoggingContext(std::shared_ptr
<LoggingContext
>& context
);
59 std::shared_ptr
<LoggingContext
> getLoggingContext();
61 /* Okay, so this gets tricky
62 * Naively, what we are doing is stashing some information in pthread specific
63 * variables so that the logging system can pick it up and tag messages with it,
64 * but without us having to track it all through the entire cache builder code base.
65 * Additionally, we use the presence of that information to determine if we are in
66 * the root logging context (where terminate() calls are fatal), or a thread context
67 * (where they should just throw so the thread fails, logs an error, and cleans up its
70 * The problem is that we need that context to follow our blocks when we switch threads.
71 * We achieve that by wrapping dispatch_(a)sync with our own calls that setup try{} blocks
72 * around the executing lambda, that way it is always safe to throw in a named context
73 * name. We also use those wrappers to copy the context between the threads using
74 * the closures as glue. Finally, we set a taint variable that can back propgate to stop
75 * the execution of any furthur blocks related to a context that has thrown.
77 * This is exposed in the header because we need it for the templates to work, but aside from
78 * cacheBuilderDispatchAsync() and friends nothing here should be used directly.
81 void runBody(void* Ctx
);
83 pthread_key_t
getLoggingContextKey(void);
85 template <typename BodyFtor
>
86 std::function
<void(void)>* heapSafe(BodyFtor
&& Body
, std::shared_ptr
<LoggingContext
> context
)
88 auto retval
= new std::function
<void(void)>([ B
= std::move(Body
), context
]() mutable {
89 if (!context
|| !context
->isTainted()) {
91 void* oldCtx
= pthread_getspecific(getLoggingContextKey());
92 setLoggingContext(context
);
95 } catch (std::string exception
) {
96 WarningTargets warningTargets
= context
->targets();
97 for (auto& target
: warningTargets
.second
) {
98 warningTargets
.first
->configurations
[target
.first
].architectures
[target
.second
].results
.failure
= exception
;
108 pthread_setspecific(getLoggingContextKey(), oldCtx
);
114 template <typename BodyFtor
>
115 void cacheBuilderDispatchAsync(dispatch_queue_t queue
, BodyFtor
&& Body
)
117 dispatch_async_f(queue
, heapSafe(Body
, getLoggingContext()), runBody
);
120 template <typename BodyFtor
>
121 void cacheBuilderDispatchGroupAsync(dispatch_group_t group
, dispatch_queue_t queue
, BodyFtor
&& Body
)
123 dispatch_group_async_f(group
, queue
, heapSafe(Body
, getLoggingContext()), runBody
);
126 template <typename BodyFtor
>
127 void cacheBuilderDispatchSync(dispatch_queue_t queue
, BodyFtor
&& Body
)
129 dispatch_sync_f(queue
, heapSafe(Body
, getLoggingContext()), runBody
);
132 #endif /* LOGGING_H */