You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

246 lines
5.6 KiB

/* -*- coding: utf-8 -*-
* ----------------------------------------------------------------------
* Copyright © 2011-2014, RedJack, LLC.
* All rights reserved.
*
* Please see the COPYING file in this distribution for license details.
* ----------------------------------------------------------------------
*/
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include "libcork/config.h"
#include "libcork/core/allocator.h"
#include "libcork/core/error.h"
#include "libcork/ds/buffer.h"
#include "libcork/os/process.h"
#include "libcork/threads/basics.h"
/*-----------------------------------------------------------------------
* Life cycle
*/
struct cork_error {
cork_error code;
struct cork_buffer *message;
struct cork_buffer *other;
struct cork_buffer buf1;
struct cork_buffer buf2;
struct cork_error *next;
};
static struct cork_error *
cork_error_new(void)
{
struct cork_error *error = cork_new(struct cork_error);
error->code = CORK_ERROR_NONE;
cork_buffer_init(&error->buf1);
cork_buffer_init(&error->buf2);
error->message = &error->buf1;
error->other = &error->buf2;
return error;
}
static void
cork_error_free(struct cork_error *error)
{
cork_buffer_done(&error->buf1);
cork_buffer_done(&error->buf2);
cork_delete(struct cork_error, error);
}
static struct cork_error * volatile errors;
cork_once_barrier(cork_error_list);
static void
cork_error_list_done(void)
{
struct cork_error *curr;
struct cork_error *next;
for (curr = errors; curr != NULL; curr = next) {
next = curr->next;
cork_error_free(curr);
}
}
static void
cork_error_list_init(void)
{
cork_cleanup_at_exit(0, cork_error_list_done);
}
cork_tls(struct cork_error *, cork_error_);
static struct cork_error *
cork_error_get(void)
{
struct cork_error **error_ptr = cork_error__get();
if (CORK_UNLIKELY(*error_ptr == NULL)) {
struct cork_error *old_head;
struct cork_error *error = cork_error_new();
cork_once(cork_error_list, cork_error_list_init());
do {
old_head = errors;
error->next = old_head;
} while (cork_ptr_cas(&errors, old_head, error) != old_head);
*error_ptr = error;
return error;
} else {
return *error_ptr;
}
}
/*-----------------------------------------------------------------------
* Public error API
*/
bool
cork_error_occurred(void)
{
struct cork_error *error = cork_error_get();
return error->code != CORK_ERROR_NONE;
}
cork_error
cork_error_code(void)
{
struct cork_error *error = cork_error_get();
return error->code;
}
const char *
cork_error_message(void)
{
struct cork_error *error = cork_error_get();
return error->message->buf;
}
void
cork_error_clear(void)
{
struct cork_error *error = cork_error_get();
error->code = CORK_ERROR_NONE;
cork_buffer_clear(error->message);
}
void
cork_error_set_printf(cork_error code, const char *format, ...)
{
va_list args;
struct cork_error *error = cork_error_get();
error->code = code;
va_start(args, format);
cork_buffer_vprintf(error->message, format, args);
va_end(args);
}
void
cork_error_set_string(cork_error code, const char *str)
{
struct cork_error *error = cork_error_get();
error->code = code;
cork_buffer_set_string(error->message, str);
}
void
cork_error_set_vprintf(cork_error code, const char *format, va_list args)
{
struct cork_error *error = cork_error_get();
error->code = code;
cork_buffer_vprintf(error->message, format, args);
}
void
cork_error_prefix_printf(const char *format, ...)
{
va_list args;
struct cork_error *error = cork_error_get();
struct cork_buffer *temp;
va_start(args, format);
cork_buffer_vprintf(error->other, format, args);
va_end(args);
cork_buffer_append_copy(error->other, error->message);
temp = error->other;
error->other = error->message;
error->message = temp;
}
void
cork_error_prefix_string(const char *str)
{
struct cork_error *error = cork_error_get();
struct cork_buffer *temp;
cork_buffer_set_string(error->other, str);
cork_buffer_append_copy(error->other, error->message);
temp = error->other;
error->other = error->message;
error->message = temp;
}
void
cork_error_prefix_vprintf(const char *format, va_list args)
{
struct cork_error *error = cork_error_get();
struct cork_buffer *temp;
cork_buffer_vprintf(error->other, format, args);
cork_buffer_append_copy(error->other, error->message);
temp = error->other;
error->other = error->message;
error->message = temp;
}
/*-----------------------------------------------------------------------
* Deprecated
*/
void
cork_error_set(uint32_t error_class, unsigned int error_code,
const char *format, ...)
{
/* Create a fallback error code that's most likely not very useful. */
va_list args;
va_start(args, format);
cork_error_set_vprintf(error_class + error_code, format, args);
va_end(args);
}
void
cork_error_prefix(const char *format, ...)
{
va_list args;
va_start(args, format);
cork_error_prefix_vprintf(format, args);
va_end(args);
}
/*-----------------------------------------------------------------------
* Built-in errors
*/
void
cork_system_error_set_explicit(int err)
{
cork_error_set_string(err, strerror(err));
}
void
cork_system_error_set(void)
{
cork_error_set_string(errno, strerror(errno));
}
void
cork_unknown_error_set_(const char *location)
{
cork_error_set_printf(CORK_UNKNOWN_ERROR, "Unknown error in %s", location);
}