2012-09-13 Pedro Alves <palves@redhat.com>

* 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.
This commit is contained in:
Pedro Alves 2012-09-13 14:35:16 +00:00
parent 80c4bb52e5
commit aa0fbdd82c
4 changed files with 246 additions and 71 deletions

View File

@ -1,3 +1,20 @@
2012-09-13 Pedro Alves <palves@redhat.com>
* 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.
2012-09-12 Doug Evans <dje@google.com>
* dwarf2read.c (dwarf2_read_addr_index): Fix handling the case where

View File

@ -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

116
gdb/registry.c Normal file
View File

@ -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];
}

View File

@ -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; \
struct registry_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; \
\
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); \
} \
\
static void \
TAG ## registry_callback_adaptor (registry_data_callback func, \
struct registry_container *container, \
void *data) \
{ \
struct TAG *tagged_container = (struct TAG *) container; \
struct registry_fields *rdata \
= &ACCESS (tagged_container)->registry_data; \
\
registry_ ## TAG ## _callback tagged_func \
= (registry_ ## TAG ## _callback) func; \
\
tagged_func (tagged_container, data); \
} \
\
void \
clear_ ## TAG ## _data (struct TAG *container) \
{ \
struct registry_fields *rdata = &ACCESS (container)->registry_data; \
struct TAG ## _data_registration *registration; \
int i; \
\
gdb_assert (rdata->data != NULL); \
\
/* 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. */ \
\
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]); \
\
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);