aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/iomgr/error.h
blob: cb740d5b01cf080dffb6a4ed67d0b46171495e01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
/*
 *
 * Copyright 2016 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#ifndef GRPC_CORE_LIB_IOMGR_ERROR_H
#define GRPC_CORE_LIB_IOMGR_ERROR_H

#include <grpc/support/port_platform.h>

#include <inttypes.h>
#include <stdbool.h>

#include <grpc/slice.h>
#include <grpc/status.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>

#include "src/core/lib/debug/trace.h"

/// Opaque representation of an error.
/// See https://github.com/grpc/grpc/blob/master/doc/core/grpc-error.md for a
/// full write up of this object.

typedef struct grpc_error grpc_error;

extern grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount;

typedef enum {
  /// 'errno' from the operating system
  GRPC_ERROR_INT_ERRNO,
  /// __LINE__ from the call site creating the error
  GRPC_ERROR_INT_FILE_LINE,
  /// stream identifier: for errors that are associated with an individual
  /// wire stream
  GRPC_ERROR_INT_STREAM_ID,
  /// grpc status code representing this error
  GRPC_ERROR_INT_GRPC_STATUS,
  /// offset into some binary blob (usually represented by
  /// GRPC_ERROR_STR_RAW_BYTES) where the error occurred
  GRPC_ERROR_INT_OFFSET,
  /// context sensitive index associated with the error
  GRPC_ERROR_INT_INDEX,
  /// context sensitive size associated with the error
  GRPC_ERROR_INT_SIZE,
  /// http2 error code associated with the error (see the HTTP2 RFC)
  GRPC_ERROR_INT_HTTP2_ERROR,
  /// TSI status code associated with the error
  GRPC_ERROR_INT_TSI_CODE,
  /// grpc_security_status associated with the error
  GRPC_ERROR_INT_SECURITY_STATUS,
  /// WSAGetLastError() reported when this error occurred
  GRPC_ERROR_INT_WSA_ERROR,
  /// File descriptor associated with this error
  GRPC_ERROR_INT_FD,
  /// HTTP status (i.e. 404)
  GRPC_ERROR_INT_HTTP_STATUS,
  /// context sensitive limit associated with the error
  GRPC_ERROR_INT_LIMIT,
  /// chttp2: did the error occur while a write was in progress
  GRPC_ERROR_INT_OCCURRED_DURING_WRITE,

  /// Must always be last
  GRPC_ERROR_INT_MAX,
} grpc_error_ints;

typedef enum {
  /// top-level textual description of this error
  GRPC_ERROR_STR_DESCRIPTION,
  /// source file in which this error occurred
  GRPC_ERROR_STR_FILE,
  /// operating system description of this error
  GRPC_ERROR_STR_OS_ERROR,
  /// syscall that generated this error
  GRPC_ERROR_STR_SYSCALL,
  /// peer that we were trying to communicate when this error occurred
  GRPC_ERROR_STR_TARGET_ADDRESS,
  /// grpc status message associated with this error
  GRPC_ERROR_STR_GRPC_MESSAGE,
  /// hex dump (or similar) with the data that generated this error
  GRPC_ERROR_STR_RAW_BYTES,
  /// tsi error string associated with this error
  GRPC_ERROR_STR_TSI_ERROR,
  /// filename that we were trying to read/write when this error occurred
  GRPC_ERROR_STR_FILENAME,
  /// which data was queued for writing when the error occurred
  GRPC_ERROR_STR_QUEUED_BUFFERS,
  /// key associated with the error
  GRPC_ERROR_STR_KEY,
  /// value associated with the error
  GRPC_ERROR_STR_VALUE,

  /// Must always be last
  GRPC_ERROR_STR_MAX,
} grpc_error_strs;

typedef enum {
  /// timestamp of error creation
  GRPC_ERROR_TIME_CREATED,

  /// Must always be last
  GRPC_ERROR_TIME_MAX,
} grpc_error_times;

/// The following "special" errors can be propagated without allocating memory.
/// They are always even so that other code (particularly combiner locks,
/// polling engines) can safely use the lower bit for themselves.

#define GRPC_ERROR_NONE ((grpc_error*)NULL)
#define GRPC_ERROR_RESERVED_1 ((grpc_error*)1)
#define GRPC_ERROR_OOM ((grpc_error*)2)
#define GRPC_ERROR_RESERVED_2 ((grpc_error*)3)
#define GRPC_ERROR_CANCELLED ((grpc_error*)4)
#define GRPC_ERROR_SPECIAL_MAX GRPC_ERROR_CANCELLED

inline bool grpc_error_is_special(struct grpc_error* err) {
  return err <= GRPC_ERROR_SPECIAL_MAX;
}

// debug only toggles that allow for a sanity to check that ensures we will
// never create any errors in the per-RPC hotpath.
void grpc_disable_error_creation();
void grpc_enable_error_creation();

const char* grpc_error_string(grpc_error* error);

/// Create an error - but use GRPC_ERROR_CREATE instead
grpc_error* grpc_error_create(const char* file, int line, grpc_slice desc,
                              grpc_error** referencing, size_t num_referencing);
/// Create an error (this is the preferred way of generating an error that is
///   not due to a system call - for system calls, use GRPC_OS_ERROR or
///   GRPC_WSA_ERROR as appropriate)
/// \a referencing is an array of num_referencing elements indicating one or
/// more errors that are believed to have contributed to this one
/// err = grpc_error_create(x, y, z, r, nr) is equivalent to:
///   err = grpc_error_create(x, y, z, NULL, 0);
///   for (i=0; i<nr; i++) err = grpc_error_add_child(err, r[i]);
#define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc)                           \
  grpc_error_create(__FILE__, __LINE__, grpc_slice_from_static_string(desc), \
                    NULL, 0)
#define GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc)                           \
  grpc_error_create(__FILE__, __LINE__, grpc_slice_from_copied_string(desc), \
                    NULL, 0)

// Create an error that references some other errors. This function adds a
// reference to each error in errs - it does not consume an existing reference
#define GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(desc, errs, count)  \
  grpc_error_create(__FILE__, __LINE__, grpc_slice_from_static_string(desc), \
                    errs, count)
#define GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(desc, errs, count)  \
  grpc_error_create(__FILE__, __LINE__, grpc_slice_from_copied_string(desc), \
                    errs, count)

#ifndef NDEBUG
grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line);
void grpc_error_do_unref(grpc_error* err, const char* file, int line);
inline grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line) {
  if (grpc_error_is_special(err)) return err;
  return grpc_error_do_ref(err, file, line);
}
inline void grpc_error_unref(grpc_error* err, const char* file, int line) {
  if (grpc_error_is_special(err)) return;
  grpc_error_do_unref(err, file, line);
}
#define GRPC_ERROR_REF(err) grpc_error_ref(err, __FILE__, __LINE__)
#define GRPC_ERROR_UNREF(err) grpc_error_unref(err, __FILE__, __LINE__)
#else
grpc_error* grpc_error_do_ref(grpc_error* err);
void grpc_error_do_unref(grpc_error* err);
inline grpc_error* grpc_error_ref(grpc_error* err) {
  if (grpc_error_is_special(err)) return err;
  return grpc_error_do_ref(err);
}
inline void grpc_error_unref(grpc_error* err) {
  if (grpc_error_is_special(err)) return;
  grpc_error_do_unref(err);
}
#define GRPC_ERROR_REF(err) grpc_error_ref(err)
#define GRPC_ERROR_UNREF(err) grpc_error_unref(err)
#endif

grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which,
                               intptr_t value) GRPC_MUST_USE_RESULT;
/// It is an error to pass nullptr as `p`. Caller should allocate a dummy
/// intptr_t for `p`, even if the value of `p` is not used.
bool grpc_error_get_int(grpc_error* error, grpc_error_ints which, intptr_t* p);
/// This call takes ownership of the slice; the error is responsible for
/// eventually unref-ing it.
grpc_error* grpc_error_set_str(grpc_error* src, grpc_error_strs which,
                               grpc_slice str) GRPC_MUST_USE_RESULT;
/// Returns false if the specified string is not set.
/// Caller does NOT own the slice.
bool grpc_error_get_str(grpc_error* error, grpc_error_strs which,
                        grpc_slice* s);

/// Add a child error: an error that is believed to have contributed to this
/// error occurring. Allows root causing high level errors from lower level
/// errors that contributed to them. The src error takes ownership of the
/// child error.
///
/// Edge Conditions -
/// 1) If either of \a src or \a child is GRPC_ERROR_NONE, returns a reference
/// to the other argument. 2) If both \a src and \a child are GRPC_ERROR_NONE,
/// returns GRPC_ERROR_NONE. 3) If \a src and \a child point to the same error,
/// returns a single reference. (Note that, 2 references should have been
/// received to the error in this case.)
grpc_error* grpc_error_add_child(grpc_error* src,
                                 grpc_error* child) GRPC_MUST_USE_RESULT;

grpc_error* grpc_os_error(const char* file, int line, int err,
                          const char* call_name) GRPC_MUST_USE_RESULT;

inline grpc_error* grpc_assert_never_ok(grpc_error* error) {
  GPR_ASSERT(error != GRPC_ERROR_NONE);
  return error;
}

/// create an error associated with errno!=0 (an 'operating system' error)
#define GRPC_OS_ERROR(err, call_name) \
  grpc_assert_never_ok(grpc_os_error(__FILE__, __LINE__, err, call_name))
grpc_error* grpc_wsa_error(const char* file, int line, int err,
                           const char* call_name) GRPC_MUST_USE_RESULT;
/// windows only: create an error associated with WSAGetLastError()!=0
#define GRPC_WSA_ERROR(err, call_name) \
  grpc_wsa_error(__FILE__, __LINE__, err, call_name)

bool grpc_log_if_error(const char* what, grpc_error* error, const char* file,
                       int line);
#define GRPC_LOG_IF_ERROR(what, error) \
  grpc_log_if_error((what), (error), __FILE__, __LINE__)

#endif /* GRPC_CORE_LIB_IOMGR_ERROR_H */