Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
errors.c File Reference
#include "serene/rt/errors.h"
#include <stdio.h>
#include "serene/rt/context.h"
#include "serene/utils.h"
#include "serene/utils/srn_dbg_sym.h"
Include dependency graph for errors.c:

Go to the source code of this file.

Functions

static const char * srn_error_tag_name (srn_error_tag_t tag)
char * srn_error_to_string (const srn_context_t *ctx, const srn_error_t *err)
 Format err as a newly allocated string of the form [TAG]: msg, allocated in ctx.
void srn_error_trace_push (const srn_context_t *ctx, srn_error_t *err, void *addr)
 Append a return address to the trace of a runtime-layer error.
srn_error_t * srn_errors_make (const srn_context_t *ctx, srn_error_tag_t tag, const char *msg, void *caller)
 Build an error in ctx's memory, tagged tag and carrying msg.
srn_error_t * srn_errors_from (const srn_context_t *ctx, const srn_error_t *src, void *caller)
 Build an error in ctx's memory that carries the layer, tag, message and payload of src, with a trace of its own that starts at caller.
void * srn_errors_fail (const srn_context_t *ctx, size_t size, size_t alignment, srn_error_tag_t tag, const char *msg, void *caller)
 Allocate a size/alignment value in ctx, set its ERROR_HEADER (the first member, srn_error_t *maybe_error) to a fresh error, and return it.

Function Documentation

◆ srn_error_tag_name()

const char * srn_error_tag_name ( srn_error_tag_t tag)
static

Definition at line 36 of file errors.c.

