From patchwork Wed Jun 13 09:38:30 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peter A. G. Crosthwaite" X-Patchwork-Id: 164579 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 3825AB7001 for ; Wed, 13 Jun 2012 19:29:47 +1000 (EST) Received: from localhost ([::1]:60315 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SejtZ-0004Xp-1I for incoming@patchwork.ozlabs.org; Wed, 13 Jun 2012 05:29:45 -0400 Received: from eggs.gnu.org ([208.118.235.92]:43317) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SejtJ-0004D3-0j for qemu-devel@nongnu.org; Wed, 13 Jun 2012 05:29:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SejtG-0002uG-Qr for qemu-devel@nongnu.org; Wed, 13 Jun 2012 05:29:28 -0400 Received: from mail-pb0-f45.google.com ([209.85.160.45]:41951) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SejtG-0002tx-KC for qemu-devel@nongnu.org; Wed, 13 Jun 2012 05:29:26 -0400 Received: by mail-pb0-f45.google.com with SMTP id ro12so2131447pbb.4 for ; Wed, 13 Jun 2012 02:29:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :in-reply-to:references:x-gm-message-state; bh=U5mUqIC/48FomojLLMCOO5x7Io+7npjdOT/eBV64YlQ=; b=Lov9qyoH0ofkHyxHYxLvzG+IytJgHDG8l00DwTqygDNcSe0OFYa+joe9VEgwNusg8E CLShsSDXNPegvZQJPcRDi6iUyQXQ49RcfTVLDL/IViXzz4SUIXgfbCO9oMTRt3YDYpub sn0D9AmMfdI608oRBYbzzU+FbhTSJfi/xd4WvEPbybDcLRYKIq8llYjzCVit2zHQig26 4kchk8oJl09r1e4jNMvLngDSY99cNDAhataBn3hWfZUeSRo2cULO9XQLvfGsk+TcVyPf m+3DEqka6hNbji2JyU7qOTDwJaS3JfijHyjBnxn665tCbFEzh/U6BR8dM0lVd56rSZ4S kF9Q== Received: by 10.68.130.67 with SMTP id oc3mr6445137pbb.18.1339579765282; Wed, 13 Jun 2012 02:29:25 -0700 (PDT) Received: from localhost ([124.148.20.9]) by mx.google.com with ESMTPS id uy2sm576893pbc.4.2012.06.13.02.29.20 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 13 Jun 2012 02:29:24 -0700 (PDT) From: "Peter A. G. Crosthwaite" To: qemu-devel@nongnu.org, aliguori@us.ibm.com, pbonzini@redhat.com Date: Wed, 13 Jun 2012 19:38:30 +1000 Message-Id: <3da6636a9b835fe9077baa9a6c25e2a151f32f07.1339578989.git.peter.crosthwaite@petalogix.com> X-Mailer: git-send-email 1.7.3.2 In-Reply-To: References: In-Reply-To: References: X-Gm-Message-State: ALoCoQntqIOGIw+uwOHFGyeTMjjKcevzrgUIdY4hGS9WIrfkIbqWYViZOo3s5aWq1F0DazLo2gRD X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.160.45 Cc: peter.maydell@linaro.org, peter.crosthwaite@petalogix.com, paul@codesourcery.com, edgar.iglesias@gmail.com, afaerber@suse.de, john.williams@petalogix.com, avi@redhat.com Subject: [Qemu-devel] [RFC v0 1/8] qom: revamp interfaces X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Paolo Bonzini This commit is composed of several changes: 1) it provides a complete set of macros that serve as building blocks for the definition of Interface types. 2) make Interface public. This is because this type serves as the base class for the actual implementation objects that are returned by dynamic_cast. While the type itself need not be subclassed by clients and in principle could remain opaque, it is useful in helper macros. 3) Change the definition of Interface, prefixing field names with "iface_" so that the macros can perform a limited a amount of static type checking. 4) Add documentation for interfaces. It doesn't change the interface SList to a type-safe qemu-queue.h list. This can be left for later. Signed-off-by: Paolo Bonzini Signed-off-by: Peter A.G. Crosthwaite --- include/qemu/object.h | 110 +++++++++++++++++++++++++++++++++++++++++++++++++ qom/object.c | 14 ++---- 2 files changed, 114 insertions(+), 10 deletions(-) diff --git a/include/qemu/object.h b/include/qemu/object.h index d93b772..a82be5f 100644 --- a/include/qemu/object.h +++ b/include/qemu/object.h @@ -186,6 +186,40 @@ typedef struct InterfaceInfo InterfaceInfo; * similar to normal types except for the fact that are only defined by * their classes and never carry any state. You can dynamically cast an object * to one of its #Interface types and vice versa. + * + * Interfaces are special in that a cast from or to an interface type returns + * a different object pointer than what you pass. Interface methods typically + * pass the whole object as the first argument, rather than the interface. + * + * + * Defining an interface + * + * // An interface has the same basic pieces as a class. + * #define TYPE_DMA_PEER "dma-peer" + * typedef Interface DMAPeer; + * typedef struct DMAPeerIface DMAPeerIface; + * struct DMAPeerIface { + * InterfaceClass parent; + * void (*push)(Object *obj, int channel, uint8_t *buf, size_t len); + * }; + * + * // Interfaces also define utility macros for casting. + * #define DMA_PEER_GET_IFACE(obj) \ + * INTERFACE_GET_IFACE(DMAPeerIface, obj, TYPE_DMA_PEER) + * #define DMA_PEER_IFACE(klass) \ + * INTERFACE_IFACE_CHECK(DMAPeerIface, klass, TYPE_DMA_PEER) + * #define DMA_PEER(obj) \ + * INTERFACE_CHECK(obj, TYPE_DMA_PEER) + * + * // This is the wrapper that calls the method. + * void dma_push(DMAPeer *peer, int channel, uint8_t *buf, size_t len) + * { + * DMAPeerIface *iface = DMA_PEER_GET_IFACE(peer); + * + * peer->push(INTERFACE_OBJECT(peer), channel, buf, len); + * } + * + * */ @@ -392,6 +426,82 @@ struct InterfaceClass ObjectClass parent_class; }; +typedef struct Interface +{ + Object iface_parent; + Object *iface_obj; +} Interface; + +/** + * INTERFACE_CLASS: + * @class: A derivative of #InterfaceClass. + * + * Converts a class to an #InterfaceClass. Right now it really has the + * same layout as #ObjectClass, so this function will always succeed. + * This may change in the future. + */ +#define INTERFACE_CLASS(class) \ + ((InterfaceClass *)(class)) + +/** + * INTERFACE_GET_CLASS: + * @class: An interface object (an instance of Interface) + * + * Retrieve the class object (vtable) of the implementation object for an + * interface. Since all such objects have the same layout, this function + * can be statically type-checked and will always succeed. However, note + * that the result is typically passed to an OBJECT_CLASS_CHECK macro, + * which actually may fail. + */ +#define INTERFACE_GET_CLASS(iface_obj) \ + INTERFACE_CLASS(object_get_class(&(iface_obj)->iface_parent)) + +/** + * INTERFACE_IFACE_CHECK: + * @class: The C type to use for the return value. + * @obj: A derivative of @type to cast. + * @name: the QOM typename of @class. + * + * A type safe version of @object_class_dynamic_cast_assert. This macro is + * typically wrapped by each type to perform type safe casts of an interface + * to a specific type. + */ +#define INTERFACE_IFACE_CHECK(class, obj, name) \ + OBJECT_CLASS_CHECK(class, obj, name) + +/** + * INTERFACE_GET_IFACE: + * @class: An interface object (an instance of Interface) + * + * Retrieve the class object (vtable) of the implementation object for an + * interface. This macro is typically wrapped by each type to safely + * retrieve a specific vtable from an implementation object. + */ +#define INTERFACE_GET_IFACE(iface, obj, type) \ + INTERFACE_IFACE_CHECK(iface, INTERFACE_GET_CLASS(obj), type) + +/** + * INTERFACE_CHECK: + * @obj: The object to obtain the class for. + * @name: The QOM typename of @obj. + * + * This function will return the specific implementation object for a given + * interface. It's generally used by each type to provide a type safe macro + * to get a specific class type from an object. + */ +#define INTERFACE_CHECK(obj, name) OBJECT_CHECK(Interface, obj, name) + +/** + * INTERFACE_OBJECT: + * @impl: The interface implementation to obtain the parent object for. + * + * This function will return the parent object associated to any object + * that is an interface implementation. It expects a pointer to Interface. + * Since all interface objects have the same layout, this function can be + * statically type-checked and will always succeed. + */ +#define INTERFACE_OBJECT(impl) ((impl)->iface_obj) + /** * InterfaceInfo: * @type: The name of the interface. diff --git a/qom/object.c b/qom/object.c index 6f839ad..e6c3cfb 100644 --- a/qom/object.c +++ b/qom/object.c @@ -63,13 +63,7 @@ struct TypeImpl InterfaceImpl interfaces[MAX_INTERFACES]; }; -typedef struct Interface -{ - Object parent; - Object *obj; -} Interface; - -#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE) +#define INTERFACE(obj) INTERFACE_CHECK(obj, TYPE_INTERFACE) static Type type_interface; @@ -251,7 +245,7 @@ static void object_interface_init(Object *obj, InterfaceImpl *iface) Interface *iface_obj; iface_obj = INTERFACE(object_new(ti->name)); - iface_obj->obj = obj; + iface_obj->iface_obj = obj; obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj); } @@ -435,7 +429,7 @@ Object *object_dynamic_cast(Object *obj, const char *typename) */ if (object_is_type(obj, type_interface)) { assert(!obj->interfaces); - obj = INTERFACE(obj)->obj; + obj = INTERFACE(obj)->iface_obj; if (object_is_type(obj, target_type)) { return obj; } @@ -986,7 +980,7 @@ gchar *object_get_canonical_path(Object *obj) char *newpath = NULL, *path = NULL; if (object_is_type(obj, type_interface)) { - obj = INTERFACE(obj)->obj; + obj = INTERFACE(obj)->iface_obj; } while (obj != root) {