[PATCH 2/9] add registry.h, change existing users

Pedro Alves palves@redhat.com
Wed Aug 29 18:19:00 GMT 2012


On 08/01/2012 09:14 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
> 
> Pedro> One thing I notice is that this leave everything templatized,
> Pedro> while it is possible to factor most things out, leaving only the
> Pedro> templating as a shim (like in C++ you would push the common code
> Pedro> to a base class that handles void*, and then derive a template
> Pedro> shim on top that just converts pointers).  Something like this.
> Pedro> This would impact your following patches, so if you prefer and
> Pedro> agree it's a good idea, I'll get back to it only after your
> Pedro> patches are in.
> 
> It seems reasonable to me.  For me the most important thing is that the
> public API remain type-safe -- I think macro-based approaches using
> void* are too error-prone -- but your patch preserves that.

Yeah.

Here's the updated patch, now that yours is in.

2012-08-29  Pedro Alves  <palves@redhat.com>

	gdb/
	* Makefile.in (COMMON_OBS): Add registry.o.
	* registry.c: New file.
	* registry.h (struct registry_container): Declare.
	(registry_data_callback): New typedef.
	(struct registry_data, struct registry_data_registration, struct
	registry_data_registry): New type.
	(register_data_with_cleanup, registry_alloc_data)
	(registry_callback_adaptor, registry_clear_data)
	(registry_container_free_data, registry_set_data, registry_data):
	Declare.
	(DEFINE_REGISTRY): Refactor structures and functions as shims over
	the new common structures and functions.
	(DECLARE_REGISTRY): Declare struct TAG ## _data.  Use the tagged
	callback typedefs.

---

 gdb/Makefile.in |    2 -
 gdb/registry.c  |  116 +++++++++++++++++++++++++++++++++++
 gdb/registry.h  |  182 ++++++++++++++++++++++++++++++++++---------------------
 3 files changed, 229 insertions(+), 71 deletions(-)
 create mode 100644 gdb/registry.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5d5574e..9e7702d 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -921,7 +921,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	inferior.o osdata.o gdb_usleep.o record.o gcore.o \
 	gdb_vecs.o jit.o progspace.o skip.o probe.o \
 	common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
-	format.o
+	format.o registry.o
 
 TSOBS = inflow.o
 
diff --git a/gdb/registry.c b/gdb/registry.c
new file mode 100644
index 0000000..c01929b
--- /dev/null
+++ b/gdb/registry.c
@@ -0,0 +1,116 @@
+/* Support functions for general registry objects.
+
+   Copyright (C) 2011, 2012
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "registry.h"
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+const struct registry_data *
+register_data_with_cleanup (struct registry_data_registry *registry,
+			    registry_data_callback save,
+			    registry_data_callback free)
+{
+  struct registry_data_registration **curr;
+
+  /* Append new registration.  */
+  for (curr = &registry->registrations;
+       *curr != NULL;
+       curr = &(*curr)->next)
+    ;
+
+  *curr = XMALLOC (struct registry_data_registration);
+  (*curr)->next = NULL;
+  (*curr)->data = XMALLOC (struct registry_data);
+  (*curr)->data->index = registry->num_registrations++;
+  (*curr)->data->save = save;
+  (*curr)->data->free = free;
+
+  return (*curr)->data;
+}
+
+void
+registry_alloc_data (struct registry_data_registry *registry,
+		       struct registry_fields *fields)
+{
+  gdb_assert (fields->data == NULL);
+  fields->num_data = registry->num_registrations;
+  fields->data = XCALLOC (fields->num_data, void *);
+}
+
+void
+registry_clear_data (struct registry_data_registry *data_registry,
+		     registry_callback_adaptor adaptor,
+		     struct registry_container *container,
+		     struct registry_fields *fields)
+{
+  struct registry_data_registration *registration;
+  int i;
+
+  gdb_assert (fields->data != NULL);
+
+  /* Process all the save handlers.  */
+
+  for (registration = data_registry->registrations, i = 0;
+       i < fields->num_data;
+       registration = registration->next, i++)
+    if (fields->data[i] != NULL && registration->data->save != NULL)
+      adaptor (registration->data->save, container, fields->data[i]);
+
+  /* Now process all the free handlers.  */
+
+  for (registration = data_registry->registrations, i = 0;
+       i < fields->num_data;
+       registration = registration->next, i++)
+    if (fields->data[i] != NULL && registration->data->free != NULL)
+      adaptor (registration->data->free, container, fields->data[i]);
+
+  memset (fields->data, 0, fields->num_data * sizeof (void *));
+}
+
+void
+registry_container_free_data (struct registry_data_registry *data_registry,
+			      registry_callback_adaptor adaptor,
+			      struct registry_container *container,
+			      struct registry_fields *fields)
+{
+  void ***rdata = &fields->data;
+  gdb_assert (*rdata != NULL);
+  registry_clear_data (data_registry, adaptor, container, fields);
+  xfree (*rdata);
+  *rdata = NULL;
+}
+
+void
+registry_set_data (struct registry_fields *fields,
+		   const struct registry_data *data,
+		   void *value)
+{
+  gdb_assert (data->index < fields->num_data);
+  fields->data[data->index] = value;
+}
+
+void *
+registry_data (struct registry_fields *fields,
+	       const struct registry_data *data)
+{
+  gdb_assert (data->index < fields->num_data);
+  return fields->data[data->index];
+}
diff --git a/gdb/registry.h b/gdb/registry.h
index 423caa6..062a500 100644
--- a/gdb/registry.h
+++ b/gdb/registry.h
@@ -85,48 +85,85 @@ struct registry_fields
 #define REGISTRY_ACCESS_FIELD(CONTAINER) \
   (CONTAINER)
 
