c687bc
From b2ac3e491eb7f18a421e2b1132e527d484681767 Mon Sep 17 00:00:00 2001
c687bc
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
c687bc
Date: Wed, 16 Dec 2020 16:06:09 -0500
c687bc
Subject: [PATCH 08/14] error: Document Error API usage rules
c687bc
MIME-Version: 1.0
c687bc
Content-Type: text/plain; charset=UTF-8
c687bc
Content-Transfer-Encoding: 8bit
c687bc
c687bc
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
c687bc
Message-id: <20201216160615.324213-5-marcandre.lureau@redhat.com>
c687bc
Patchwork-id: 100477
c687bc
O-Subject: [RHEL-8.4.0 qemu-kvm PATCH v2 04/10] error: Document Error API usage rules
c687bc
Bugzilla: 1859494
c687bc
RH-Acked-by: Danilo de Paula <ddepaula@redhat.com>
c687bc
RH-Acked-by: Sergio Lopez Pascual <slp@redhat.com>
c687bc
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
c687bc
c687bc
From: Markus Armbruster <armbru@redhat.com>
c687bc
c687bc
This merely codifies existing practice, with one exception: the rule
c687bc
advising against returning void, where existing practice is mixed.
c687bc
c687bc
When the Error API was created, we adopted the (unwritten) rule to
c687bc
return void when the function returns no useful value on success,
c687bc
unlike GError, which recommends to return true on success and false on
c687bc
error then.
c687bc
c687bc
When a function returns a distinct error value, say false, a checked
c687bc
call that passes the error up looks like
c687bc
c687bc
    if (!frobnicate(..., errp)) {
c687bc
        handle the error...
c687bc
    }
c687bc
c687bc
When it returns void, we need
c687bc
c687bc
    Error *err = NULL;
c687bc
c687bc
    frobnicate(..., &err;;
c687bc
    if (err) {
c687bc
        handle the error...
c687bc
        error_propagate(errp, err);
c687bc
    }
c687bc
c687bc
Not only is this more verbose, it also creates an Error object even
c687bc
when @errp is null, &error_abort or &error_fatal.
c687bc
c687bc
People got tired of the additional boilerplate, and started to ignore
c687bc
the unwritten rule.  The result is confusion among developers about
c687bc
the preferred usage.
c687bc
c687bc
Make the rule advising against returning void official by putting it
c687bc
in writing.  This will hopefully reduce confusion.
c687bc
c687bc
Update the examples accordingly.
c687bc
c687bc
The remainder of this series will update a substantial amount of code
c687bc
to honor the rule.
c687bc
c687bc
Signed-off-by: Markus Armbruster <armbru@redhat.com>
c687bc
Reviewed-by: Eric Blake <eblake@redhat.com>
c687bc
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
c687bc
Reviewed-by: Greg Kurz <groug@kaod.org>
c687bc
Message-Id: <20200707160613.848843-4-armbru@redhat.com>
c687bc
c687bc
(cherry picked from commit e3fe3988d7851cac30abffae06d2f555ff7bee62)
c687bc
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
c687bc
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
c687bc
---
c687bc
 include/qapi/error.h | 52 +++++++++++++++++++++++++++++++++++++++-----
c687bc
 1 file changed, 46 insertions(+), 6 deletions(-)
c687bc
c687bc
diff --git a/include/qapi/error.h b/include/qapi/error.h
c687bc
index 3351fe76368..08d48e74836 100644
c687bc
--- a/include/qapi/error.h
c687bc
+++ b/include/qapi/error.h
c687bc
@@ -15,6 +15,33 @@
c687bc
 /*
c687bc
  * Error reporting system loosely patterned after Glib's GError.
c687bc
  *
c687bc
+ * = Rules =
c687bc
+ *
c687bc
+ * - Functions that use Error to report errors have an Error **errp
c687bc
+ *   parameter.  It should be the last parameter, except for functions
c687bc
+ *   taking variable arguments.
c687bc
+ *
c687bc
+ * - You may pass NULL to not receive the error, &error_abort to abort
c687bc
+ *   on error, &error_fatal to exit(1) on error, or a pointer to a
c687bc
+ *   variable containing NULL to receive the error.
c687bc
+ *
c687bc
+ * - Separation of concerns: the function is responsible for detecting
c687bc
+ *   errors and failing cleanly; handling the error is its caller's
c687bc
+ *   job.  Since the value of @errp is about handling the error, the
c687bc
+ *   function should not examine it.
c687bc
+ *
c687bc
+ * - On success, the function should not touch *errp.  On failure, it
c687bc
+ *   should set a new error, e.g. with error_setg(errp, ...), or
c687bc
+ *   propagate an existing one, e.g. with error_propagate(errp, ...).
c687bc
+ *
c687bc
+ * - Whenever practical, also return a value that indicates success /
c687bc
+ *   failure.  This can make the error checking more concise, and can
c687bc
+ *   avoid useless error object creation and destruction.  Note that
c687bc
+ *   we still have many functions returning void.  We recommend
c687bc
+ *   • bool-valued functions return true on success / false on failure,
c687bc
+ *   • pointer-valued functions return non-null / null pointer, and
c687bc
+ *   • integer-valued functions return non-negative / negative.
c687bc
+ *
c687bc
  * = Creating errors =
c687bc
  *
c687bc
  * Create an error:
c687bc
@@ -95,14 +122,13 @@
c687bc
  * Create a new error and pass it to the caller:
c687bc
  *     error_setg(errp, "situation normal, all fouled up");
c687bc
  *
c687bc
- * Call a function and receive an error from it:
c687bc
- *     Error *err = NULL;
c687bc
- *     foo(arg, &err;;
c687bc
- *     if (err) {
c687bc
+ * Call a function, receive an error from it, and pass it to the caller
c687bc
+ * - when the function returns a value that indicates failure, say
c687bc
+ *   false:
c687bc
+ *     if (!foo(arg, errp)) {
c687bc
  *         handle the error...
c687bc
  *     }
c687bc
- *
c687bc
- * Receive an error and pass it on to the caller:
c687bc
+ * - when it does not, say because it is a void function:
c687bc
  *     Error *err = NULL;
c687bc
  *     foo(arg, &err;;
c687bc
  *     if (err) {
c687bc
@@ -120,6 +146,20 @@
c687bc
  *     foo(arg, errp);
c687bc
  * for readability.
c687bc
  *
c687bc
+ * Receive an error, and handle it locally
c687bc
+ * - when the function returns a value that indicates failure, say
c687bc
+ *   false:
c687bc
+ *     Error *err = NULL;
c687bc
+ *     if (!foo(arg, &err)) {
c687bc
+ *         handle the error...
c687bc
+ *     }
c687bc
+ * - when it does not, say because it is a void function:
c687bc
+ *     Error *err = NULL;
c687bc
+ *     foo(arg, &err;;
c687bc
+ *     if (err) {
c687bc
+ *         handle the error...
c687bc
+ *     }
c687bc
+ *
c687bc
  * Receive and accumulate multiple errors (first one wins):
c687bc
  *     Error *err = NULL, *local_err = NULL;
c687bc
  *     foo(arg, &err;;
c687bc
-- 
c687bc
2.27.0
c687bc