From 46f398569f1b54e66588056e6d4d33e6ea1c7e01 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 15 Feb 2018 11:36:23 -0500 Subject: [PATCH] error: Revamp interface documentation Backports commit edf6f3b3358597d37da0cf636ce3ed8a546d0f26 from qemu --- qemu/include/qapi/error.h | 153 +++++++++++++++++++++++++++++--------- 1 file changed, 118 insertions(+), 35 deletions(-) diff --git a/qemu/include/qapi/error.h b/qemu/include/qapi/error.h index 431c2826..1da01a85 100644 --- a/qemu/include/qapi/error.h +++ b/qemu/include/qapi/error.h @@ -2,13 +2,75 @@ * QEMU Error Objects * * Copyright IBM, Corp. 2011 + * Copyright (C) 2011-2015 Red Hat, Inc. * * Authors: * Anthony Liguori + * Markus Armbruster * * This work is licensed under the terms of the GNU LGPL, version 2. See * the COPYING.LIB file in the top-level directory. */ + +/* + * Error reporting system loosely patterned after Glib's GError. + * + * Create an error: + * error_setg(&err, "situation normal, all fouled up"); + * + * Report an error to stderr: + * error_report_err(err); + * This frees the error object. + * + * Report an error somewhere else: + * const char *msg = error_get_pretty(err); + * do with msg what needs to be done... + * error_free(err); + * + * Handle an error without reporting it (just for completeness): + * error_free(err); + * + * Pass an existing error to the caller: + * error_propagate(errp, err); + * where Error **errp is a parameter, by convention the last one. + * + * Create a new error and pass it to the caller: + * error_setg(errp, "situation normal, all fouled up"); + * + * Call a function and receive an error from it: + * Error *err = NULL; + * foo(arg, &err); + * if (err) { + * handle the error... + * } + * + * Call a function ignoring errors: + * foo(arg, NULL); + * + * Call a function aborting on errors: + * foo(arg, &error_abort); + * + * Receive an error and pass it on to the caller: + * Error *err = NULL; + * foo(arg, &err); + * if (err) { + * handle the error... + * error_propagate(errp, err); + * } + * where Error **errp is a parameter, by convention the last one. + * + * Do *not* "optimize" this to + * foo(arg, errp); + * if (*errp) { // WRONG! + * handle the error... + * } + * because errp may be NULL! + * + * But when all you do with the error is pass it on, please use + * foo(arg, errp); + * for readability. + */ + #ifndef ERROR_H #define ERROR_H @@ -17,18 +79,21 @@ #include "unicorn/platform.h" /** - * A class representing internal errors within QEMU. An error has a ErrorClass - * code and a human message. + * Opaque error object. */ typedef struct Error Error; /** - * Set an indirect pointer to an error given a ErrorClass value and a - * printf-style human message. This function is not meant to be used outside - * of QEMU. + * Get @err's human-readable error message. */ -void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) - GCC_FMT_ATTR(3, 4); +const char *error_get_pretty(Error *err); + +/* + * Get @err's error class. + * Note: use of error classes other than ERROR_CLASS_GENERIC_ERROR is + * strongly discouraged. + */ +ErrorClass error_get_class(const Error *err); /** * Set an indirect pointer to an error given a ErrorClass value and a @@ -38,50 +103,68 @@ void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) void error_set_errno(Error **errp, int os_error, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(4, 5); -/** - * Same as error_set(), but sets a generic error +/* + * Create a new error object and assign it to *@errp. + * If @errp is NULL, the error is ignored. Don't bother creating one + * then. + * If @errp is &error_abort, print a suitable message and abort(). + * If @errp is anything else, *@errp must be NULL. + * The new error's class is ERROR_CLASS_GENERIC_ERROR, and its + * human-readable error message is made from printf-style @fmt, ... */ void error_setg(Error **errp, const char *fmt, ...) GCC_FMT_ATTR(2, 3); + +/* + * Just like error_setg(), with @os_error info added to the message. + * If @os_error is non-zero, ": " + strerror(os_error) is appended to + * the human-readable error message. + */ void error_setg_errno(Error **errp, int os_error, const char *fmt, ...) GCC_FMT_ATTR(3, 4); -/** - * Helper for open() errors - */ -void error_setg_file_open(Error **errp, int os_errno, const char *filename); - /* - * Get the error class of an error object. - */ -ErrorClass error_get_class(const Error *err); - -/** - * Returns an exact copy of the error passed as an argument. - */ -Error *error_copy(const Error *err); - -/** - * Get a human readable representation of an error object. - */ -const char *error_get_pretty(Error *err); - -/** - * Propagate an error to an indirect pointer to an error. This function will - * always transfer ownership of the error reference and handles the case where - * dst_err is NULL correctly. Errors after the first are discarded. + * Propagate error object (if any) from @local_err to @dst_errp. + * If @local_err is NULL, do nothing (because there's nothing to + * propagate). + * Else, if @dst_errp is NULL, errors are being ignored. Free the + * error object. + * Else, if @dst_errp is &error_abort, print a suitable message and + * abort(). + * Else, if @dst_errp already contains an error, ignore this one: free + * the error object. + * Else, move the error object from @local_err to *@dst_errp. + * On return, @local_err is invalid. */ void error_propagate(Error **dst_errp, Error *local_err); /** - * Free an error object. + * Convenience function to report open() failure. + */ +void error_setg_file_open(Error **errp, int os_errno, const char *filename); + +/** + * Return an exact copy of @err. + */ +Error *error_copy(const Error *err); + +/** + * Free @err. + * @err may be NULL. */ void error_free(Error *err); -/** - * If passed to error_set and friends, abort(). +/* + * Just like error_setg(), except you get to specify the error class. + * Note: use of error classes other than ERROR_CLASS_GENERIC_ERROR is + * strongly discouraged. */ +void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...) + GCC_FMT_ATTR(3, 4); +/* + * Pass to error_setg() & friends to abort() on error. + */ extern Error *error_abort; #endif