+/* Opaque type representing a container type with a registry.  This
+   type is never defined.  This is used to factor out common
+   functionality of all struct tag names into common code.  IOW,
+   "struct tag name" pointers are cast to and from "struct
+   registry_container" pointers when calling the common registry
+   "backend" functions.  */
+struct registry_container;
+
+/* Registry callbacks have this type.  */
+typedef void (*registry_data_callback) (struct registry_container *, void *);
+
+struct registry_data
+{
+  unsigned index;
+  registry_data_callback save;
+  registry_data_callback free;
+};
+
+struct registry_data_registration
+{
+  struct registry_data *data;
+  struct registry_data_registration *next;
+};
+
+struct registry_data_registry
+{
+  struct registry_data_registration *registrations;
+  unsigned num_registrations;
+};
+
+/* Registry backend functions.  Client code uses the frontend
+   functions defined by DEFINE_REGISTRY below instead.  */
+
+const struct registry_data *register_data_with_cleanup
+  (struct registry_data_registry *registry,
+   registry_data_callback save,
+   registry_data_callback free);
+
+void registry_alloc_data (struct registry_data_registry *registry,
+			  struct registry_fields *registry_fields);
+
+/* Cast FUNC and CONTAINER to the real types, and call FUNC, also
+   passing DATA.  */
+typedef void (*registry_callback_adaptor) (registry_data_callback func,
+					   struct registry_container *container,
+					   void *data);
+
+void registry_clear_data (struct registry_data_registry *data_registry,
+			  registry_callback_adaptor adaptor,
+			  struct registry_container *container,
+			  struct registry_fields *fields);
+
+void registry_container_free_data (struct registry_data_registry *data_registry,
+				   registry_callback_adaptor adaptor,
+				   struct registry_container *container,
+				   struct registry_fields *fields);
+
+void registry_set_data (struct registry_fields *fields,
+			const struct registry_data *data,
+			void *value);
+
+void *registry_data (struct registry_fields *fields,
+		     const struct registry_data *data);
+
 /* Define a new registry implementation.  */
 
 #define DEFINE_REGISTRY(TAG, ACCESS)					\
-struct TAG ## _data							\
-{									\
-  unsigned index;							\
-  void (*save) (struct TAG *, void *);					\
-  void (*free) (struct TAG *, void *);					\
-};									\
-									\
-struct TAG ## _data_registration					\
-{									\
-  struct TAG ## _data *data;						\
-  struct TAG ## _data_registration *next;				\
-};									\
-									\
-struct TAG ## _data_registry						\
-{									\
-  struct TAG ## _data_registration *registrations;			\
-  unsigned num_registrations;						\
-};									\
-									\
-struct TAG ## _data_registry TAG ## _data_registry = { NULL, 0 };	\
+struct registry_data_registry TAG ## _data_registry = { NULL, 0 };	\
 									\
 const struct TAG ## _data *						\
 register_ ## TAG ## _data_with_cleanup (void (*save) (struct TAG *, void *), \
