Patchwork [4/9] Introduce QError

login
register
mail settings
Submitter Luiz Capitulino
Date Oct. 13, 2009, 4:57 p.m.
Message ID <1255453026-18637-5-git-send-email-lcapitulino@redhat.com>
Download mbox | patch
Permalink /patch/35875/
State New
Headers show

Comments

Luiz Capitulino - Oct. 13, 2009, 4:57 p.m.
QError is a high-level data type that can be used to store error
information.

Before using it functions usually have to register a new error type,
this is done by adding a new entry in the qerror_type[] table with
the following error information:

1. Code, which should be added to enum QErrorCode first
2. Description, the general error cause
3. Prefix, usually subsystem's name
4. A print function

The prefix and print function are optional. If no print function is
specified the default one will be used, which prints the prefix
before printing the error description.

Note that the default function is very simple and a deep level of
data structure nesting has not been tested.

QError exports the following functions:

- qerror_new(): Create a new 'empty' QError
- qerror_from_va(): Create a new QError from the specified va_list
- qerror_print(): Print the specified QError

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 Makefile  |    2 +-
 qerror.c  |  189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qerror.h  |   47 +++++++++++++++
 qobject.h |    1 +
 4 files changed, 238 insertions(+), 1 deletions(-)
 create mode 100644 qerror.c
 create mode 100644 qerror.h

Patch

diff --git a/Makefile b/Makefile
index e60eb4b..1c1ee86 100644
--- a/Makefile
+++ b/Makefile
@@ -125,7 +125,7 @@  obj-y += buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
 obj-y += qemu-char.o aio.o net-checksum.o savevm.o
 obj-y += msmouse.o ps2.o
 obj-y += qdev.o qdev-properties.o
-obj-y += qint.o qstring.o qdict.o qlist.o qmisc.o qemu-config.o
+obj-y += qint.o qstring.o qdict.o qlist.o qmisc.o qerror.o qemu-config.o
 
 obj-$(CONFIG_BRLAPI) += baum.o
 obj-$(CONFIG_WIN32) += tap-win32.o
