1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #ifndef TENSORFLOW_CORE_PLATFORM_STATUS_H_
17 #define TENSORFLOW_CORE_PLATFORM_STATUS_H_
18
19 #include <functional>
20 #include <iosfwd>
21 #include <memory>
22 #include <string>
23
24 #include "tensorflow/core/platform/logging.h"
25 #include "tensorflow/core/platform/macros.h"
26 #include "tensorflow/core/platform/stringpiece.h"
27 #include "tensorflow/core/platform/types.h"
28 #include "tensorflow/core/protobuf/error_codes.pb.h"
29
30 namespace tensorflow {
31
32 #if defined(__clang__)
33 // Only clang supports warn_unused_result as a type annotation.
34 class TF_MUST_USE_RESULT Status;
35 #endif
36
37 /// @ingroup core
38 /// Denotes success or failure of a call in Tensorflow.
39 class Status {
40 public:
41 /// Create a success status.
Status()42 Status() {}
43
44 /// \brief Create a status with the specified error code and msg as a
45 /// human-readable string containing more detailed information.
46 Status(tensorflow::error::Code code, tensorflow::StringPiece msg);
47
48 /// Copy the specified status.
49 Status(const Status& s);
50 Status& operator=(const Status& s);
51 #ifndef SWIG
52 Status(Status&& s) noexcept;
53 Status& operator=(Status&& s) noexcept;
54 #endif // SWIG
55
OK()56 static Status OK() { return Status(); }
57
58 /// Returns true iff the status indicates success.
ok()59 bool ok() const { return (state_ == NULL); }
60
code()61 tensorflow::error::Code code() const {
62 return ok() ? tensorflow::error::OK : state_->code;
63 }
64
error_message()65 const string& error_message() const {
66 return ok() ? empty_string() : state_->msg;
67 }
68
69 bool operator==(const Status& x) const;
70 bool operator!=(const Status& x) const;
71
72 /// \brief If `ok()`, stores `new_status` into `*this`. If `!ok()`,
73 /// preserves the current status, but may augment with additional
74 /// information about `new_status`.
75 ///
76 /// Convenient way of keeping track of the first error encountered.
77 /// Instead of:
78 /// `if (overall_status.ok()) overall_status = new_status`
79 /// Use:
80 /// `overall_status.Update(new_status);`
81 void Update(const Status& new_status);
82
83 /// \brief Return a string representation of this status suitable for
84 /// printing. Returns the string `"OK"` for success.
85 string ToString() const;
86
87 // Ignores any errors. This method does nothing except potentially suppress
88 // complaints from any tools that are checking that errors are not dropped on
89 // the floor.
90 void IgnoreError() const;
91
92 private:
93 static const string& empty_string();
94 struct State {
95 tensorflow::error::Code code;
96 string msg;
97 };
98 // OK status has a `NULL` state_. Otherwise, `state_` points to
99 // a `State` structure containing the error code and message(s)
100 std::unique_ptr<State> state_;
101
102 void SlowCopyFrom(const State* src);
103 };
104
105 // Helper class to manage multiple child status values.
106 class StatusGroup {
107 public:
108 // Utility function to mark a Status as derived. By marking derived status,
109 // Derived status messages are ignored when reporting errors to end users.
110 static Status MakeDerived(const Status& s);
111 static bool IsDerived(const Status& s);
112
113 // Enable warning and error log collection for appending to the aggregated
114 // status. This function may be called more than once.
115 static void ConfigureLogHistory();
116
117 // Return a merged status with combined child status messages with a summary.
118 Status as_summary_status() const;
119 // Return a merged status with combined child status messages with
120 // concatenation.
121 Status as_concatenated_status() const;
122
ok()123 bool ok() const { return ok_; }
124
125 // Augment this group with the child status `status`.
126 void Update(const Status& status);
127
128 // Attach recent warning and error log messages
129 void AttachLogMessages();
HasLogMessages()130 bool HasLogMessages() const { return !recent_logs_.empty(); }
131
132 private:
133 bool ok_ = true;
134 size_t num_ok_ = 0;
135 std::vector<Status> children_;
136 std::vector<std::string> recent_logs_; // recent warning and error logs
137 };
138
Status(const Status & s)139 inline Status::Status(const Status& s)
140 : state_((s.state_ == nullptr) ? nullptr : new State(*s.state_)) {}
141
142 inline Status& Status::operator=(const Status& s) {
143 // The following condition catches both aliasing (when this == &s),
144 // and the common case where both s and *this are ok.
145 if (state_ != s.state_) {
146 SlowCopyFrom(s.state_.get());
147 }
148 return *this;
149 }
150
151 #ifndef SWIG
Status(Status && s)152 inline Status::Status(Status&& s) noexcept : state_(std::move(s.state_)) {}
153
154 inline Status& Status::operator=(Status&& s) noexcept {
155 if (state_ != s.state_) {
156 state_ = std::move(s.state_);
157 }
158 return *this;
159 }
160 #endif // SWIG
161
162 inline bool Status::operator==(const Status& x) const {
163 return (this->state_ == x.state_) || (ToString() == x.ToString());
164 }
165
166 inline bool Status::operator!=(const Status& x) const { return !(*this == x); }
167
168 /// @ingroup core
169 std::ostream& operator<<(std::ostream& os, const Status& x);
170
171 typedef std::function<void(const Status&)> StatusCallback;
172
173 extern tensorflow::string* TfCheckOpHelperOutOfLine(
174 const ::tensorflow::Status& v, const char* msg);
175
TfCheckOpHelper(::tensorflow::Status v,const char * msg)176 inline tensorflow::string* TfCheckOpHelper(::tensorflow::Status v,
177 const char* msg) {
178 if (v.ok()) return nullptr;
179 return TfCheckOpHelperOutOfLine(v, msg);
180 }
181
182 #define TF_DO_CHECK_OK(val, level) \
183 while (auto _result = ::tensorflow::TfCheckOpHelper(val, #val)) \
184 LOG(level) << *(_result)
185
186 #define TF_CHECK_OK(val) TF_DO_CHECK_OK(val, FATAL)
187 #define TF_QCHECK_OK(val) TF_DO_CHECK_OK(val, QFATAL)
188
189 // DEBUG only version of TF_CHECK_OK. Compiler still parses 'val' even in opt
190 // mode.
191 #ifndef NDEBUG
192 #define TF_DCHECK_OK(val) TF_CHECK_OK(val)
193 #else
194 #define TF_DCHECK_OK(val) \
195 while (false && (::tensorflow::Status::OK() == (val))) LOG(FATAL)
196 #endif
197
198 } // namespace tensorflow
199
200 #endif // TENSORFLOW_CORE_PLATFORM_STATUS_H_
201