-				    void (*free) (struct TAG *, void *)) \
+					void (*free) (struct TAG *, void *)) \
 {									\
-  struct TAG ## _data_registration **curr;				\
-									\
-  /* Append new registration.  */					\
-  for (curr = &TAG ## _data_registry.registrations;			\
-       *curr != NULL; curr = &(*curr)->next);				\
-									\
-  *curr = XMALLOC (struct TAG ## _data_registration);			\
-  (*curr)->next = NULL;							\
-  (*curr)->data = XMALLOC (struct TAG ## _data);			\
-  (*curr)->data->index = TAG ## _data_registry.num_registrations++;	\
-  (*curr)->data->save = save;						\
-  (*curr)->data->free = free;						\
+  struct registry_data_registration **curr;				\
 									\
-  return (*curr)->data;							\
+  return (struct TAG ## _data *)					\
+    register_data_with_cleanup (&TAG ## _data_registry,			\
+				(registry_data_callback) save,		\
+				(registry_data_callback) free);		\
 }									\
 									\
 const struct TAG ## _data *						\
@@ -139,76 +176,81 @@ static void								\
 TAG ## _alloc_data (struct TAG *container)				\
 {									\
   struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-  gdb_assert (rdata->data == NULL);					\
-  rdata->num_data = TAG ## _data_registry.num_registrations;		\
-  rdata->data = XCALLOC (rdata->num_data, void *);			\
+									\
+  registry_alloc_data (&TAG ## _data_registry, rdata);			\
 }									\
 									\
-void									\
-clear_ ## TAG ## _data (struct TAG *container)				\
+static void								\
+TAG ## registry_callback_adaptor (registry_data_callback func,		\
+				  struct registry_container *container, \
+				  void *data)				\
 {									\
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-  struct TAG ## _data_registration *registration;			\
-  int i;								\
+  struct TAG *tagged_container = (struct TAG *) container;		\
+  struct registry_fields *rdata						\
+    = &ACCESS (tagged_container)->registry_data;			\
 									\
-  gdb_assert (rdata->data != NULL);					\
+  registry_ ## TAG ## _callback tagged_func				\
+    = (registry_ ## TAG ## _callback) func;				\
 									\
-  /* Process all the save handlers.  */					\
-									\
-  for (registration = TAG ## _data_registry.registrations, i = 0;	\
-       i < rdata->num_data;						\
-       registration = registration->next, i++)				\
-    if (rdata->data[i] != NULL && registration->data->save != NULL)	\
-      registration->data->save (container, rdata->data[i]);		\
-									\
-  /* Now process all the free handlers.  */				\
+  tagged_func (tagged_container, data);					\
+}									\
 									\
-  for (registration = TAG ## _data_registry.registrations, i = 0;	\
-       i < rdata->num_data;						\
-       registration = registration->next, i++)				\
-    if (rdata->data[i] != NULL && registration->data->free != NULL)	\
-      registration->data->free (container, rdata->data[i]);		\
+void									\
+clear_ ## TAG ## _data (struct TAG *container)				\
+{									\
+  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
 									\
-  memset (rdata->data, 0, rdata->num_data * sizeof (void *));		\
+  registry_clear_data (&TAG ## _data_registry,				\
+		       TAG ## registry_callback_adaptor,		\
+		       (struct registry_container *) container,		\
+		       rdata);						\
 }									\
 									\
 static void								\
 TAG ## _free_data (struct TAG *container)				\
 {									\
   struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-  gdb_assert (rdata->data != NULL);					\
-  clear_ ## TAG ## _data (container);					\
-  xfree (rdata->data);							\
-  rdata->data = NULL;							\
+									\
+  registry_container_free_data (&TAG ## _data_registry,			\
+				TAG ## registry_callback_adaptor,	\
+				(struct registry_container *) container, \
+				rdata);					\
 }									\
 									\
 void									\
-set_ ## TAG ## _data (struct TAG *container, const struct TAG ## _data *data, \
-		  void *value)						\
+set_ ## TAG ## _data (struct TAG *container,				\
+		      const struct TAG ## _data *data,			\
+		      void *value)					\
 {									\
   struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-  gdb_assert (data->index < rdata->num_data);				\
-  rdata->data[data->index] = value;					\
+									\
+  registry_set_data (rdata,						\
+		     (struct registry_data *) data,			\
+		     value);						\
 }									\
 									\
 void *									\
 TAG ## _data (struct TAG *container, const struct TAG ## _data *data)	\
 {									\
   struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-  gdb_assert (data->index < rdata->num_data);				\
-  return rdata->data[data->index];					\
+									\
+  return registry_data (rdata,						\
+			(struct registry_data *) data);			\
 }
 
 
 /* External declarations for the registry functions.  */
 
 #define DECLARE_REGISTRY(TAG)						\
+struct TAG ## _data;							\
+typedef void (*registry_ ## TAG ## _callback) (struct TAG *, void *);	\
 extern const struct TAG ## _data *register_ ## TAG ## _data (void);	\
 extern const struct TAG ## _data *register_ ## TAG ## _data_with_cleanup \
- (void (*save) (struct TAG *, void *), void (*free) (struct TAG *, void *)); \
+ (registry_ ## TAG ## _callback save, registry_ ## TAG ## _callback free); \
 extern void clear_ ## TAG ## _data (struct TAG *);		\
 extern void set_ ## TAG ## _data (struct TAG *,			\
-			       const struct TAG ## _data *data, void *value); \
+				  const struct TAG ## _data *data, \
+				  void *value);			\
 extern void *TAG ## _data (struct TAG *,			\
 			   const struct TAG ## _data *data);
 



More information about the Gdb-patches mailing list