On 05/22/2014 08:57 PM, Alexander Graf wrote: > > On 22.05.14 12:53, Alexey Kardashevskiy wrote: >> This adds a VMSTATE_HASH_V macro. This implements put/get callbacks for it. >> This implements a qemu_hash_init() wrapper to save key/value sizes. >> >> Signed-off-by: Alexey Kardashevskiy <a...@ozlabs.ru> >> --- >> include/migration/vmstate.h | 10 +++++++++ >> include/qemu-common.h | 13 +++++++++++ >> vmstate.c | 54 >> +++++++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 77 insertions(+) >> >> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h >> index 7e45048..6af599d 100644 >> --- a/include/migration/vmstate.h >> +++ b/include/migration/vmstate.h >> @@ -166,6 +166,7 @@ extern const VMStateInfo vmstate_info_timer; >> extern const VMStateInfo vmstate_info_buffer; >> extern const VMStateInfo vmstate_info_unused_buffer; >> extern const VMStateInfo vmstate_info_bitmap; >> +static const VMStateInfo vmstate_info_hash; >> #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0) >> #define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0) >> @@ -740,6 +741,15 @@ extern const VMStateInfo vmstate_info_bitmap; >> #define VMSTATE_BUFFER_UNSAFE(_field, _state, _version, _size) \ >> VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, >> vmstate_info_buffer, _size) >> +#define VMSTATE_HASH_V(_field, _state, _version) { \ >> + .name = (stringify(_field)), \ >> + .version_id = (_version), \ >> + .size = sizeof(qemu_hash), \ >> + .info = &vmstate_info_hash, \ >> + .flags = VMS_SINGLE, \ >> + .offset = vmstate_offset_value(_state, _field, qemu_hash), \ >> +} >> + >> #define VMSTATE_UNUSED_V(_v, _size) \ >> VMSTATE_UNUSED_BUFFER(NULL, _v, _size) >> diff --git a/include/qemu-common.h b/include/qemu-common.h >> index 3f3fd60..ee973e7 100644 >> --- a/include/qemu-common.h >> +++ b/include/qemu-common.h >> @@ -462,4 +462,17 @@ int parse_debug_env(const char *name, int max, int >> initial); >> const char *qemu_ether_ntoa(const MACAddr *mac); >> +typedef struct qemu_hash { >> + GHashTable *hash; >> + int key_size; >> + int value_size; >> +} qemu_hash; >> + >> +static inline void qemu_hash_init(qemu_hash *h, int key_size, int >> value_size) >> +{ >> + h->key_size = key_size; >> + h->value_size = value_size; >> + h->hash = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, >> g_free); >> +} >> + >> #endif >> diff --git a/vmstate.c b/vmstate.c >> index b5882fa..2148e73 100644 >> --- a/vmstate.c >> +++ b/vmstate.c >> @@ -667,3 +667,57 @@ const VMStateInfo vmstate_info_bitmap = { >> .get = get_bitmap, >> .put = put_bitmap, >> }; >> + >> +/* Save restore for qemu_hash which is a wrapper over GHashTable */ >> +static int get_hash(QEMUFile *f, void *pv, size_t size) >> +{ >> + qemu_hash *h = pv; >> + uint32_t num = g_hash_table_size(h->hash); >> + gpointer key, value; >> + >> + num = qemu_get_be32(f); >> + >> + for ( ; num; --num) { >> + int i; >> + >> + key = g_malloc0(h->key_size); >> + for (i = 0; i < h->key_size; ++i) { >> + ((uint8_t *)key)[i] = qemu_get_byte(f); >> + } >> + value = g_malloc0(h->value_size); >> + for (i = 0; i < h->value_size; ++i) { >> + ((uint8_t *)value)[i] = qemu_get_byte(f); >> + } >> + g_hash_table_insert(h->hash, key, value); >> + } >> + >> + return 0; >> +} >> + >> +static void put_hash(QEMUFile *f, void *pv, size_t size) >> +{ >> + qemu_hash *h = pv; >> + uint32_t num = g_hash_table_size(h->hash); >> + GHashTableIter iter; >> + gpointer key, value; >> + >> + qemu_put_be32(f, num); >> + >> + g_hash_table_iter_init(&iter, h->hash); >> + while (g_hash_table_iter_next (&iter, &key, &value)) { >> + int i; >> + >> + for (i = 0; i < h->key_size; ++i) { >> + qemu_put_byte(f, ((uint8_t *)key)[i]); >> + } >> + for (i = 0; i < h->value_size; ++i) { >> + qemu_put_byte(f, ((uint8_t *)value)[i]); > > I think the only way to do this safely would be to do a recursive > introspective walk through the hash table's key and value properties. Every > key and every property can be an object again, right? > > We would basically impose a limit onto ourselves that every member of the > hash table would have to be a GObject again.
This is a bit too much for the task I am trying to solve :) @key here is uin32_t and there is no point in making it an object... -- Alexey