blob: cb740d5b01cf080dffb6a4ed67d0b46171495e01 [file] [log] [blame]
/*
*
* 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 */