[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 5/8] Introduce QError
From: |
Luiz Capitulino |
Subject: |
[Qemu-devel] [PATCH 5/8] Introduce QError |
Date: |
Wed, 4 Nov 2009 18:04:04 -0200 |
QError is a high-level data type which represents an exception,
it stores the following error information:
- name A generic error name (eg. "ServiceUnavailable")
- description A detailed error description, which may contain
references to run-time error data
- filename The file name of where the error occurred
- line number The exact line number of the error
- run-time data Run-time error data
The qerror_print() function should be used to properly format and
print the stored information to the right place, that is, to stderr
if the Monitor is not running, or to the Monitor's device otherwise.
The following functions are exported:
- qerror_new(): Create a new QError
- qerror_from_info(): Create a new QError from the specified error
information
- qerror_print(): Print the specified QError
Signed-off-by: Luiz Capitulino <address@hidden>
---
Makefile | 2 +-
qerror.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
qerror.h | 39 ++++++++++
qobject.h | 1 +
4 files changed, 276 insertions(+), 1 deletions(-)
create mode 100644 qerror.c
create mode 100644 qerror.h
diff --git a/Makefile b/Makefile
index 6fcbcaa..2dfaebd 100644
--- a/Makefile
+++ b/Makefile
@@ -135,7 +135,7 @@ obj-y += buffered_file.o migration.o migration-tcp.o
qemu-sockets.o
obj-y += qemu-char.o aio.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 qfloat.o qbool.o qjson.o
+obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o qjson.o qerror.o
obj-y += qemu-config.o
obj-$(CONFIG_BRLAPI) += baum.o
diff --git a/qerror.c b/qerror.c
new file mode 100644
index 0000000..7d3137f
--- /dev/null
+++ b/qerror.c
@@ -0,0 +1,235 @@
+/*
+ * QError: QEMU Error data-type.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+#include "qint.h"
+#include "qjson.h"
+#include "qerror.h"
+#include "qstring.h"
+#include "sysemu.h"
+#include "qemu-common.h"
+
+static void qerror_destroy_obj(QObject *obj);
+
+static const QType qerror_type = {
+ .code = QTYPE_QERROR,
+ .destroy = qerror_destroy_obj,
+};
+
+/**
+ * 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_info(): Create a new QError from error information
+ *
+ * The information consists of:
+ *
+ * - name generic error name
+ * - file the file name of where the error occurred
+ * - linenr the line number of where the error occurred
+ * - desc detailed description (see below)
+ * - fmt JSON printf-like format for 'specific data'
+ * - va va_list of all arguments for 'specific data'
+ *
+ * Note that this is a low-level function, it is supposed to be called
+ * by higher-level functions or macros.
+ *
+ * The 'desc' parameter is a printf-like string, the format of the format
+ * string is:
+ *
+ * %(KEY)TYPE
+ *
+ * Where KEY is a QDict key and TYPE is the type of its value, KEY and
+ * its value must be passed to qerror_from_info().
+ *
+ * Valid types are:
+ *
+ * s (string)
+ * d (integer)
+ *
+ * Example:
+ *
+ * "foo error on device: %(device)s slot: %(slot_nr)d"
+ *
+ * A single percent sign can be printed if followed by a second one,
+ * for example:
+ *
+ * "running out of foo: %(foo)d%%"
+ *
+ * Return strong reference.
+ */
+QError *qerror_from_info(const char *name, const char *file, int linenr,
+ const char *desc, const char *fmt, va_list *va)
+{
+ QError *qerr;
+
+ qerr = qerror_new();
+ qerr->name = name;
+ qerr->file = file;
+ qerr->linenr = linenr;
+ qerr->desc = desc;
+ if (fmt) {
+ qerr->data = qobject_from_json_va(fmt, va);
+ assert(qerr->data != NULL);
+ }
+
+ return qerr;
+}
+
+static char *get_substr(const char *start, const char *end)
+{
+ char *str;
+ size_t length;
+
+ length = end - start + 1;
+ str = qemu_malloc(length + 1);
+ memcpy(str, start, length);
+ str[length] = '\0';
+
+ return str;
+}
+
+static void qerror_abort(const QError *qerr)
+{
+ fprintf(stderr, " in '%s' at %s:%d\n", qerr->desc,
qerr->file,qerr->linenr);
+ abort();
+}
+
+#define ERROR_PREFIX "\n\nqerror: "
+
+static void type_error(const QError *qerr, int c)
+{
+ fprintf(stderr, ERROR_PREFIX "invalid type '%c'", c);
+ qerror_abort(qerr);
+}
+
+static void key_error(const QError *qerr, const char *key)
+{
+ fprintf(stderr, ERROR_PREFIX "key '%s' not found in QDict ", key);
+ fprintf(stderr, "call at %s:%d\n", qerr->file, qerr->linenr);
+ abort();
+}
+
+static void parse_error(const QError *qerror, int c)
+{
+ fprintf(stderr, ERROR_PREFIX "expected '%c'", c);
+ qerror_abort(qerror);
+}
+
+static const char *append_field(QString *qstring, const QError *qerror,
+ const char *start)
+{
+ int type;
+ char *name;
+ QDict *qdict;
+ const char *end;
+
+ if (*start != '%')
+ parse_error(qerror, '%');
+ start++;
+ if (*start != '(')
+ parse_error(qerror, '(');
+ start++;
+
+ end = strchr(start, ')');
+ if (!end)
+ parse_error(qerror, ')');
+
+ name = get_substr(start, end - 1);
+ qdict = qobject_to_qdict(qerror->data);
+
+ if (!qdict_haskey(qdict, name)) {
+ key_error(qerror, name);
+ }
+
+ type = *++end;
+ switch (type) {
+ case 's':
+ qstring_append(qstring, qdict_get_str(qdict, name));
+ break;
+ case 'd':
+ qstring_append_int(qstring, qdict_get_int(qdict, name));
+ break;
+ default:
+ type_error(qerror, type);
+ }
+
+ qemu_free(name);
+ return ++end;
+}
+
+/**
+ * qerror_print(): Print QError data
+ *
+ * This function will print the member 'desc' of the specified QError object,
+ * it uses qemu_error() for this, so that the output is routed to the right
+ * place (ie. stderr ou Monitor's device).
+ */
+void qerror_print(const QError *qerror)
+{
+ const char *p;
+ QString *qstring;
+
+ assert(qerror->desc != NULL);
+
+ qstring = qstring_new();
+
+ for (p = qerror->desc; *p != '\0';) {
+ if (*p != '%') {
+ qstring_append_chr(qstring, *p++);
+ } else if (*(p + 1) == '%') {
+ qstring_append_chr(qstring, '%');
+ p += 2;
+ } else {
+ p = append_field(qstring, qerror, p);
+ }
+ }
+
+ qemu_error("%s\n", qstring_get_str(qstring));
+ QDECREF(qstring);
+}
+
+/**
+ * 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..dc39dec
--- /dev/null
+++ b/qerror.h
@@ -0,0 +1,39 @@
+/*
+ * QError header file.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <address@hidden>
+ *
+ * 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"
+
+typedef struct QError {
+ QObject_HEAD;
+ const char *name; /* generic name */
+ const char *desc; /* description */
+ int linenr; /* line number */
+ const char *file; /* file name */
+ QObject *data; /* run-time data */
+} QError;
+
+QError *qerror_new(void);
+QError *qerror_from_info(const char *name, const char *file, int linenr,
+ const char *desc, const char *fmt, va_list *va);
+void qerror_print(const QError *qerror);
+QError *qobject_to_qerror(const QObject *obj);
+
+/*
+ * Common error names
+ */
+#define QERR_DEV_NFOUND "DeviceNotFound"
+#define QERR_SER_UNAV "ServiceUnavailable"
+
+#endif /* QERROR_H */
diff --git a/qobject.h b/qobject.h
index 167b607..838dddc 100644
--- a/qobject.h
+++ b/qobject.h
@@ -43,6 +43,7 @@ typedef enum {
QTYPE_QLIST,
QTYPE_QFLOAT,
QTYPE_QBOOL,
+ QTYPE_QERROR,
} qtype_code;
struct QObject;
--
1.6.5.2.143.g8cc62
- [Qemu-devel] [RFC 0/8]: QError v2, Luiz Capitulino, 2009/11/04
- [Qemu-devel] [PATCH 1/8] QJSon: Introduce qobject_from_json_va(), Luiz Capitulino, 2009/11/04
- [Qemu-devel] [PATCH 3/8] Add qstring_append_chr() unit-test, Luiz Capitulino, 2009/11/04
- [Qemu-devel] [PATCH 2/8] QString: Introduce qstring_append_chr(), Luiz Capitulino, 2009/11/04
- [Qemu-devel] [PATCH 4/8] QString: Introduce qstring_append_int(), Luiz Capitulino, 2009/11/04
- [Qemu-devel] [PATCH 5/8] Introduce QError,
Luiz Capitulino <=
- [Qemu-devel] [PATCH 6/8] monitor: QError support, Luiz Capitulino, 2009/11/04
- [Qemu-devel] [PATCH 7/8] qdev: Use QError for not found error, Luiz Capitulino, 2009/11/04
- [Qemu-devel] [PATCH 8/8] monitor: do_info_balloon(): use QError, Luiz Capitulino, 2009/11/04
- Re: [Qemu-devel] [RFC 0/8]: QError v2, Anthony Liguori, 2009/11/11