summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-06-04 20:45:23 +0200
committerThomas Haller <thaller@redhat.com>2017-07-05 14:22:10 +0200
commitb8bc80bcdb4f384d6b151691eefbbf9001f5f993 (patch)
tree3689a1b1f6fc7ac97169bb964613fbf78dcbf508
parent3f76b5b7eb418caaa47897c8b8169877a5fdf757 (diff)
downloadNetworkManager-b8bc80bcdb4f384d6b151691eefbbf9001f5f993.tar.gz
all: add base object type in "nm-obj.h"
Platform has it's own, simple implementation of object types: NMPObject. Extract a base type and move it to "shared/nm-utils/nm-obj.h" so it can be reused. The base type is trival, but it allows us to implement other objects which are compatible with NMPObjects. Currently there is no API for generic NMObjBaseInst type, so compatible in this case only means, that they can be used in the same context (see example below). The only thing that you can do with a NMObjBaseInst is check it's NMObjBaseClass. Incidentally, NMObjBaseInst is also made compatible to GTypeInstance. It means, an NMObjBaseInst is not necessarily a valid GTypeInstance (like NMPObject is not), but it could be implemented as such. For example, you could do: if (NMP_CLASS_IS_VALID ((NMPClass *) obj->klass)) { /* is an NMPObject */ } else if (G_TYPE_CHECK_INSTANCE_TYPE (obj, NM_TYPE_SOMETHING)) { /* it a NMSometing GType */ } else { /* something else? */ } The reason why NMPObject is not implemented as proper GTypeInstance is because it would require us to register a GType (like g_type_register_fundamental). However, then the NMPClass struct can no longer be const and immutable memory. But we could. NMObjBaseInst may or may not be a GTypeInstance. In a sense, it's a base type of GTypeInstance and all our objects should be based on it (optionally, they we may make them valid GTypes too).
-rw-r--r--Makefile.am1
-rw-r--r--shared/nm-utils/nm-obj.h82
-rw-r--r--src/platform/nmp-object.c12
-rw-r--r--src/platform/nmp-object.h19
-rw-r--r--src/platform/tests/test-nmp-object.c51
5 files changed, 151 insertions, 14 deletions
diff --git a/Makefile.am b/Makefile.am
index f25fc02711..336fbd5a7a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4444,6 +4444,7 @@ EXTRA_DIST += \
shared/nm-utils/c-list.h \
shared/nm-utils/gsystem-local-alloc.h \
shared/nm-utils/nm-glib.h \
+ shared/nm-utils/nm-obj.h \
shared/nm-utils/nm-macros-internal.h \
shared/nm-utils/nm-shared-utils.c \
shared/nm-utils/nm-shared-utils.h \
diff --git a/shared/nm-utils/nm-obj.h b/shared/nm-utils/nm-obj.h
new file mode 100644
index 0000000000..1a9d48681a
--- /dev/null
+++ b/shared/nm-utils/nm-obj.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2017 Red Hat, Inc.
+ */
+
+#ifndef __NM_OBJ_H__
+#define __NM_OBJ_H__
+
+/*****************************************************************************/
+
+#define NM_OBJ_REF_COUNT_STACKINIT (G_MAXINT)
+
+typedef struct _NMObjBaseInst NMObjBaseInst;
+typedef struct _NMObjBaseClass NMObjBaseClass;
+
+struct _NMObjBaseInst {
+ /* The first field of NMObjBaseInst is compatible with GObject.
+ * Basically, NMObjBaseInst is an abstract base type of GTypeInstance.
+ *
+ * If you do it right, you may derive a type of NMObjBaseInst as a proper GTypeInstance.
+ * That involves allocating a GType for it, which can be inconvenient because
+ * a GType is dynamically created (and the class can no longer be immutable
+ * memory).
+ *
+ * Even if your implementation of NMObjBaseInst is not a full fledged GType(Instance),
+ * you still can use GTypeInstances in the same context as you can decide based on the
+ * NMObjBaseClass with what kind of object you are dealing with.
+ *
+ * Basically, the only thing NMObjBaseInst gives you is access to an
+ * NMObjBaseClass instance.
+ */
+ union {
+ const NMObjBaseClass *klass;
+ GTypeInstance g_type_instance;
+ };
+};
+
+struct _NMObjBaseClass {
+ /* NMObjBaseClass is the base class of all NMObjBaseInst implementations.
+ * Note that it is also an abstract super class of GTypeInstance, that means
+ * you may implement a NMObjBaseClass as a subtype of GTypeClass.
+ *
+ * For that to work, you must properly set the GTypeClass instance (and it's
+ * GType).
+ *
+ * Note that to implement a NMObjBaseClass that is *not* a GTypeClass, you wouldn't
+ * set the GType. Hence, this field is only useful for type implementations that actually
+ * extend GTypeClass.
+ *
+ * In a way it is wrong that NMObjBaseClass has the GType member, because it is
+ * a base class of GTypeClass and doesn't necessarily use the GType. However,
+ * it is here so that G_TYPE_CHECK_INSTANCE_TYPE() and friends work correctly
+ * on any NMObjectClass. That means, while not necessary, it is convenient that
+ * a NMObjBaseClass has all members of GTypeClass.
+ * Also note that usually you have only one instance of a certain type, so this
+ * wastes just a few bytes for the unneeded GType.
+ */
+ union {
+ GType g_type;
+ GTypeClass g_type_class;
+ };
+};
+
+/*****************************************************************************/
+
+#endif /* __NM_OBJ_H__ */
diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c
index 2d77824bf9..4bf2b9f8fd 100644
--- a/src/platform/nmp-object.c
+++ b/src/platform/nmp-object.c
@@ -208,7 +208,7 @@ NMPObject *
nmp_object_ref (NMPObject *obj)
{
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj), NULL);
- g_return_val_if_fail (obj->_ref_count != NMP_REF_COUNT_STACKINIT, NULL);
+ g_return_val_if_fail (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT, NULL);
obj->_ref_count++;
return obj;
@@ -219,7 +219,7 @@ nmp_object_unref (NMPObject *obj)
{
if (obj) {
g_return_if_fail (obj->_ref_count > 0);
- g_return_if_fail (obj->_ref_count != NMP_REF_COUNT_STACKINIT);
+ g_return_if_fail (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT);
if (--obj->_ref_count <= 0) {
const NMPClass *klass = obj->_class;
@@ -294,7 +294,7 @@ _nmp_object_stackinit_from_class (NMPObject *obj, const NMPClass *klass)
memset (obj, 0, sizeof (NMPObject));
obj->_class = klass;
- obj->_ref_count = NMP_REF_COUNT_STACKINIT;
+ obj->_ref_count = NM_OBJ_REF_COUNT_STACKINIT;
return obj;
}
@@ -434,7 +434,7 @@ nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode
return klass->cmd_plobj_to_string_id (&obj->object, buf, buf_size);
case NMP_OBJECT_TO_STRING_ALL:
g_snprintf (buf, buf_size,
- "[%s,%p,%d,%ccache,%calive,%cvisible; %s]",
+ "[%s,%p,%u,%ccache,%calive,%cvisible; %s]",
klass->obj_type_name, obj, obj->_ref_count,
obj->is_cached ? '+' : '-',
nmp_object_is_alive (obj) ? '+' : '-',
@@ -461,7 +461,7 @@ _vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_strin
return klass->cmd_plobj_to_string_id (&obj->object, buf, buf_size);
case NMP_OBJECT_TO_STRING_ALL:
g_snprintf (buf, buf_size,
- "[%s,%p,%d,%ccache,%calive,%cvisible,%cin-nl,%p; %s]",
+ "[%s,%p,%u,%ccache,%calive,%cvisible,%cin-nl,%p; %s]",
klass->obj_type_name, obj, obj->_ref_count,
obj->is_cached ? '+' : '-',
nmp_object_is_alive (obj) ? '+' : '-',
@@ -502,7 +502,7 @@ _vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_s
case NMP_OBJECT_TO_STRING_ALL:
g_snprintf (buf, buf_size,
- "[%s,%p,%d,%ccache,%calive,%cvisible; %s]",
+ "[%s,%p,%u,%ccache,%calive,%cvisible; %s]",
klass->obj_type_name, obj, obj->_ref_count,
obj->is_cached ? '+' : '-',
nmp_object_is_alive (obj) ? '+' : '-',
diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h
index fb7f713f31..a21d6fd192 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -21,6 +21,7 @@
#ifndef __NMP_OBJECT_H__
#define __NMP_OBJECT_H__
+#include "nm-utils/nm-obj.h"
#include "nm-platform.h"
#include "nm-multi-index.h"
@@ -138,13 +139,14 @@ struct _NMPCacheId {
};
typedef struct {
+ NMObjBaseClass parent;
+ const char *obj_type_name;
+ int sizeof_data;
+ int sizeof_public;
NMPObjectType obj_type;
int addr_family;
int rtm_gettype;
- int sizeof_data;
- int sizeof_public;
NMPlatformSignalIdType signal_type_id;
- const char *obj_type_name;
const char *signal_type;
const guint8 *supported_cache_ids;
@@ -266,8 +268,11 @@ typedef struct {
} NMPObjectIP6Route;
struct _NMPObject {
- const NMPClass *_class;
- int _ref_count;
+ union {
+ NMObjBaseInst parent;
+ const NMPClass *_class;
+ };
+ guint _ref_count;
bool is_cached;
union {
NMPlatformObject object;
@@ -326,8 +331,6 @@ NMP_CLASS_IS_VALID (const NMPClass *klass)
&& ((((char *) klass) - ((char *) _nmp_classes)) % (sizeof (_nmp_classes[0]))) == 0;
}
-#define NMP_REF_COUNT_STACKINIT (G_MAXINT)
-
static inline NMPObject *
NMP_OBJECT_UP_CAST(const NMPlatformObject *plobj)
{
@@ -358,7 +361,7 @@ NMP_OBJECT_IS_STACKINIT (const NMPObject *obj)
{
nm_assert (!obj || NMP_OBJECT_IS_VALID (obj));
- return obj && obj->_ref_count == NMP_REF_COUNT_STACKINIT;
+ return obj && obj->_ref_count == NM_OBJ_REF_COUNT_STACKINIT;
}
static inline const NMPClass *
diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c
index 42dfc572e6..adc006e6f2 100644
--- a/src/platform/tests/test-nmp-object.c
+++ b/src/platform/tests/test-nmp-object.c
@@ -33,6 +33,56 @@ struct {
/*****************************************************************************/
+static void
+test_obj_base (void)
+{
+ static const GObject *g = NULL;
+ static const GTypeClass *k = NULL;
+ static const NMPObject *o = NULL;
+ static const NMPClass *c = NULL;
+
+ NMObjBaseInst *obj;
+ gs_unref_object GCancellable *obj_cancellable = g_cancellable_new ();
+ nm_auto_nmpobj NMPObject *obj_link = nmp_object_new_link (10);
+
+#define STATIC_ASSERT(cond) \
+ G_STMT_START { \
+ G_STATIC_ASSERT (cond); \
+ G_STATIC_ASSERT_EXPR (cond); \
+ g_assert (cond); \
+ } G_STMT_END
+
+ STATIC_ASSERT (&g->g_type_instance == (void *) &o->_class);
+ STATIC_ASSERT (&g->g_type_instance.g_class == (void *) &o->_class);
+ STATIC_ASSERT (&g->ref_count == (void *) &o->_ref_count);
+
+ STATIC_ASSERT (sizeof (o->parent) == sizeof (GTypeInstance));
+
+ STATIC_ASSERT (&c->parent == (void *) c);
+ STATIC_ASSERT (&c->parent.g_type_class == (void *) c);
+ STATIC_ASSERT (&c->parent.g_type == (void *) c);
+ STATIC_ASSERT (&c->parent.g_type == &k->g_type);
+
+ STATIC_ASSERT (sizeof (c->parent) == sizeof (GTypeClass));
+
+ STATIC_ASSERT (&o->parent == (void *) o);
+ STATIC_ASSERT (&o->parent.klass == (void *) &o->_class);
+
+ STATIC_ASSERT (G_STRUCT_OFFSET (NMPObject, _ref_count) == sizeof (NMObjBaseInst));
+ STATIC_ASSERT (G_STRUCT_OFFSET (NMPClass, obj_type_name) == sizeof (NMObjBaseClass));
+
+ obj = (NMObjBaseInst *) obj_cancellable;
+ g_assert (!NMP_CLASS_IS_VALID ((NMPClass *) obj->klass));
+ g_assert (G_TYPE_CHECK_INSTANCE_TYPE (obj, G_TYPE_CANCELLABLE));
+
+ obj = (NMObjBaseInst *) obj_link;
+ g_assert (NMP_CLASS_IS_VALID ((NMPClass *) obj->klass));
+ g_assert (!G_TYPE_CHECK_INSTANCE_TYPE (obj, G_TYPE_CANCELLABLE));
+
+}
+
+/*****************************************************************************/
+
static gboolean
_nmp_object_id_equal (const NMPObject *a, const NMPObject *b)
{
@@ -429,6 +479,7 @@ main (int argc, char **argv)
udev_enumerate_unref (enumerator);
}
+ g_test_add_func ("/nmp-object/obj-base", test_obj_base);
g_test_add_func ("/nmp-object/cache_link", test_cache_link);
result = g_test_run ();