36 {
37 switch (tag) {
38 case ABSURD:
39 return "ABSURD";
40 case NOT_IMPLEMENTED:
41 return "NOT_IMPLEMENTED";
43 return "SEQ_LIMIT_REACHED";
45 return "AL_LIMIT_REACHED";
47 return "SM_BUFFER_ID_EXHAUSTED";
49 return "INDEX_OUT_OF_BOUND";
50 case CORRUPTED_SEQ:
51 return "CORRUPTED_SEQ";
53 return "CORRUPTED_ARRAY_LIST";
55 return "FAILED_TO_ADD_MODULE";
57 return "JIT_IR_PARSE_FAILED";
59 return "JIT_SYMBOL_NOT_FOUND";
61 return "JIT_SYMBOL_ALREADY_DEFINED";
63 return "EMPTY_NAMESPACE_NAME";
65 return "EMPTY_SYMBOL_NAME";
67 return "STRING_LENGTH_LIMIT_EXCEEDED";
68 case WRONG_RANGE:
69 return "WRONG_RANGE";
71 return "EPOLL_INIT_FAILED";
73 return "EPOLL_EVENT_FD_FAILED";
75 return "EPOLL_FAILED_TO_ADD_FD";
77 return "CONNECTION_REFUSED";
79 return "CONNECTION_RESET";
81 return "CONNECTION_ABORTED";
82 case BROKEN_PIPE:
83 return "BROKEN_PIPE";
84 case BAD_DESCRIPTOR:
85 return "BAD_DESCRIPTOR";
86 case TIMED_OUT:
87 return "TIMED_OUT";
88 case CANCELED:
89 return "CANCELED";
90 case NOT_CONNECTED:
91 return "NOT_CONNECTED";
92 case ADDRESS_IN_USE:
93 return "ADDRESS_IN_USE";
95 return "HOST_UNREACHABLE";
97 return "NETWORK_UNREACHABLE";
99 return "MESSAGE_TOO_LONG";
101 return "TOO_MANY_OPEN_FILES";
103 return "PERMISSION_DENIED";
104 case OUT_OF_MEMORY:
105 return "OUT_OF_MEMORY";
106 case NOT_FOUND:
107 return "NOT_FOUND";
108 case ALREADY_EXISTS:
109 return "ALREADY_EXISTS";
110 case IS_A_DIRECTORY:
111 return "IS_A_DIRECTORY";
112 case NOT_A_DIRECTORY:
113 return "NOT_A_DIRECTORY";
114 case NO_SPACE:
115 return "NO_SPACE";
116 case INVALID_ARGUMENT:
117 return "INVALID_ARGUMENT";
118 case CHANNEL_BUSY:
119 return "CHANNEL_BUSY";
121 return "MEMORY_MAP_FAILED";
122 case IR_PARSE_ERROR:
123 return "IR_PARSE_ERROR";
124 case UNKNOWN_IO_ERROR:
125 return "UNKNOWN_IO_ERROR";
126 }
127 return "UNKNOWN";
128}
@ AL_LIMIT_REACHED
Definition errors.h:96
@ EPOLL_EVENT_FD_FAILED
Definition errors.h:113
@ NOT_IMPLEMENTED
Definition errors.h:94
@ BROKEN_PIPE
Definition errors.h:121
@ SM_BUFFER_ID_EXHAUSTED
Definition errors.h:97
@ HOST_UNREACHABLE
Definition errors.h:127
@ CORRUPTED_SEQ
Definition errors.h:99
@ CORRUPTED_ARRAY_LIST
Definition errors.h:100
@ EMPTY_NAMESPACE_NAME
Definition errors.h:108
@ JIT_IR_PARSE_FAILED
The JIT could not parse a module's LLVM IR or bitcode.
Definition errors.h:103
@ NETWORK_UNREACHABLE
Definition errors.h:128
@ STRING_LENGTH_LIMIT_EXCEEDED
Definition errors.h:110
@ IS_A_DIRECTORY
Definition errors.h:135
@ INVALID_ARGUMENT
The request itself is malformed (an empty POLL interest mask, for example), so retrying it unchanged ...
Definition errors.h:140
@ CHANNEL_BUSY
The channel already has a full ring's worth of operations in flight.
Definition errors.h:144
@ ABSURD
Definition errors.h:93
@ WRONG_RANGE
Definition errors.h:111
@ JIT_SYMBOL_ALREADY_DEFINED
A JIT symbol definition collided with a name already defined.
Definition errors.h:107
@ PERMISSION_DENIED
Definition errors.h:131
@ CONNECTION_RESET
Definition errors.h:119
@ UNKNOWN_IO_ERROR
Definition errors.h:147
@ TOO_MANY_OPEN_FILES
Definition errors.h:130
@ JIT_SYMBOL_NOT_FOUND
A JIT symbol lookup found no symbol of that name.
Definition errors.h:105
@ NOT_CONNECTED
Definition errors.h:125
@ CONNECTION_REFUSED
Definition errors.h:118
@ FAILED_TO_ADD_MODULE
Definition errors.h:101
@ INDEX_OUT_OF_BOUND
Definition errors.h:98
@ SEQ_LIMIT_REACHED
Definition errors.h:95
@ CONNECTION_ABORTED
Definition errors.h:120
@ ADDRESS_IN_USE
Definition errors.h:126
@ EPOLL_FAILED_TO_ADD_FD
Definition errors.h:114
@ EPOLL_INIT_FAILED
Definition errors.h:112
@ BAD_DESCRIPTOR
Definition errors.h:122
@ OUT_OF_MEMORY
Definition errors.h:132
@ NOT_FOUND
Definition errors.h:133
@ CANCELED
Definition errors.h:124
@ NOT_A_DIRECTORY
Definition errors.h:136
@ TIMED_OUT
Definition errors.h:123
@ IR_PARSE_ERROR
Definition errors.h:146
@ EMPTY_SYMBOL_NAME
Definition errors.h:109
@ MEMORY_MAP_FAILED
Definition errors.h:145
@ MESSAGE_TOO_LONG
Definition errors.h:129
@ ALREADY_EXISTS
Definition errors.h:134
@ NO_SPACE
Definition errors.h:137
Here is the caller graph for this function:

◆ srn_error_to_string()

char * srn_error_to_string ( const srn_context_t * ctx,
const srn_error_t * err )
nodiscard

