@ -926,6 +926,28 @@ static const VMStateDescription vmstate_domain = {
}
} ;
/* test QLIST Migration */
typedef struct TestQListElement {
uint32_t id ;
QLIST_ENTRY ( TestQListElement ) next ;
} TestQListElement ;
typedef struct TestQListContainer {
uint32_t id ;
QLIST_HEAD ( , TestQListElement ) list ;
} TestQListContainer ;
static const VMStateDescription vmstate_qlist_element = {
. name = " test/queue list " ,
. version_id = 1 ,
. minimum_version_id = 1 ,
. fields = ( VMStateField [ ] ) {
VMSTATE_UINT32 ( id , TestQListElement ) ,
VMSTATE_END_OF_LIST ( )
}
} ;
static const VMStateDescription vmstate_iommu = {
. name = " iommu " ,
. version_id = 1 ,
@ -939,6 +961,18 @@ static const VMStateDescription vmstate_iommu = {
}
} ;
static const VMStateDescription vmstate_container = {
. name = " test/container/qlist " ,
. version_id = 1 ,
. minimum_version_id = 1 ,
. fields = ( VMStateField [ ] ) {
VMSTATE_UINT32 ( id , TestQListContainer ) ,
VMSTATE_QLIST_V ( list , TestQListContainer , 1 , vmstate_qlist_element ,
TestQListElement , next ) ,
VMSTATE_END_OF_LIST ( )
}
} ;
uint8_t first_domain_dump [ ] = {
/* id */
0x00 , 0x0 , 0x0 , 0x6 ,
@ -1229,6 +1263,140 @@ static void test_gtree_load_iommu(void)
qemu_fclose ( fload ) ;
}
static uint8_t qlist_dump [ ] = {
0x00 , 0x00 , 0x00 , 0x01 , /* container id */
0x1 , /* start of a */
0x00 , 0x00 , 0x00 , 0x0a ,
0x1 , /* start of b */
0x00 , 0x00 , 0x0b , 0x00 ,
0x1 , /* start of c */
0x00 , 0x0c , 0x00 , 0x00 ,
0x1 , /* start of d */
0x0d , 0x00 , 0x00 , 0x00 ,
0x0 , /* end of list */
QEMU_VM_EOF , /* just to ensure we won't get EOF reported prematurely */
} ;
static TestQListContainer * alloc_container ( void )
{
TestQListElement * a = g_malloc ( sizeof ( TestQListElement ) ) ;
TestQListElement * b = g_malloc ( sizeof ( TestQListElement ) ) ;
TestQListElement * c = g_malloc ( sizeof ( TestQListElement ) ) ;
TestQListElement * d = g_malloc ( sizeof ( TestQListElement ) ) ;
TestQListContainer * container = g_malloc ( sizeof ( TestQListContainer ) ) ;
a - > id = 0x0a ;
b - > id = 0x0b00 ;
c - > id = 0xc0000 ;
d - > id = 0xd000000 ;
container - > id = 1 ;
QLIST_INIT ( & container - > list ) ;
QLIST_INSERT_HEAD ( & container - > list , d , next ) ;
QLIST_INSERT_HEAD ( & container - > list , c , next ) ;
QLIST_INSERT_HEAD ( & container - > list , b , next ) ;
QLIST_INSERT_HEAD ( & container - > list , a , next ) ;
return container ;
}
static void free_container ( TestQListContainer * container )
{
TestQListElement * iter , * tmp ;
QLIST_FOREACH_SAFE ( iter , & container - > list , next , tmp ) {
QLIST_REMOVE ( iter , next ) ;
g_free ( iter ) ;
}
g_free ( container ) ;
}
static void compare_containers ( TestQListContainer * c1 , TestQListContainer * c2 )
{
TestQListElement * first_item_c1 , * first_item_c2 ;
while ( ! QLIST_EMPTY ( & c1 - > list ) ) {
first_item_c1 = QLIST_FIRST ( & c1 - > list ) ;
first_item_c2 = QLIST_FIRST ( & c2 - > list ) ;
assert ( first_item_c2 ) ;
assert ( first_item_c1 - > id = = first_item_c2 - > id ) ;
QLIST_REMOVE ( first_item_c1 , next ) ;
QLIST_REMOVE ( first_item_c2 , next ) ;
g_free ( first_item_c1 ) ;
g_free ( first_item_c2 ) ;
}
assert ( QLIST_EMPTY ( & c2 - > list ) ) ;
}
/*
* Check the prev & next fields are correct by doing list
* manipulations on the container . We will do that for both
* the source and the destination containers
*/
static void manipulate_container ( TestQListContainer * c )
{
TestQListElement * prev = NULL , * iter = QLIST_FIRST ( & c - > list ) ;
TestQListElement * elem ;
elem = g_malloc ( sizeof ( TestQListElement ) ) ;
elem - > id = 0x12 ;
QLIST_INSERT_AFTER ( iter , elem , next ) ;
elem = g_malloc ( sizeof ( TestQListElement ) ) ;
elem - > id = 0x13 ;
QLIST_INSERT_HEAD ( & c - > list , elem , next ) ;
while ( iter ) {
prev = iter ;
iter = QLIST_NEXT ( iter , next ) ;
}
elem = g_malloc ( sizeof ( TestQListElement ) ) ;
elem - > id = 0x14 ;
QLIST_INSERT_BEFORE ( prev , elem , next ) ;
elem = g_malloc ( sizeof ( TestQListElement ) ) ;
elem - > id = 0x15 ;
QLIST_INSERT_AFTER ( prev , elem , next ) ;
QLIST_REMOVE ( prev , next ) ;
g_free ( prev ) ;
}
static void test_save_qlist ( void )
{
TestQListContainer * container = alloc_container ( ) ;
save_vmstate ( & vmstate_container , container ) ;
compare_vmstate ( qlist_dump , sizeof ( qlist_dump ) ) ;
free_container ( container ) ;
}
static void test_load_qlist ( void )
{
QEMUFile * fsave , * fload ;
TestQListContainer * orig_container = alloc_container ( ) ;
TestQListContainer * dest_container = g_malloc0 ( sizeof ( TestQListContainer ) ) ;
char eof ;
QLIST_INIT ( & dest_container - > list ) ;
fsave = open_test_file ( true ) ;
qemu_put_buffer ( fsave , qlist_dump , sizeof ( qlist_dump ) ) ;
g_assert ( ! qemu_file_get_error ( fsave ) ) ;
qemu_fclose ( fsave ) ;
fload = open_test_file ( false ) ;
vmstate_load_state ( fload , & vmstate_container , dest_container , 1 ) ;
eof = qemu_get_byte ( fload ) ;
g_assert ( ! qemu_file_get_error ( fload ) ) ;
g_assert_cmpint ( eof , = = , QEMU_VM_EOF ) ;
manipulate_container ( orig_container ) ;
manipulate_container ( dest_container ) ;
compare_containers ( orig_container , dest_container ) ;
free_container ( orig_container ) ;
free_container ( dest_container ) ;
}
typedef struct TmpTestStruct {
TestStruct * parent ;
int64_t diff ;
@ -1353,6 +1521,8 @@ int main(int argc, char **argv)
g_test_add_func ( " /vmstate/gtree/load/loaddomain " , test_gtree_load_domain ) ;
g_test_add_func ( " /vmstate/gtree/save/saveiommu " , test_gtree_save_iommu ) ;
g_test_add_func ( " /vmstate/gtree/load/loadiommu " , test_gtree_load_iommu ) ;
g_test_add_func ( " /vmstate/qlist/save/saveqlist " , test_save_qlist ) ;
g_test_add_func ( " /vmstate/qlist/load/loadqlist " , test_load_qlist ) ;
g_test_add_func ( " /vmstate/tmp_struct " , test_tmp_struct ) ;
g_test_run ( ) ;