]> git.saurik.com Git - apple/dyld.git/blob - interlinked-dylibs/Logging.h
dyld-421.2.tar.gz
[apple/dyld.git] / interlinked-dylibs / Logging.h
1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
2 *
3 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #ifndef LOGGING_H
26 #define LOGGING_H
27
28 #include <stdio.h>
29 #include <pthread.h>
30 #include "mega-dylib-utils.h"
31
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);
35
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);
39
40 void setVerbose(bool level);
41 void setReturnNonZeroOnTerminate();
42 void setWarnAnErrorPrefixes(const char* warn, const char* err);
43
44 struct LoggingContext {
45 LoggingContext(const std::string& N);
46 LoggingContext(const std::string& N, WarningTargets T);
47 void taint();
48 bool isTainted();
49 const std::string& name();
50 const WarningTargets& targets();
51
52 private:
53 const std::string _name;
54 const WarningTargets _warnings;
55 bool _tainted;
56 };
57
58 void setLoggingContext(std::shared_ptr<LoggingContext>& context);
59 std::shared_ptr<LoggingContext> getLoggingContext();
60
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
68 * state.
69 *
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.
76 *
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.
79 */
80
81 void runBody(void* Ctx);
82
83 pthread_key_t getLoggingContextKey(void);
84
85 template <typename BodyFtor>
86 std::function<void(void)>* heapSafe(BodyFtor&& Body, std::shared_ptr<LoggingContext> context)
87 {
88 auto retval = new std::function<void(void)>([ B = std::move(Body), context ]() mutable {
89 if (!context || !context->isTainted()) {
90
91 void* oldCtx = pthread_getspecific(getLoggingContextKey());
92 setLoggingContext(context);
93 try {
94 B();
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;
99 }
100 if (context) {
101 context->taint();
102 }
103 } catch (...) {
104 if (context) {
105 context->taint();
106 }
107 }
108 pthread_setspecific(getLoggingContextKey(), oldCtx);
109 }
110 });
111 return retval;
112 }
113
114 template <typename BodyFtor>
115 void cacheBuilderDispatchAsync(dispatch_queue_t queue, BodyFtor&& Body)
116 {
117 dispatch_async_f(queue, heapSafe(Body, getLoggingContext()), runBody);
118 }
119
120 template <typename BodyFtor>
121 void cacheBuilderDispatchGroupAsync(dispatch_group_t group, dispatch_queue_t queue, BodyFtor&& Body)
122 {
123 dispatch_group_async_f(group, queue, heapSafe(Body, getLoggingContext()), runBody);
124 }
125
126 template <typename BodyFtor>
127 void cacheBuilderDispatchSync(dispatch_queue_t queue, BodyFtor&& Body)
128 {
129 dispatch_sync_f(queue, heapSafe(Body, getLoggingContext()), runBody);
130 }
131
132 #endif /* LOGGING_H */