3 * Copyright 2016 gRPC authors.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <grpc/support/port_platform.h>
20 #include "src/core/lib/iomgr/error.h"
25 #include <grpc/status.h>
26 #include <grpc/support/alloc.h>
27 #include <grpc/support/log.h>
28 #include <grpc/support/string_util.h>
31 #include <grpc/support/log_windows.h>
34 #include "src/core/lib/debug/trace.h"
35 #include "src/core/lib/gpr/useful.h"
36 #include "src/core/lib/iomgr/error_internal.h"
37 #include "src/core/lib/profiling/timers.h"
38 #include "src/core/lib/slice/slice_internal.h"
40 grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount(false,
42 grpc_core::DebugOnlyTraceFlag grpc_trace_closure(false, "closure");
44 static const char* error_int_name(grpc_error_ints key) {
46 case GRPC_ERROR_INT_ERRNO:
48 case GRPC_ERROR_INT_FILE_LINE:
50 case GRPC_ERROR_INT_STREAM_ID:
52 case GRPC_ERROR_INT_GRPC_STATUS:
54 case GRPC_ERROR_INT_OFFSET:
56 case GRPC_ERROR_INT_INDEX:
58 case GRPC_ERROR_INT_SIZE:
60 case GRPC_ERROR_INT_HTTP2_ERROR:
62 case GRPC_ERROR_INT_TSI_CODE:
64 case GRPC_ERROR_INT_SECURITY_STATUS:
65 return "security_status";
66 case GRPC_ERROR_INT_FD:
68 case GRPC_ERROR_INT_WSA_ERROR:
70 case GRPC_ERROR_INT_HTTP_STATUS:
72 case GRPC_ERROR_INT_LIMIT:
74 case GRPC_ERROR_INT_OCCURRED_DURING_WRITE:
75 return "occurred_during_write";
76 case GRPC_ERROR_INT_MAX:
77 GPR_UNREACHABLE_CODE(return "unknown");
79 GPR_UNREACHABLE_CODE(return "unknown");
82 static const char* error_str_name(grpc_error_strs key) {
84 case GRPC_ERROR_STR_KEY:
86 case GRPC_ERROR_STR_VALUE:
88 case GRPC_ERROR_STR_DESCRIPTION:
90 case GRPC_ERROR_STR_OS_ERROR:
92 case GRPC_ERROR_STR_TARGET_ADDRESS:
93 return "target_address";
94 case GRPC_ERROR_STR_SYSCALL:
96 case GRPC_ERROR_STR_FILE:
98 case GRPC_ERROR_STR_GRPC_MESSAGE:
99 return "grpc_message";
100 case GRPC_ERROR_STR_RAW_BYTES:
102 case GRPC_ERROR_STR_TSI_ERROR:
104 case GRPC_ERROR_STR_FILENAME:
106 case GRPC_ERROR_STR_QUEUED_BUFFERS:
107 return "queued_buffers";
108 case GRPC_ERROR_STR_MAX:
109 GPR_UNREACHABLE_CODE(return "unknown");
111 GPR_UNREACHABLE_CODE(return "unknown");
114 static const char* error_time_name(grpc_error_times key) {
116 case GRPC_ERROR_TIME_CREATED:
118 case GRPC_ERROR_TIME_MAX:
119 GPR_UNREACHABLE_CODE(return "unknown");
121 GPR_UNREACHABLE_CODE(return "unknown");
125 grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line) {
126 if (grpc_trace_error_refcount.enabled()) {
127 gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
128 gpr_atm_no_barrier_load(&err->atomics.refs.count),
129 gpr_atm_no_barrier_load(&err->atomics.refs.count) + 1, file, line);
131 gpr_ref(&err->atomics.refs);
135 grpc_error* grpc_error_do_ref(grpc_error* err) {
136 gpr_ref(&err->atomics.refs);
141 static void unref_errs(grpc_error* err) {
142 uint8_t slot = err->first_err;
143 while (slot != UINT8_MAX) {
144 grpc_linked_error* lerr =
145 reinterpret_cast<grpc_linked_error*>(err->arena + slot);
146 GRPC_ERROR_UNREF(lerr->err);
147 GPR_ASSERT(err->last_err == slot ? lerr->next == UINT8_MAX
148 : lerr->next != UINT8_MAX);
153 static void unref_strs(grpc_error* err) {
154 for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
155 uint8_t slot = err->strs[which];
156 if (slot != UINT8_MAX) {
157 grpc_slice_unref_internal(
158 *reinterpret_cast<grpc_slice*>(err->arena + slot));
163 static void error_destroy(grpc_error* err) {
164 GPR_ASSERT(!grpc_error_is_special(err));
167 gpr_free((void*)gpr_atm_acq_load(&err->atomics.error_string));
172 void grpc_error_do_unref(grpc_error* err, const char* file, int line) {
173 if (grpc_trace_error_refcount.enabled()) {
174 gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
175 gpr_atm_no_barrier_load(&err->atomics.refs.count),
176 gpr_atm_no_barrier_load(&err->atomics.refs.count) - 1, file, line);
178 if (gpr_unref(&err->atomics.refs)) {
183 void grpc_error_do_unref(grpc_error* err) {
184 if (gpr_unref(&err->atomics.refs)) {
190 static uint8_t get_placement(grpc_error** err, size_t size) {
192 uint8_t slots = static_cast<uint8_t>(size / sizeof(intptr_t));
193 if ((*err)->arena_size + slots > (*err)->arena_capacity) {
194 (*err)->arena_capacity = static_cast<uint8_t> GPR_MIN(
195 UINT8_MAX - 1, (3 * (*err)->arena_capacity / 2));
196 if ((*err)->arena_size + slots > (*err)->arena_capacity) {
200 grpc_error* orig = *err;
202 *err = static_cast<grpc_error*>(gpr_realloc(
203 *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t)));
205 if (grpc_trace_error_refcount.enabled()) {
207 gpr_log(GPR_DEBUG, "realloc %p -> %p", orig, *err);
212 uint8_t placement = (*err)->arena_size;
213 (*err)->arena_size = static_cast<uint8_t>((*err)->arena_size + slots);
217 static void internal_set_int(grpc_error** err, grpc_error_ints which,
219 uint8_t slot = (*err)->ints[which];
220 if (slot == UINT8_MAX) {
221 slot = get_placement(err, sizeof(value));
222 if (slot == UINT8_MAX) {
223 gpr_log(GPR_ERROR, "Error %p is full, dropping int {\"%s\":%" PRIiPTR "}",
224 *err, error_int_name(which), value);
228 (*err)->ints[which] = slot;
229 (*err)->arena[slot] = value;
232 static void internal_set_str(grpc_error** err, grpc_error_strs which,
233 const grpc_slice& value) {
234 uint8_t slot = (*err)->strs[which];
235 if (slot == UINT8_MAX) {
236 slot = get_placement(err, sizeof(value));
237 if (slot == UINT8_MAX) {
238 const char* str = grpc_slice_to_c_string(value);
239 gpr_log(GPR_ERROR, "Error %p is full, dropping string {\"%s\":\"%s\"}",
240 *err, error_str_name(which), str);
241 gpr_free((void*)str);
245 grpc_slice_unref_internal(
246 *reinterpret_cast<grpc_slice*>((*err)->arena + slot));
248 (*err)->strs[which] = slot;
249 memcpy((*err)->arena + slot, &value, sizeof(value));
252 static char* fmt_time(gpr_timespec tm);
253 static void internal_set_time(grpc_error** err, grpc_error_times which,
254 gpr_timespec value) {
255 uint8_t slot = (*err)->times[which];
256 if (slot == UINT8_MAX) {
257 slot = get_placement(err, sizeof(value));
258 if (slot == UINT8_MAX) {
259 const char* time_str = fmt_time(value);
260 gpr_log(GPR_ERROR, "Error %p is full, dropping \"%s\":\"%s\"}", *err,
261 error_time_name(which), time_str);
262 gpr_free((void*)time_str);
266 (*err)->times[which] = slot;
267 memcpy((*err)->arena + slot, &value, sizeof(value));
270 static void internal_add_error(grpc_error** err, grpc_error* new_err) {
271 grpc_linked_error new_last = {new_err, UINT8_MAX};
272 uint8_t slot = get_placement(err, sizeof(grpc_linked_error));
273 if (slot == UINT8_MAX) {
274 gpr_log(GPR_ERROR, "Error %p is full, dropping error %p = %s", *err,
275 new_err, grpc_error_string(new_err));
276 GRPC_ERROR_UNREF(new_err);
279 if ((*err)->first_err == UINT8_MAX) {
280 GPR_ASSERT((*err)->last_err == UINT8_MAX);
281 (*err)->last_err = slot;
282 (*err)->first_err = slot;
284 GPR_ASSERT((*err)->last_err != UINT8_MAX);
285 grpc_linked_error* old_last =
286 reinterpret_cast<grpc_linked_error*>((*err)->arena + (*err)->last_err);
287 old_last->next = slot;
288 (*err)->last_err = slot;
290 memcpy((*err)->arena + slot, &new_last, sizeof(grpc_linked_error));
293 #define SLOTS_PER_INT (sizeof(intptr_t) / sizeof(intptr_t))
294 #define SLOTS_PER_STR (sizeof(grpc_slice) / sizeof(intptr_t))
295 #define SLOTS_PER_TIME (sizeof(gpr_timespec) / sizeof(intptr_t))
296 #define SLOTS_PER_LINKED_ERROR (sizeof(grpc_linked_error) / sizeof(intptr_t))
298 // size of storing one int and two slices and a timespec. For line, desc, file,
300 #define DEFAULT_ERROR_CAPACITY \
301 (SLOTS_PER_INT + (SLOTS_PER_STR * 2) + SLOTS_PER_TIME)
303 // It is very common to include and extra int and string in an error
304 #define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME)
306 static gpr_atm g_error_creation_allowed = true;
308 void grpc_disable_error_creation() {
309 gpr_atm_no_barrier_store(&g_error_creation_allowed, false);
312 void grpc_enable_error_creation() {
313 gpr_atm_no_barrier_store(&g_error_creation_allowed, true);
316 grpc_error* grpc_error_create(const char* file, int line,
317 const grpc_slice& desc, grpc_error** referencing,
318 size_t num_referencing) {
319 GPR_TIMER_SCOPE("grpc_error_create", 0);
320 uint8_t initial_arena_capacity = static_cast<uint8_t>(
321 DEFAULT_ERROR_CAPACITY +
322 static_cast<uint8_t>(num_referencing * SLOTS_PER_LINKED_ERROR) +
324 grpc_error* err = static_cast<grpc_error*>(
325 gpr_malloc(sizeof(*err) + initial_arena_capacity * sizeof(intptr_t)));
326 if (err == nullptr) { // TODO(ctiller): make gpr_malloc return NULL
327 return GRPC_ERROR_OOM;
330 if (!gpr_atm_no_barrier_load(&g_error_creation_allowed)) {
332 "Error creation occurred when error creation was disabled [%s:%d]",
336 if (grpc_trace_error_refcount.enabled()) {
337 gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line);
342 err->arena_capacity = initial_arena_capacity;
343 err->first_err = UINT8_MAX;
344 err->last_err = UINT8_MAX;
346 memset(err->ints, UINT8_MAX, GRPC_ERROR_INT_MAX);
347 memset(err->strs, UINT8_MAX, GRPC_ERROR_STR_MAX);
348 memset(err->times, UINT8_MAX, GRPC_ERROR_TIME_MAX);
350 internal_set_int(&err, GRPC_ERROR_INT_FILE_LINE, line);
351 internal_set_str(&err, GRPC_ERROR_STR_FILE,
352 grpc_slice_from_static_string(file));
353 internal_set_str(&err, GRPC_ERROR_STR_DESCRIPTION, desc);
355 for (size_t i = 0; i < num_referencing; ++i) {
356 if (referencing[i] == GRPC_ERROR_NONE) continue;
360 referencing[i])); // TODO(ncteisen), change ownership semantics
363 internal_set_time(&err, GRPC_ERROR_TIME_CREATED, gpr_now(GPR_CLOCK_REALTIME));
365 gpr_atm_no_barrier_store(&err->atomics.error_string, 0);
366 gpr_ref_init(&err->atomics.refs, 1);
370 static void ref_strs(grpc_error* err) {
371 for (size_t i = 0; i < GRPC_ERROR_STR_MAX; ++i) {
372 uint8_t slot = err->strs[i];
373 if (slot != UINT8_MAX) {
374 grpc_slice_ref_internal(
375 *reinterpret_cast<grpc_slice*>(err->arena + slot));
380 static void ref_errs(grpc_error* err) {
381 uint8_t slot = err->first_err;
382 while (slot != UINT8_MAX) {
383 grpc_linked_error* lerr =
384 reinterpret_cast<grpc_linked_error*>(err->arena + slot);
385 GRPC_ERROR_REF(lerr->err);
390 static grpc_error* copy_error_and_unref(grpc_error* in) {
391 GPR_TIMER_SCOPE("copy_error_and_unref", 0);
393 if (grpc_error_is_special(in)) {
394 out = GRPC_ERROR_CREATE_FROM_STATIC_STRING("unknown");
395 if (in == GRPC_ERROR_NONE) {
396 internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
397 grpc_slice_from_static_string("no error"));
398 internal_set_int(&out, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK);
399 } else if (in == GRPC_ERROR_OOM) {
400 internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
401 grpc_slice_from_static_string("oom"));
402 } else if (in == GRPC_ERROR_CANCELLED) {
403 internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
404 grpc_slice_from_static_string("cancelled"));
405 internal_set_int(&out, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED);
407 } else if (gpr_ref_is_unique(&in->atomics.refs)) {
410 uint8_t new_arena_capacity = in->arena_capacity;
411 // the returned err will be added to, so we ensure this is room to avoid
412 // unneeded allocations.
413 if (in->arena_capacity - in->arena_size <
414 static_cast<uint8_t> SLOTS_PER_STR) {
415 new_arena_capacity = static_cast<uint8_t>(3 * new_arena_capacity / 2);
417 out = static_cast<grpc_error*>(
418 gpr_malloc(sizeof(*in) + new_arena_capacity * sizeof(intptr_t)));
420 if (grpc_trace_error_refcount.enabled()) {
421 gpr_log(GPR_DEBUG, "%p create copying %p", out, in);
424 // bulk memcpy of the rest of the struct.
425 size_t skip = sizeof(&out->atomics);
426 memcpy((void*)((uintptr_t)out + skip), (void*)((uintptr_t)in + skip),
427 sizeof(*in) + (in->arena_size * sizeof(intptr_t)) - skip);
428 // manually set the atomics and the new capacity
429 gpr_atm_no_barrier_store(&out->atomics.error_string, 0);
430 gpr_ref_init(&out->atomics.refs, 1);
431 out->arena_capacity = new_arena_capacity;
434 GRPC_ERROR_UNREF(in);
439 grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which,
441 GPR_TIMER_SCOPE("grpc_error_set_int", 0);
442 grpc_error* new_err = copy_error_and_unref(src);
443 internal_set_int(&new_err, which, value);
448 grpc_status_code code;
450 } special_error_status_map;
451 static const special_error_status_map error_status_map[] = {
452 {GRPC_STATUS_OK, ""}, // GRPC_ERROR_NONE
453 {GRPC_STATUS_INVALID_ARGUMENT, ""}, // GRPC_ERROR_RESERVED_1
454 {GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory"}, // GRPC_ERROR_OOM
455 {GRPC_STATUS_INVALID_ARGUMENT, ""}, // GRPC_ERROR_RESERVED_2
456 {GRPC_STATUS_CANCELLED, "Cancelled"}, // GRPC_ERROR_CANCELLED
459 bool grpc_error_get_int(grpc_error* err, grpc_error_ints which, intptr_t* p) {
460 GPR_TIMER_SCOPE("grpc_error_get_int", 0);
461 if (grpc_error_is_special(err)) {
462 if (which != GRPC_ERROR_INT_GRPC_STATUS) return false;
463 *p = error_status_map[reinterpret_cast<size_t>(err)].code;
466 uint8_t slot = err->ints[which];
467 if (slot != UINT8_MAX) {
468 if (p != nullptr) *p = err->arena[slot];
474 grpc_error* grpc_error_set_str(grpc_error* src, grpc_error_strs which,
475 const grpc_slice& str) {
476 GPR_TIMER_SCOPE("grpc_error_set_str", 0);
477 grpc_error* new_err = copy_error_and_unref(src);
478 internal_set_str(&new_err, which, str);
482 bool grpc_error_get_str(grpc_error* err, grpc_error_strs which,
484 if (grpc_error_is_special(err)) {
485 if (which != GRPC_ERROR_STR_GRPC_MESSAGE) return false;
486 *str = grpc_slice_from_static_string(
487 error_status_map[reinterpret_cast<size_t>(err)].msg);
490 uint8_t slot = err->strs[which];
491 if (slot != UINT8_MAX) {
492 *str = *reinterpret_cast<grpc_slice*>(err->arena + slot);
499 grpc_error* grpc_error_add_child(grpc_error* src, grpc_error* child) {
500 GPR_TIMER_SCOPE("grpc_error_add_child", 0);
501 if (src != GRPC_ERROR_NONE) {
502 if (child == GRPC_ERROR_NONE) {
503 /* \a child is empty. Simply return the ref to \a src */
505 } else if (child != src) {
506 grpc_error* new_err = copy_error_and_unref(src);
507 internal_add_error(&new_err, child);
510 /* \a src and \a child are the same. Drop one of the references and return
512 GRPC_ERROR_UNREF(child);
516 /* \a src is empty. Simply return the ref to \a child */
521 static const char* no_error_string = "\"No Error\"";
522 static const char* oom_error_string = "\"Out of memory\"";
523 static const char* cancelled_error_string = "\"Cancelled\"";
536 static void append_chr(char c, char** s, size_t* sz, size_t* cap) {
538 *cap = GPR_MAX(8, 3 * *cap / 2);
539 *s = static_cast<char*>(gpr_realloc(*s, *cap));
544 static void append_str(const char* str, char** s, size_t* sz, size_t* cap) {
545 for (const char* c = str; *c; c++) {
546 append_chr(*c, s, sz, cap);
550 static void append_esc_str(const uint8_t* str, size_t len, char** s, size_t* sz,
552 static const char* hex = "0123456789abcdef";
553 append_chr('"', s, sz, cap);
554 for (size_t i = 0; i < len; i++, str++) {
555 if (*str < 32 || *str >= 127) {
556 append_chr('\\', s, sz, cap);
559 append_chr('b', s, sz, cap);
562 append_chr('f', s, sz, cap);
565 append_chr('n', s, sz, cap);
568 append_chr('r', s, sz, cap);
571 append_chr('t', s, sz, cap);
574 append_chr('u', s, sz, cap);
575 append_chr('0', s, sz, cap);
576 append_chr('0', s, sz, cap);
577 append_chr(hex[*str >> 4], s, sz, cap);
578 append_chr(hex[*str & 0x0f], s, sz, cap);
582 append_chr(static_cast<char>(*str), s, sz, cap);
585 append_chr('"', s, sz, cap);
588 static void append_kv(kv_pairs* kvs, char* key, char* value) {
589 if (kvs->num_kvs == kvs->cap_kvs) {
590 kvs->cap_kvs = GPR_MAX(3 * kvs->cap_kvs / 2, 4);
591 kvs->kvs = static_cast<kv_pair*>(
592 gpr_realloc(kvs->kvs, sizeof(*kvs->kvs) * kvs->cap_kvs));
594 kvs->kvs[kvs->num_kvs].key = key;
595 kvs->kvs[kvs->num_kvs].value = value;
599 static char* key_int(grpc_error_ints which) {
600 return gpr_strdup(error_int_name(which));
603 static char* fmt_int(intptr_t p) {
605 gpr_asprintf(&s, "%" PRIdPTR, p);
609 static void collect_ints_kvs(grpc_error* err, kv_pairs* kvs) {
610 for (size_t which = 0; which < GRPC_ERROR_INT_MAX; ++which) {
611 uint8_t slot = err->ints[which];
612 if (slot != UINT8_MAX) {
613 append_kv(kvs, key_int(static_cast<grpc_error_ints>(which)),
614 fmt_int(err->arena[slot]));
619 static char* key_str(grpc_error_strs which) {
620 return gpr_strdup(error_str_name(which));
623 static char* fmt_str(const grpc_slice& slice) {
627 append_esc_str((const uint8_t*)GRPC_SLICE_START_PTR(slice),
628 GRPC_SLICE_LENGTH(slice), &s, &sz, &cap);
629 append_chr(0, &s, &sz, &cap);
633 static void collect_strs_kvs(grpc_error* err, kv_pairs* kvs) {
634 for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
635 uint8_t slot = err->strs[which];
636 if (slot != UINT8_MAX) {
637 append_kv(kvs, key_str(static_cast<grpc_error_strs>(which)),
638 fmt_str(*reinterpret_cast<grpc_slice*>(err->arena + slot)));
643 static char* key_time(grpc_error_times which) {
644 return gpr_strdup(error_time_name(which));
647 static char* fmt_time(gpr_timespec tm) {
649 const char* pfx = "!!";
650 switch (tm.clock_type) {
651 case GPR_CLOCK_MONOTONIC:
654 case GPR_CLOCK_REALTIME:
657 case GPR_CLOCK_PRECISE:
664 gpr_asprintf(&out, "\"%s%" PRId64 ".%09d\"", pfx, tm.tv_sec, tm.tv_nsec);
668 static void collect_times_kvs(grpc_error* err, kv_pairs* kvs) {
669 for (size_t which = 0; which < GRPC_ERROR_TIME_MAX; ++which) {
670 uint8_t slot = err->times[which];
671 if (slot != UINT8_MAX) {
672 append_kv(kvs, key_time(static_cast<grpc_error_times>(which)),
673 fmt_time(*reinterpret_cast<gpr_timespec*>(err->arena + slot)));
678 static void add_errs(grpc_error* err, char** s, size_t* sz, size_t* cap) {
679 uint8_t slot = err->first_err;
681 while (slot != UINT8_MAX) {
682 grpc_linked_error* lerr =
683 reinterpret_cast<grpc_linked_error*>(err->arena + slot);
684 if (!first) append_chr(',', s, sz, cap);
686 const char* e = grpc_error_string(lerr->err);
687 append_str(e, s, sz, cap);
688 GPR_ASSERT(err->last_err == slot ? lerr->next == UINT8_MAX
689 : lerr->next != UINT8_MAX);
694 static char* errs_string(grpc_error* err) {
698 append_chr('[', &s, &sz, &cap);
699 add_errs(err, &s, &sz, &cap);
700 append_chr(']', &s, &sz, &cap);
701 append_chr(0, &s, &sz, &cap);
705 static int cmp_kvs(const void* a, const void* b) {
706 const kv_pair* ka = static_cast<const kv_pair*>(a);
707 const kv_pair* kb = static_cast<const kv_pair*>(b);
708 return strcmp(ka->key, kb->key);
711 static char* finish_kvs(kv_pairs* kvs) {
716 append_chr('{', &s, &sz, &cap);
717 for (size_t i = 0; i < kvs->num_kvs; i++) {
718 if (i != 0) append_chr(',', &s, &sz, &cap);
719 append_esc_str(reinterpret_cast<const uint8_t*>(kvs->kvs[i].key),
720 strlen(kvs->kvs[i].key), &s, &sz, &cap);
721 gpr_free(kvs->kvs[i].key);
722 append_chr(':', &s, &sz, &cap);
723 append_str(kvs->kvs[i].value, &s, &sz, &cap);
724 gpr_free(kvs->kvs[i].value);
726 append_chr('}', &s, &sz, &cap);
727 append_chr(0, &s, &sz, &cap);
733 const char* grpc_error_string(grpc_error* err) {
734 GPR_TIMER_SCOPE("grpc_error_string", 0);
735 if (err == GRPC_ERROR_NONE) return no_error_string;
736 if (err == GRPC_ERROR_OOM) return oom_error_string;
737 if (err == GRPC_ERROR_CANCELLED) return cancelled_error_string;
739 void* p = (void*)gpr_atm_acq_load(&err->atomics.error_string);
741 return static_cast<const char*>(p);
745 memset(&kvs, 0, sizeof(kvs));
747 collect_ints_kvs(err, &kvs);
748 collect_strs_kvs(err, &kvs);
749 collect_times_kvs(err, &kvs);
750 if (err->first_err != UINT8_MAX) {
751 append_kv(&kvs, gpr_strdup("referenced_errors"), errs_string(err));
754 qsort(kvs.kvs, kvs.num_kvs, sizeof(kv_pair), cmp_kvs);
756 char* out = finish_kvs(&kvs);
758 if (!gpr_atm_rel_cas(&err->atomics.error_string, 0, (gpr_atm)out)) {
760 out = (char*)gpr_atm_acq_load(&err->atomics.error_string);
766 grpc_error* grpc_os_error(const char* file, int line, int err,
767 const char* call_name) {
768 return grpc_error_set_str(
771 grpc_error_create(file, line,
772 grpc_slice_from_static_string(strerror(err)),
774 GRPC_ERROR_INT_ERRNO, err),
775 GRPC_ERROR_STR_OS_ERROR,
776 grpc_slice_from_static_string(strerror(err))),
777 GRPC_ERROR_STR_SYSCALL, grpc_slice_from_copied_string(call_name));
781 grpc_error* grpc_wsa_error(const char* file, int line, int err,
782 const char* call_name) {
783 char* utf8_message = gpr_format_message(err);
784 grpc_error* error = grpc_error_set_str(
787 grpc_error_create(file, line,
788 grpc_slice_from_static_string("OS Error"), NULL,
790 GRPC_ERROR_INT_WSA_ERROR, err),
791 GRPC_ERROR_STR_OS_ERROR, grpc_slice_from_copied_string(utf8_message)),
792 GRPC_ERROR_STR_SYSCALL, grpc_slice_from_static_string(call_name));
793 gpr_free(utf8_message);
798 bool grpc_log_error(const char* what, grpc_error* error, const char* file,
800 GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
801 const char* msg = grpc_error_string(error);
802 gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what, msg);
803 GRPC_ERROR_UNREF(error);