Format err as a newly allocated string of the form [TAG]: msg, allocated in ctx.

Returns [UNKNOWN]: <null> when err is null.

Definition at line 133 of file errors.c.

133 {
134 PANIC_IF_NULL(err);
135 const char *tag = srn_error_tag_name(err->tag);
136 const char *msg = err->msg != nullptr ? err->msg : "<null>";
137
138 int header_len = snprintf(nullptr, 0, "[%s]: %s", tag, msg);
139 PANIC_IF(header_len < 0, "srn_error_to_string: formatting failed");
140
141 // Measure the trace lines before allocating so a single allocation covers
142 // the whole string.
143 int trace_len = 0;
144 char sym[256];
145 if (err->layer == SRN_ERR_RUNTIME_LAYER && err->as.frames != nullptr) {
146 for (uint16_t i = 0; i < err->as.frames->count; i++) {
147 void *addr = err->as.frames->return_addrs[i];
148 const char *name = srn_dbg_sym_name(addr, sym, sizeof(sym));
149 if (name != nullptr) {
150 trace_len += snprintf(nullptr, 0, "\n #%u %p %s", i, addr, name);
151 } else {
152 trace_len += snprintf(nullptr, 0, "\n #%u %p", i, addr);
153 }
154 }
155 }
156
157 size_t total = (size_t)header_len + (size_t)trace_len + 1;
158 char *buf = srn_allocate(ctx, total, alignof(char));
159 PANIC_IF_NULL(buf);
160
161 int written = snprintf(buf, total, "[%s]: %s", tag, msg);
162 if (err->layer == SRN_ERR_RUNTIME_LAYER && err->as.frames != nullptr) {
163 for (uint16_t i = 0; i < err->as.frames->count; i++) {
164 void *addr = err->as.frames->return_addrs[i];
165 const char *name = srn_dbg_sym_name(addr, sym, sizeof(sym));
166 if (name != nullptr) {
167 written += snprintf(buf + written, total - (size_t)written, "\n #%u %p %s", i, addr, name);
168 } else {
169 written += snprintf(buf + written, total - (size_t)written, "\n #%u %p", i, addr);
170 }
171 }
172 }
173
174 return buf;
175}
static atomic_int total
Definition 05_parallel.c:40
void * srn_allocate(const srn_context_t *ctx, size_t size, size_t alignment)
Allocate size bytes aligned to alignment from the context's memory block.
Definition context.c:73
static const char * srn_error_tag_name(srn_error_tag_t tag)
Definition errors.c:36
@ SRN_ERR_RUNTIME_LAYER
Definition errors.h:151
const char * srn_dbg_sym_name(void *addr, char *buf, size_t buflen)
Resolve addr to a symbol name and write it into buf (null-terminated, at most buflen bytes including ...
Definition srn_dbg_sym.c:26
union srn_error_t::@110141362101221075206211275212023153042233307220 as
srn_error_layer_t layer
Definition errors.h:174
char * msg
Definition errors.h:176
srn_error_tag_t tag
Definition errors.h:175
srn_trace_frames_t * frames
Definition errors.h:181
uint16_t count
Definition errors.h:166
void * return_addrs[TRACE_FRAME_DEPTH]
Definition errors.h:165
#define PANIC_IF_NULL(ptr)
Definition utils.h:66
#define PANIC_IF(cond, msg)
Definition utils.h:59
Here is the call graph for this function:
Here is the caller graph for this function:

◆ srn_error_trace_push()

void srn_error_trace_push ( const srn_context_t * ctx,
srn_error_t * err,
void * addr )

Append a return address to the trace of a runtime-layer error.

Allocates frames from ctx on the first call. Silently does nothing when the trace is full or the error is not a runtime-layer error.

Definition at line 177 of file errors.c.

177 {
178 if (err->layer != SRN_ERR_RUNTIME_LAYER) {
179 return;
180 }
181
182 if (err->as.frames == nullptr) {
183 err->as.frames = ALLOC(ctx, srn_trace_frames_t);
184 PANIC_IF_NULL(err->as.frames);
185 err->as.frames->count = 0;
186 }
187
188 if (err->as.frames->count >= TRACE_FRAME_DEPTH) {
189 return;
190 }
191
192 err->as.frames->return_addrs[err->as.frames->count++] = addr;
193}
#define ALLOC(ctx, T)
Definition context.h:95
#define TRACE_FRAME_DEPTH
Definition errors.h:63
This is how we create a traceback for the C level code in the runtime lib.
Definition errors.h:164
Here is the caller graph for this function:

◆ srn_errors_fail()

void * srn_errors_fail ( const srn_context_t * ctx,
size_t size,
size_t alignment,
srn_error_tag_t tag,
const char * msg,
void * caller )
nodiscard

Allocate a size/alignment value in ctx, set its ERROR_HEADER (the first member, srn_error_t *maybe_error) to a fresh error, and return it.

The result is a valid fallible value whose HAS_ERROR is true. Use the FAIL macro, which fills in size/alignment from the target type.

Definition at line 224 of file errors.c.

227 {
228 // The ERROR_HEADER convention guarantees `srn_error_t *maybe_error` is the
229 // first member of any fallible T, so offset 0 of the value is that pointer.
230 // Allocate the value and set it to a fresh error; the caller checks it with
231 // HAS_ERROR and never reads the other fields of an errored value.
232 void *value = srn_allocate(ctx, size, alignment);
233 PANIC_IF_NULL(value);
234 *(srn_error_t **)value = srn_errors_make(ctx, tag, msg, caller);
235 return value;
236}
srn_error_t * srn_errors_make(const srn_context_t *ctx, srn_error_tag_t tag, const char *msg, void *caller)
Build an error in ctx's memory, tagged tag and carrying msg.
Definition errors.c:196
A runtime error, a tag classifying the failure and a human-readable message.
Definition errors.h:173
Here is the call graph for this function:

◆ srn_errors_from()

srn_error_t * srn_errors_from ( const srn_context_t * ctx,
const srn_error_t * src,
void * caller )

Build an error in ctx's memory that carries the layer, tag, message and payload of src, with a trace of its own that starts at caller.

src is not written to, so this is the way to take a trace on an error that is shared or immutable, such as the reactor's static IO errors. A runtime layer src with frames has them copied, so the earlier trace is kept. The ERR_FROM macro supplies caller.

Definition at line 207 of file errors.c.

207 {
208 PANIC_IF_NULL(src);
210 err->layer = src->layer;
211 err->tag = src->tag;
212 err->msg = src->msg;
213 err->as = src->as;
214
215 if (src->layer == SRN_ERR_RUNTIME_LAYER && src->as.frames != nullptr) {
217 *err->as.frames = *src->as.frames;
218 }
219
220 srn_error_trace_push(ctx, err, caller);
221 return err;
222}
#define ALLOC_OR_PANIC(ctx, T)
Definition context.h:98
void srn_error_trace_push(const srn_context_t *ctx, srn_error_t *err, void *addr)
Append a return address to the trace of a runtime-layer error.
Definition errors.c:177
Here is the call graph for this function:

◆ srn_errors_make()

srn_error_t * srn_errors_make ( const srn_context_t * ctx,
srn_error_tag_t tag,
const char * msg,
void * caller )

Build an error in ctx's memory, tagged tag and carrying msg.

caller is the return address of the call site (pass __builtin_return_address(0)) and is recorded as the first frame of the trace. The ERR macro supplies it automatically.

Definition at line 196 of file errors.c.

196 {
197 srn_error_t *err = ALLOC(ctx, srn_error_t);
198 PANIC_IF_NULL(err);
200 err->tag = tag;
201 err->msg = (char *)msg;
202 err->as.frames = nullptr;
203 srn_error_trace_push(ctx, err, caller);
204 return err;
205}
Here is the call graph for this function:
Here is the caller graph for this function: