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

10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2011-2013, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the COPYING file in this distribution for license details.
  7. * ----------------------------------------------------------------------
  8. */
  9. #include <assert.h>
  10. #include <errno.h>
  11. #include <stdarg.h>
  12. #include <string.h>
  13. #include "libcork/config.h"
  14. #include "libcork/core/allocator.h"
  15. #include "libcork/core/error.h"
  16. #include "libcork/ds/buffer.h"
  17. #include "libcork/os/process.h"
  18. #include "libcork/threads/basics.h"
  19. /*-----------------------------------------------------------------------
  20. * Life cycle
  21. */
  22. struct cork_error {
  23. cork_error code;
  24. struct cork_buffer *message;
  25. struct cork_buffer *other;
  26. struct cork_buffer buf1;
  27. struct cork_buffer buf2;
  28. struct cork_error *next;
  29. };
  30. static struct cork_error *
  31. cork_error_new(void)
  32. {
  33. struct cork_error *error = cork_new(struct cork_error);
  34. error->code = CORK_ERROR_NONE;
  35. cork_buffer_init(&error->buf1);
  36. cork_buffer_init(&error->buf2);
  37. error->message = &error->buf1;
  38. error->other = &error->buf2;
  39. return error;
  40. }
  41. static void
  42. cork_error_free(struct cork_error *error)
  43. {
  44. cork_buffer_done(&error->buf1);
  45. cork_buffer_done(&error->buf2);
  46. free(error);
  47. }
  48. static struct cork_error * volatile errors;
  49. cork_once_barrier(cork_error_list);
  50. static void
  51. cork_error_list_done(void)
  52. {
  53. struct cork_error *curr;
  54. struct cork_error *next;
  55. for (curr = errors; curr != NULL; curr = next) {
  56. next = curr->next;
  57. cork_error_free(curr);
  58. }
  59. }
  60. static void
  61. cork_error_list_init(void)
  62. {
  63. cork_cleanup_at_exit(0, cork_error_list_done);
  64. }
  65. cork_tls(struct cork_error *, cork_error_);
  66. static struct cork_error *
  67. cork_error_get(void)
  68. {
  69. struct cork_error **error_ptr = cork_error__get();
  70. if (CORK_UNLIKELY(*error_ptr == NULL)) {
  71. struct cork_error *old_head;
  72. struct cork_error *error = cork_error_new();
  73. cork_once(cork_error_list, cork_error_list_init());
  74. do {
  75. old_head = errors;
  76. error->next = old_head;
  77. } while (cork_ptr_cas(&errors, old_head, error) != old_head);
  78. *error_ptr = error;
  79. return error;
  80. } else {
  81. return *error_ptr;
  82. }
  83. }
  84. /*-----------------------------------------------------------------------
  85. * Public error API
  86. */
  87. bool
  88. cork_error_occurred(void)
  89. {
  90. struct cork_error *error = cork_error_get();
  91. return error->code != CORK_ERROR_NONE;
  92. }
  93. cork_error
  94. cork_error_code(void)
  95. {
  96. struct cork_error *error = cork_error_get();
  97. return error->code;
  98. }
  99. const char *
  100. cork_error_message(void)
  101. {
  102. struct cork_error *error = cork_error_get();
  103. return error->message->buf;
  104. }
  105. void
  106. cork_error_clear(void)
  107. {
  108. struct cork_error *error = cork_error_get();
  109. error->code = CORK_ERROR_NONE;
  110. cork_buffer_clear(error->message);
  111. }
  112. void
  113. cork_error_set_printf(cork_error code, const char *format, ...)
  114. {
  115. va_list args;
  116. struct cork_error *error = cork_error_get();
  117. error->code = code;
  118. va_start(args, format);
  119. cork_buffer_vprintf(error->message, format, args);
  120. va_end(args);
  121. }
  122. void
  123. cork_error_set_string(cork_error code, const char *str)
  124. {
  125. struct cork_error *error = cork_error_get();
  126. error->code = code;
  127. cork_buffer_set_string(error->message, str);
  128. }
  129. void
  130. cork_error_set_vprintf(cork_error code, const char *format, va_list args)
  131. {
  132. struct cork_error *error = cork_error_get();
  133. error->code = code;
  134. cork_buffer_vprintf(error->message, format, args);
  135. }
  136. void
  137. cork_error_prefix_printf(const char *format, ...)
  138. {
  139. va_list args;
  140. struct cork_error *error = cork_error_get();
  141. struct cork_buffer *temp;
  142. va_start(args, format);
  143. cork_buffer_vprintf(error->other, format, args);
  144. va_end(args);
  145. cork_buffer_append_copy(error->other, error->message);
  146. temp = error->other;
  147. error->other = error->message;
  148. error->message = temp;
  149. }
  150. void
  151. cork_error_prefix_string(const char *str)
  152. {
  153. struct cork_error *error = cork_error_get();
  154. struct cork_buffer *temp;
  155. cork_buffer_set_string(error->other, str);
  156. cork_buffer_append_copy(error->other, error->message);
  157. temp = error->other;
  158. error->other = error->message;
  159. error->message = temp;
  160. }
  161. void
  162. cork_error_prefix_vprintf(const char *format, va_list args)
  163. {
  164. struct cork_error *error = cork_error_get();
  165. struct cork_buffer *temp;
  166. cork_buffer_vprintf(error->other, format, args);
  167. cork_buffer_append_copy(error->other, error->message);
  168. temp = error->other;
  169. error->other = error->message;
  170. error->message = temp;
  171. }
  172. /*-----------------------------------------------------------------------
  173. * Deprecated
  174. */
  175. void
  176. cork_error_set(uint32_t error_class, unsigned int error_code,
  177. const char *format, ...)
  178. {
  179. /* Create a fallback error code that's most likely not very useful. */
  180. va_list args;
  181. va_start(args, format);
  182. cork_error_set_vprintf(error_class + error_code, format, args);
  183. va_end(args);
  184. }
  185. void
  186. cork_error_prefix(const char *format, ...)
  187. {
  188. va_list args;
  189. va_start(args, format);
  190. cork_error_prefix_vprintf(format, args);
  191. va_end(args);
  192. }
  193. /*-----------------------------------------------------------------------
  194. * Built-in errors
  195. */
  196. void
  197. cork_system_error_set_explicit(int err)
  198. {
  199. cork_error_set_string(err, strerror(err));
  200. }
  201. void
  202. cork_system_error_set(void)
  203. {
  204. cork_error_set_string(errno, strerror(errno));
  205. }
  206. void
  207. cork_unknown_error_set_(const char *location)
  208. {
  209. cork_error_set_printf(CORK_UNKNOWN_ERROR, "Unknown error in %s", location);
  210. }