diff --git a/qerror.c b/qerror.c
new file mode 100644
index 0000000..bbea770
--- /dev/null
+++ b/qerror.c
@@ -0,0 +1,189 @@ 
+/*
+ * QError: QEMU Error data-type.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+#include "sysemu.h"
+#include "qint.h"
+#include "qmisc.h"
+#include "qlist.h"
+#include "qerror.h"
+#include "qstring.h"
+#include "qemu-common.h"
+
+static void qerror_destroy_obj(QObject *obj);
+
+static const QType qerror_type = {
+    .code = QTYPE_QERROR,
+    .destroy = qerror_destroy_obj,
+};
+
+static QErrorTable qerror_table[] = {
+    {
+        .code   = QERR_UNKNOWN,
+        .desc   = "unknown error",
+    },
+};
+
+/**
+ * qerror_new(): Create a new QError
+ *
+ * Return strong reference.
+ */
+QError *qerror_new(void)
+{
+    QError *qerr;
+
+    qerr = qemu_mallocz(sizeof(*qerr));
+    QOBJECT_INIT(qerr, &qerror_type);
+
+    return qerr;
+}
+
+/*
+ * qerror_from_va(): Create a new QError from a va_list
+ *
+ * The specified format and va_list are used to build the specific
+ * error data object, which is stored in the 'data' member of QError.
+ *
+ * Return strong reference.
+ */
+QError *qerror_from_va(QErrorCode code, const char *fmt, va_list va)
+{
+    QError *qerr;
+
+    assert((code > 0) && (code < QERR_MAX));
+
+    qerr = qerror_new();
+    qerr->entry = &qerror_table[code];
+    if (fmt) {
+        qerr->data = qobject_from_va(fmt, va);
+        if (!qerr->data) {
+            qemu_free(qerr);
+            return NULL;
+        }
+    }
+
+    return qerr;
+}
+
+static int show_dict_sep;
+static int show_list_sep;
+static void qerror_qobject_print(const QObject *obj);
+
+static void print_qdict(const char *key, QObject *obj, void *opaque)
+{
+    if (show_dict_sep)
+        qemu_error(",");
+
+    qemu_error("%s=", key);
+    qerror_qobject_print(obj);
+
+    show_dict_sep = 1;
+}
+
+static void print_qlist(QObject *obj, void *opaque)
+{
+    if (show_list_sep)
+        qemu_error(",");
+
+    qerror_qobject_print(obj);
+
+    show_list_sep = 1;
+}
+
+static void qerror_qobject_print(const QObject *obj)
+{
+    if (!obj)
+        return;
+
+    switch (qobject_type(obj)) {
+        case QTYPE_QINT:
+            qemu_error("%" PRId64, qint_get_int(qobject_to_qint(obj)));
+            break;
+        case QTYPE_QSTRING:
+            qemu_error("%s", qstring_get_str(qobject_to_qstring(obj)));
+            break;
+        case QTYPE_QDICT:
+            show_dict_sep = 0;
+            qdict_iter(qobject_to_qdict(obj), print_qdict, NULL);
+            break;
+        case QTYPE_QLIST:
+            show_list_sep = 0;
+            qlist_iter(qobject_to_qlist(obj), print_qlist, NULL);
+            break;
+        default:
+            abort();
+            break;
+    }
+}
+
+/**
+ * qerror_default_print(): Standard function to print QError data
+ */
+static void qerror_default_print(const QError *qerror)
+{
+    const QErrorTable *entry = qerror->entry;
+
+    if (entry->prefix)
+        qemu_error("%s: ", entry->prefix);
+
+    qemu_error("%s", entry->desc);
+    if (qerror->data) {
+        qemu_error(": ");
+        qerror_qobject_print(qerror->data);
+    }
+
+    qemu_error("\n");
+}
+
+/**
+ * qerror_print(): Print QError data
+ *
+ * This function calls the user_print() callback associated
+ * with the error to print QError data in human readable
+ * format.
+ *
+ * If the error does not define a user_print() callback, the
+ * standard one will be called.
+ */
+void qerror_print(const QError *qerror)
+{
+    if (qerror->entry->user_print) {
+        qerror->entry->user_print(qerror);
+    } else {
+        qerror_default_print(qerror);
+    }
+}
+
+/**
+ * qobject_to_qerror(): Convert a QObject into a QError
+ */
+QError *qobject_to_qerror(const QObject *obj)
+{
+    if (qobject_type(obj) != QTYPE_QERROR) {
+        return NULL;
+    }
+
+    return container_of(obj, QError, base);
+}
+
+/**
+ * qerror_destroy_obj(): Free all memory allocated by a QError
+ */
+static void qerror_destroy_obj(QObject *obj)
+{
+    QError *qerr;
+
+    assert(obj != NULL);
+    qerr = qobject_to_qerror(obj);
+
+    qobject_decref(qerr->data);
+    qemu_free(qerr);
+}
diff --git a/qerror.h b/qerror.h
new file mode 100644
index 0000000..ed25ef1
--- /dev/null
+++ b/qerror.h
@@ -0,0 +1,47 @@ 
+/*
+ * QError header file.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+#ifndef QERROR_H
+#define QERROR_H
+
+#include <stdarg.h>
+#include "qobject.h"
+
+/*
+ * IMPORTANT: errors numbers must not change after they have been
+ * added here.
+ */
+typedef enum QErrorCode {
+    QERR_UNKNOWN,
+    QERR_MAX,
+} QErrorCode;
+
+struct QError;
+
+typedef struct QErrorTable {
+    QErrorCode code;
+    const char *prefix;
+    const char *desc;
+    void (*user_print)(const struct QError *qerror);
+} QErrorTable;
+
+typedef struct QError {
+    QObject_HEAD;
+    QObject *data; /* error specific data */
+    const QErrorTable *entry;
+} QError;
+
+QError *qerror_new(void);
+QError *qerror_from_va(QErrorCode code, const char *fmt, va_list va);
+QError *qobject_to_qerror(const QObject *obj);
+void qerror_print(const QError *qerror);
+
+#endif /* QERROR_H */
diff --git a/qobject.h b/qobject.h
index 4cc9287..484d4dd 100644
--- a/qobject.h
+++ b/qobject.h
@@ -41,6 +41,7 @@  typedef enum {
     QTYPE_QSTRING,
     QTYPE_QDICT,
     QTYPE_QLIST,
+    QTYPE_QERROR,
 } qtype_code;
 
 struct QObject;