[libvirt] [PATCHv4 0/4] vbox: Rewrite vbox driver.

Use vboxUniformedAPI to rewrite vbox driver. vboxInitialize and vboxDomainSave are rewrited in this way. Taowei (4): add definitions for vboxUniformedAPI implement vboxUniformedAPI in vbox_tmpl.c use vboxUniformedAPI to generate common code install vboxUniformedAPI po/POTFILES.in | 1 + src/Makefile.am | 4 +- src/vbox/vbox_common.c | 150 +++++++++++++++ src/vbox/vbox_common.h | 151 +++++++++++++++ src/vbox/vbox_driver.c | 35 +++- src/vbox/vbox_tmpl.c | 419 ++++++++++++++++++++++++----------------- src/vbox/vbox_uniformed_api.h | 168 +++++++++++++++++ 7 files changed, 749 insertions(+), 179 deletions(-) create mode 100644 src/vbox/vbox_common.c create mode 100644 src/vbox/vbox_common.h create mode 100644 src/vbox/vbox_uniformed_api.h -- 1.7.9.5

Introducing a new file vbox_uniformed_api to define the uniformed API and some other common types used by the API. All symbols defined in this file are treated the same in vbox_common.c as well as vbox_tmpl.c. Other specified defines will be put in vbox_CAPI_v*.h , vbox_tmpl.c(version specified) and vbox_common.h (only used for common code). --- src/Makefile.am | 3 +- src/vbox/vbox_uniformed_api.h | 168 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 src/vbox/vbox_uniformed_api.h diff --git a/src/Makefile.am b/src/Makefile.am index 2b9ac61..c1e3f45 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -673,7 +673,8 @@ VBOX_DRIVER_SOURCES = \ vbox/vbox_V4_2.c vbox/vbox_CAPI_v4_2.h \ vbox/vbox_V4_2_20.c vbox/vbox_CAPI_v4_2_20.h \ vbox/vbox_V4_3.c vbox/vbox_CAPI_v4_3.h \ - vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h + vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h \ + vbox/vbox_uniformed_api.h VBOX_DRIVER_EXTRA_DIST = \ vbox/vbox_tmpl.c vbox/README \ diff --git a/src/vbox/vbox_uniformed_api.h b/src/vbox/vbox_uniformed_api.h new file mode 100644 index 0000000..dfd9497 --- /dev/null +++ b/src/vbox/vbox_uniformed_api.h @@ -0,0 +1,168 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@gmail.com) + * + * 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.1 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, see + * <http://www.gnu.org/licenses/>. + */ + +#ifndef VBOX_UNIFORMED_API_H +# define VBOX_UNIFORMED_API_H + +# include "internal.h" + +/* This file may be used in three place. That is vbox_tmpl.c, + * vbox_common.c and vbox_driver.c. The vboxUniformedAPI and some + * types used for vboxUniformedAPI is defined here. + * + * The vbox_tmpl.c is the only place where the driver knows the inside + * architecture of those vbox structs(vboxObj, vboxSession, + * pFuncs, vboxCallback and vboxQueue). The file should be included + * after the currect vbox_CAPI_v*.h, then we can use the vbox structs + * in vboxGlobalData. The vbox_tmpl.c should implement functions + * defined in vboxUniformedAPI. + * + * In vbox_driver.c, it is used to define the struct vboxUniformedAPI. + * The vbox_driver.c collects vboxUniformedAPI for all versions. + * Then vboxRegister calls the vboxRegisterUniformedAPI to register. + * Note: In vbox_driver.c, the vbox structs in vboxGlobalData is + * defined by vbox_CAPI_v2.2.h. + * + * The vbox_common.c, it is used to generate common codes for all vbox + * versions. Bacause the same member varible's offset in a vbox struct + * may change between different vbox versions. The vbox_common.c + * shouldn't directly use struct's member varibles defined in + * vbox_CAPI_v*.h. To make things safety, we include the + * vbox_common.h in vbox_common.c. In this case, we treat structs + * defined by vbox as a void*. The common codes don't concern about + * the inside of this structs(actually, we can't, in the common level). + * With the help of vboxUniformed API, we call VirtualBox's API and + * implement the vbox driver in a high level. + * + * In conclusion: + * * In vbox_tmpl.c, this file is included after vbox_CAPI_v*.h + * * In vbox_driver.c, this file is included after vbox_glue.h + * * In vbox_common.c, this file is included after vbox_common.h + * + */ + +/* Extracted define from vbox_tmpl.c */ + +# ifdef WIN32 +struct _vboxIID_v2_x_WIN32 { + /* IID is represented by a GUID value. */ + GUID value; +}; +# endif /* !WIN32 */ + +struct _vboxIID_v2_x { + /* IID is represented by a pointer to a nsID. */ + nsID *value; + + /* backing is used in cases where we need to create or copy an IID. + * We cannot allocate memory that can be freed by ComUnallocMem. + * Therefore, we use this stack allocated nsID instead. */ + nsID backing; +}; + +struct _vboxIID_v3_x { + /* IID is represented by a UTF-16 encoded UUID in string form. */ + PRUnichar *value; + + /* owner indicates if we own the value and need to free it. */ + bool owner; +}; + +typedef union { +# ifdef WIN32 + struct _vboxIID_v2_x_WIN32 vboxIID_v2_x_WIN32; +# endif /* !WIN32 */ + struct _vboxIID_v2_x vboxIID_v2_x; + struct _vboxIID_v3_x vboxIID_v3_x; +} vboxIIDUnion; + +typedef union { + nsresult uResultCode; + PRInt32 resultCode; +} resultCodeUnion; + +typedef struct { + virMutex lock; + unsigned long version; + + virCapsPtr caps; + virDomainXMLOptionPtr xmlopt; + + IVirtualBox *vboxObj; + ISession *vboxSession; + + /** Our version specific API table pointer. */ + PCVBOXXPCOM pFuncs; + + /* The next is used when VBOX_API_VERSION > 2002000 */ + /* Async event handling */ + virObjectEventStatePtr domainEvents; + int fdWatch; +# if defined(VBOX_API_VERSION) && VBOX_API_VERSION > 2002000 && VBOX_API_VERSION <= 3002000 + /* IVirtualBoxCallback is used in VirtualBox 3.x only */ + IVirtualBoxCallback *vboxCallback; +# else /* VBOX_API_VERSION == 2002000 || VBOX_API_VERSION > 3002000 or VBOX_API_VERSION undefined */ + void *vboxCallback; +# endif /* VBOX_API_VERSION == 2002000 || VBOX_API_VERSION > 3002000 or VBOX_API_VERSION undefined */ + + +# if defined(VBOX_API_VERSION) && VBOX_API_VERSION > 2002000 + nsIEventQueue *vboxQueue; +# else /* VBOX_API_VERSION == 2002000 or undefined */ + void *vboxQueue; +# endif /* VBOX_API_VERSION == 2002000 or undefined */ + int volatile vboxCallBackRefCount; + + /* pointer back to the connection */ + virConnectPtr conn; + +} vboxGlobalData; + +/* vboxUniformedAPI gives vbox_common.c a uniformed layer to see + * vbox API. + */ +typedef struct { + /* vbox API version */ + uint32_t APIVersion; + uint32_t XPCOMCVersion; + /* vbox APIs */ + int (*pfnInitialize)(vboxGlobalData *data); + int (*initializeFWatch)(vboxGlobalData *data); + void (*initializeVboxIID)(vboxIIDUnion *iidu); + void (*vboxIIDUnalloc)(vboxGlobalData *data, vboxIIDUnion *iidu); + void (*vboxIIDFromUUID)(vboxGlobalData *data, vboxIIDUnion *iidu, const unsigned char *uuid); + void (*DEBUGIID)(const char *msg, vboxIIDUnion *iidu); + nsresult (*objectGetMachine)(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine **machine); + nsresult (*sessionOpenExisting)(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine *machine); + nsresult (*sessionGetConsole)(ISession *session, IConsole **console); + nsresult (*sessionClose)(ISession *session); + nsresult (*consoleSaveState)(IConsole *console, IProgress **progress); + nsresult (*progressWaitForCompletion)(IProgress *progress, PRInt32 timeout); + nsresult (*progressGetResultCode)(IProgress *progress, resultCodeUnion *resultCode); + nsresult (*nsisupportsRelease)(void *Ihandle); + /* vbox API features */ + bool fWatchNeedInitialize; + bool getMachineForSession; +} vboxUniformedAPI; + +int vboxInitialize(vboxGlobalData *data); +int vboxDomainSave(virDomainPtr dom, const char *path); + +void vboxRegisterUniformedAPI(vboxUniformedAPI *vboxAPI); + +#endif /* VBOX_UNIFORMED_API_H */ -- 1.7.9.5

On 26.06.2014 15:51, Taowei wrote:
Introducing a new file vbox_uniformed_api to define the uniformed API and some other common types used by the API. All symbols defined in this file are treated the same in vbox_common.c as well as vbox_tmpl.c. Other specified defines will be put in vbox_CAPI_v*.h , vbox_tmpl.c(version specified) and vbox_common.h (only used for common code).
--- src/Makefile.am | 3 +- src/vbox/vbox_uniformed_api.h | 168 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 src/vbox/vbox_uniformed_api.h
diff --git a/src/Makefile.am b/src/Makefile.am index 2b9ac61..c1e3f45 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -673,7 +673,8 @@ VBOX_DRIVER_SOURCES = \ vbox/vbox_V4_2.c vbox/vbox_CAPI_v4_2.h \ vbox/vbox_V4_2_20.c vbox/vbox_CAPI_v4_2_20.h \ vbox/vbox_V4_3.c vbox/vbox_CAPI_v4_3.h \ - vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h + vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h \ + vbox/vbox_uniformed_api.h
VBOX_DRIVER_EXTRA_DIST = \ vbox/vbox_tmpl.c vbox/README \ diff --git a/src/vbox/vbox_uniformed_api.h b/src/vbox/vbox_uniformed_api.h new file mode 100644 index 0000000..dfd9497 --- /dev/null +++ b/src/vbox/vbox_uniformed_api.h @@ -0,0 +1,168 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@gmail.com) + * + * 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.1 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, see + * <http://www.gnu.org/licenses/>. + */ + +#ifndef VBOX_UNIFORMED_API_H +# define VBOX_UNIFORMED_API_H + +# include "internal.h" + +/* This file may be used in three place. That is vbox_tmpl.c, + * vbox_common.c and vbox_driver.c. The vboxUniformedAPI and some + * types used for vboxUniformedAPI is defined here. + * + * The vbox_tmpl.c is the only place where the driver knows the inside + * architecture of those vbox structs(vboxObj, vboxSession, + * pFuncs, vboxCallback and vboxQueue). The file should be included + * after the currect vbox_CAPI_v*.h, then we can use the vbox structs + * in vboxGlobalData. The vbox_tmpl.c should implement functions + * defined in vboxUniformedAPI. + * + * In vbox_driver.c, it is used to define the struct vboxUniformedAPI. + * The vbox_driver.c collects vboxUniformedAPI for all versions. + * Then vboxRegister calls the vboxRegisterUniformedAPI to register. + * Note: In vbox_driver.c, the vbox structs in vboxGlobalData is + * defined by vbox_CAPI_v2.2.h. + * + * The vbox_common.c, it is used to generate common codes for all vbox + * versions. Bacause the same member varible's offset in a vbox struct + * may change between different vbox versions. The vbox_common.c + * shouldn't directly use struct's member varibles defined in + * vbox_CAPI_v*.h. To make things safety, we include the + * vbox_common.h in vbox_common.c. In this case, we treat structs + * defined by vbox as a void*. The common codes don't concern about + * the inside of this structs(actually, we can't, in the common level). + * With the help of vboxUniformed API, we call VirtualBox's API and + * implement the vbox driver in a high level. + * + * In conclusion: + * * In vbox_tmpl.c, this file is included after vbox_CAPI_v*.h + * * In vbox_driver.c, this file is included after vbox_glue.h + * * In vbox_common.c, this file is included after vbox_common.h + * + */ + +/* Extracted define from vbox_tmpl.c */ + +# ifdef WIN32 +struct _vboxIID_v2_x_WIN32 { + /* IID is represented by a GUID value. */ + GUID value; +}; +# endif /* !WIN32 */ + +struct _vboxIID_v2_x { + /* IID is represented by a pointer to a nsID. */ + nsID *value; + + /* backing is used in cases where we need to create or copy an IID. + * We cannot allocate memory that can be freed by ComUnallocMem. + * Therefore, we use this stack allocated nsID instead. */ + nsID backing; +}; + +struct _vboxIID_v3_x { + /* IID is represented by a UTF-16 encoded UUID in string form. */ + PRUnichar *value; + + /* owner indicates if we own the value and need to free it. */ + bool owner; +}; + +typedef union { +# ifdef WIN32 + struct _vboxIID_v2_x_WIN32 vboxIID_v2_x_WIN32; +# endif /* !WIN32 */ + struct _vboxIID_v2_x vboxIID_v2_x; + struct _vboxIID_v3_x vboxIID_v3_x; +} vboxIIDUnion; + +typedef union { + nsresult uResultCode; + PRInt32 resultCode; +} resultCodeUnion; + +typedef struct { + virMutex lock; + unsigned long version; + + virCapsPtr caps; + virDomainXMLOptionPtr xmlopt; + + IVirtualBox *vboxObj; + ISession *vboxSession; + + /** Our version specific API table pointer. */ + PCVBOXXPCOM pFuncs; + + /* The next is used when VBOX_API_VERSION > 2002000 */ + /* Async event handling */ + virObjectEventStatePtr domainEvents; + int fdWatch; +# if defined(VBOX_API_VERSION) && VBOX_API_VERSION > 2002000 && VBOX_API_VERSION <= 3002000 + /* IVirtualBoxCallback is used in VirtualBox 3.x only */ + IVirtualBoxCallback *vboxCallback; +# else /* VBOX_API_VERSION == 2002000 || VBOX_API_VERSION > 3002000 or VBOX_API_VERSION undefined */ + void *vboxCallback; +# endif /* VBOX_API_VERSION == 2002000 || VBOX_API_VERSION > 3002000 or VBOX_API_VERSION undefined */ + + +# if defined(VBOX_API_VERSION) && VBOX_API_VERSION > 2002000 + nsIEventQueue *vboxQueue; +# else /* VBOX_API_VERSION == 2002000 or undefined */ + void *vboxQueue; +# endif /* VBOX_API_VERSION == 2002000 or undefined */ + int volatile vboxCallBackRefCount; + + /* pointer back to the connection */ + virConnectPtr conn; + +} vboxGlobalData; + +/* vboxUniformedAPI gives vbox_common.c a uniformed layer to see + * vbox API. + */ +typedef struct { + /* vbox API version */ + uint32_t APIVersion; + uint32_t XPCOMCVersion; + /* vbox APIs */ + int (*pfnInitialize)(vboxGlobalData *data); + int (*initializeFWatch)(vboxGlobalData *data); + void (*initializeVboxIID)(vboxIIDUnion *iidu); + void (*vboxIIDUnalloc)(vboxGlobalData *data, vboxIIDUnion *iidu); + void (*vboxIIDFromUUID)(vboxGlobalData *data, vboxIIDUnion *iidu, const unsigned char *uuid); + void (*DEBUGIID)(const char *msg, vboxIIDUnion *iidu); + nsresult (*objectGetMachine)(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine **machine); + nsresult (*sessionOpenExisting)(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine *machine); + nsresult (*sessionGetConsole)(ISession *session, IConsole **console); + nsresult (*sessionClose)(ISession *session); + nsresult (*consoleSaveState)(IConsole *console, IProgress **progress); + nsresult (*progressWaitForCompletion)(IProgress *progress, PRInt32 timeout); + nsresult (*progressGetResultCode)(IProgress *progress, resultCodeUnion *resultCode); + nsresult (*nsisupportsRelease)(void *Ihandle); + /* vbox API features */ + bool fWatchNeedInitialize; + bool getMachineForSession; +} vboxUniformedAPI; + +int vboxInitialize(vboxGlobalData *data); +int vboxDomainSave(virDomainPtr dom, const char *path);
The vboxDomainSave() should be introduced in the 3/4.
+ +void vboxRegisterUniformedAPI(vboxUniformedAPI *vboxAPI); + +#endif /* VBOX_UNIFORMED_API_H */

Implement vboxUniformedAPI for each vbox API version. Some common code and definitions are moved to vbox_common.c and vbox_uniformed_api.h. --- src/vbox/vbox_tmpl.c | 419 +++++++++++++++++++++++++++++--------------------- 1 file changed, 245 insertions(+), 174 deletions(-) diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 4ba9ad7..7d01308 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -89,7 +89,7 @@ /* Include this *last* or we'll get the wrong vbox_CAPI_*.h. */ #include "vbox_glue.h" - +#include "vbox_uniformed_api.h" #define VIR_FROM_THIS VIR_FROM_VBOX @@ -189,7 +189,7 @@ if (strUtf16) {\ #define DEBUGUUID(msg, iid) \ {\ - VIR_DEBUG(msg ": {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",\ + VIR_DEBUG("%s: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", msg,\ (unsigned)(iid)->m0,\ (unsigned)(iid)->m1,\ (unsigned)(iid)->m2,\ @@ -203,42 +203,6 @@ if (strUtf16) {\ (unsigned)(iid)->m3[7]);\ }\ -typedef struct { - virMutex lock; - unsigned long version; - - virCapsPtr caps; - virDomainXMLOptionPtr xmlopt; - - IVirtualBox *vboxObj; - ISession *vboxSession; - - /** Our version specific API table pointer. */ - PCVBOXXPCOM pFuncs; - -#if VBOX_API_VERSION == 2002000 - -} vboxGlobalData; - -#else /* !(VBOX_API_VERSION == 2002000) */ - - /* Async event handling */ - virObjectEventStatePtr domainEvents; - int fdWatch; - -# if VBOX_API_VERSION <= 3002000 - /* IVirtualBoxCallback is used in VirtualBox 3.x only */ - IVirtualBoxCallback *vboxCallback; -# endif /* VBOX_API_VERSION <= 3002000 */ - - nsIEventQueue *vboxQueue; - int volatile vboxCallBackRefCount; - - /* pointer back to the connection */ - virConnectPtr conn; - -} vboxGlobalData; - /* g_pVBoxGlobalData has to be global variable, * there is no other way to make the callbacks * work other then having g_pVBoxGlobalData as @@ -249,6 +213,8 @@ typedef struct { * them that way */ +#if VBOX_API_VERSION > 2002000 + static vboxGlobalData *g_pVBoxGlobalData = NULL; #endif /* !(VBOX_API_VERSION == 2002000) */ @@ -386,13 +352,10 @@ static void nsIDFromChar(nsID *iid, const unsigned char *uuid) typedef struct _vboxIID_v2_x_WIN32 vboxIID; typedef struct _vboxIID_v2_x_WIN32 vboxIID_v2_x_WIN32; -struct _vboxIID_v2_x_WIN32 { - /* IID is represented by a GUID value. */ - GUID value; -}; - # define VBOX_IID_INITIALIZER { { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } } +# define IIDU(name) (iidu->vboxIID_v2_x_WIN32.name) + static void vboxIIDUnalloc_v2_x_WIN32(vboxGlobalData *data ATTRIBUTE_UNUSED, vboxIID_v2_x_WIN32 *iid ATTRIBUTE_UNUSED) @@ -401,6 +364,13 @@ vboxIIDUnalloc_v2_x_WIN32(vboxGlobalData *data ATTRIBUTE_UNUSED, } static void +_vboxIIDUnalloc_v2_x_WIN32(vboxGlobalData *data ATTRIBUTE_UNUSED, + vboxIIDUnion *iid ATTRIBUTE_UNUSED) +{ + /* Nothing to free */ +} + +static void vboxIIDToUUID_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid, unsigned char *uuid) { nsIDtoChar(uuid, (nsID *)&iid->value); @@ -415,6 +385,13 @@ vboxIIDFromUUID_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid, nsIDFromChar((nsID *)&iid->value, uuid); } +static void +_vboxIIDFromUUID_v2_x_WIN32(vboxGlobalData *data, vboxIIDUnion *iidu, + const unsigned char *uuid) +{ + vboxIIDFromUUID_v2_x_WIN32(data, &iidu->vboxIID_v2_x_WIN32, uuid); +} + static bool vboxIIDIsEqual_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid1, vboxIID_v2_x_WIN32 *iid2) { @@ -432,6 +409,7 @@ vboxIIDFromArrayItem_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid, memcpy(&iid->value, &items[idx], sizeof(GUID)); } + # define vboxIIDUnalloc(iid) vboxIIDUnalloc_v2_x_WIN32(data, iid) # define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v2_x_WIN32(iid, uuid) # define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v2_x_WIN32(data, iid, uuid) @@ -440,23 +418,16 @@ vboxIIDFromArrayItem_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid, vboxIIDFromArrayItem_v2_x_WIN32(data, iid, array, idx) # define DEBUGIID(msg, iid) DEBUGUUID(msg, (nsID *)&(iid)) + # else /* !WIN32 */ typedef struct _vboxIID_v2_x vboxIID; typedef struct _vboxIID_v2_x vboxIID_v2_x; -struct _vboxIID_v2_x { - /* IID is represented by a pointer to a nsID. */ - nsID *value; - - /* backing is used in cases where we need to create or copy an IID. - * We cannot allocate memory that can be freed by ComUnallocMem. - * Therefore, we use this stack allocated nsID instead. */ - nsID backing; -}; - # define VBOX_IID_INITIALIZER { NULL, { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } } +# define IIDU(name) (iidu->vboxIID_v2_x.name) + static void vboxIIDUnalloc_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid) { @@ -472,6 +443,12 @@ vboxIIDUnalloc_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid) } static void +_vboxIIDUnalloc_v2_x(vboxGlobalData *data, vboxIIDUnion *iidu) +{ + vboxIIDUnalloc_v2_x(data, &iidu->vboxIID_v2_x); +} + +static void vboxIIDToUUID_v2_x(vboxIID_v2_x *iid, unsigned char *uuid) { nsIDtoChar(uuid, iid->value); @@ -489,6 +466,13 @@ vboxIIDFromUUID_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid, nsIDFromChar(iid->value, uuid); } +static void +_vboxIIDFromUUID_v2_x(vboxGlobalData *data, vboxIIDUnion *iidu, + const unsigned char *uuid) +{ + vboxIIDFromUUID_v2_x(data, &iidu->vboxIID_v2_x, uuid); +} + static bool vboxIIDIsEqual_v2_x(vboxIID_v2_x *iid1, vboxIID_v2_x *iid2) { @@ -506,6 +490,7 @@ vboxIIDFromArrayItem_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid, memcpy(iid->value, array->items[idx], sizeof(nsID)); } + # define vboxIIDUnalloc(iid) vboxIIDUnalloc_v2_x(data, iid) # define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v2_x(iid, uuid) # define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v2_x(data, iid, uuid) @@ -514,6 +499,7 @@ vboxIIDFromArrayItem_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid, vboxIIDFromArrayItem_v2_x(data, iid, array, idx) # define DEBUGIID(msg, iid) DEBUGUUID(msg, iid) + # endif /* !WIN32 */ #else /* VBOX_API_VERSION != 2002000 */ @@ -521,16 +507,10 @@ vboxIIDFromArrayItem_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid, typedef struct _vboxIID_v3_x vboxIID; typedef struct _vboxIID_v3_x vboxIID_v3_x; -struct _vboxIID_v3_x { - /* IID is represented by a UTF-16 encoded UUID in string form. */ - PRUnichar *value; - - /* owner indicates if we own the value and need to free it. */ - bool owner; -}; - # define VBOX_IID_INITIALIZER { NULL, true } +# define IIDU(name) (iidu->vboxIID_v3_x.name) + static void vboxIIDUnalloc_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid) { @@ -543,6 +523,12 @@ vboxIIDUnalloc_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid) } static void +_vboxIIDUnalloc_v3_x(vboxGlobalData *data, vboxIIDUnion *iidu) +{ + vboxIIDUnalloc_v3_x(data, &iidu->vboxIID_v3_x); +} + +static void vboxIIDToUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid, unsigned char *uuid) { @@ -568,6 +554,13 @@ vboxIIDFromUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid, data->pFuncs->pfnUtf8ToUtf16(utf8, &iid->value); } +static void +_vboxIIDFromUUID_v3_x(vboxGlobalData *data, vboxIIDUnion *iidu, + const unsigned char *uuid) +{ + vboxIIDFromUUID_v3_x(data, &iidu->vboxIID_v3_x, uuid); +} + static bool vboxIIDIsEqual_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid1, vboxIID_v3_x *iid2) @@ -606,6 +599,7 @@ vboxIIDFromArrayItem_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid, vboxIIDFromArrayItem_v3_x(data, iid, array, idx) # define DEBUGIID(msg, strUtf16) DEBUGPRUnichar(msg, strUtf16) + # if VBOX_API_VERSION >= 3001000 /** @@ -826,6 +820,196 @@ static PRUnichar *PRUnicharFromInt(int n) { #endif /* !(VBOX_API_VERSION == 2002000) */ +/* Begin of vboxUniformedAPI */ + +static int _pfnInitialize(vboxGlobalData *data) +{ + data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION); + if (data->pFuncs == NULL) + return -1; +#if VBOX_XPCOMC_VERSION == 0x00010000U + data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession); +#else /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */ + data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj, ISESSION_IID_STR, &data->vboxSession); +#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */ + return 0; +} + +static int +_initializeFWatch(vboxGlobalData *data ATTRIBUTE_UNUSED) +{ +#if (VBOX_XPCOMC_VERSION == 0x00010000U) || (VBOX_API_VERSION == 2002000) + /* No event queue functionality in 2.2.* as of now */ + VIR_WARN("There is no fWatch initical in current version"); +#else /* (VBOX_XPCOMC_VERSION != 0x00010000U && VBOX_API_VERSION != 2002000) */ + /* Initialize the fWatch needed for Event Callbacks */ + data->fdWatch = -1; + data->pFuncs->pfnGetEventQueue(&data->vboxQueue); + if (data->vboxQueue == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("nsIEventQueue object is null")); + return -1; + } +#endif /* (VBOX_XPCOMC_VERSION != 0x00010000U && VBOX_API_VERSION != 2002000) */ + return 0; +} + +static nsresult +_sessionGetConsole(ISession *session, IConsole **console) +{ + return session->vtbl->GetConsole(session, console); +} + +static nsresult +_consoleSaveState(IConsole *console, IProgress **progress) +{ + return console->vtbl->SaveState(console, progress); +} + +static nsresult +_progressWaitForCompletion(IProgress *progress, PRInt32 timeout) +{ + return progress->vtbl->WaitForCompletion(progress, timeout); +} + +static nsresult _nsisupportsRelease(void *Ihandle) +{ + /* It is safety to convert a pointer from IVirtual(or structs + * like this) to nsISupports*/ + nsISupports *nsi = (nsISupports *)Ihandle; + return nsi->vtbl->Release(nsi); +} + +#if VBOX_API_VERSION == 2002000 + +static nsresult +_progressGetResultCode(IProgress *progress, resultCodeUnion *resultCode) +{ + return progress->vtbl->GetResultCode(progress, &resultCode->uResultCode); +} + +static void _initializeVboxIID(vboxIIDUnion *iidu) +{ + memset(iidu, 0, sizeof(vboxIIDUnion)); +} + +static void _DEBUGIID(const char *msg, vboxIIDUnion *iidu) +{ +# ifdef WIN32 + DEBUGUUID(msg, (nsID *)&IIDU(value)); +# else /* !WIN32 */ + DEBUGUUID(msg, IIDU(value)); +# endif /* !WIN32 */ +} + +#else /* VBOX_API_VERSION != 2002000 */ + +static nsresult +_progressGetResultCode(IProgress *progress, resultCodeUnion *resultCode) +{ + return progress->vtbl->GetResultCode(progress, &resultCode->resultCode); +} + +static void _initializeVboxIID(vboxIIDUnion *iidu) +{ + memset(iidu, 0, sizeof(vboxIIDUnion)); + IIDU(owner) = true; +} + +static void _DEBUGIID(const char *msg, vboxIIDUnion *iidu) +{ + DEBUGPRUnichar(msg, IIDU(value)); +} + +#endif /* VBOX_API_VERSION != 2002000 */ + +#if VBOX_API_VERSION < 4000000 + +static nsresult +_objectGetMachine(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine **machine) +{ + return data->vboxObj->vtbl->GetMachine(data->vboxObj, IIDU(value), machine); +} + +static nsresult +_sessionOpenExisting(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine *machine ATTRIBUTE_UNUSED) +{ + return data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, IIDU(value)); +} + +static nsresult +_sessionClose(ISession *session) +{ + return session->vtbl->Close(session); +} + +#else /* VBOX_API_VERSION >= 4000000 */ + +static nsresult +_objectGetMachine(vboxGlobalData *data, vboxIIDUnion *iidu, IMachine **machine) +{ + return data->vboxObj->vtbl->FindMachine(data->vboxObj, IIDU(value), machine); +} + +static nsresult +_sessionOpenExisting(vboxGlobalData *data, vboxIIDUnion *iidu ATTRIBUTE_UNUSED, IMachine *machine) +{ + return machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Shared); +} + +static nsresult +_sessionClose(ISession *session) +{ + return session->vtbl->UnlockMachine(session); +} + +#endif /* VBOX_API_VERSION >= 4000000 */ + +vboxUniformedAPI NAME(UniformedAPI) = { + .APIVersion = VBOX_API_VERSION, + .XPCOMCVersion = VBOX_XPCOMC_VERSION, + .pfnInitialize = _pfnInitialize, + .initializeFWatch = _initializeFWatch, + .initializeVboxIID = _initializeVboxIID, + .objectGetMachine = _objectGetMachine, + .sessionOpenExisting = _sessionOpenExisting, + .sessionClose = _sessionClose, + .sessionGetConsole = _sessionGetConsole, + .consoleSaveState = _consoleSaveState, + .progressWaitForCompletion = _progressWaitForCompletion, + .progressGetResultCode = _progressGetResultCode, + .nsisupportsRelease = _nsisupportsRelease, +#if VBOX_API_VERSION == 2002000 +# ifdef WIN32 + .vboxIIDUnalloc = _vboxIIDUnalloc_v2_x_WIN32, + .vboxIIDFromUUID = _vboxIIDFromUUID_v2_x_WIN32, +# else /* !WIN32 */ + .vboxIIDUnalloc = _vboxIIDUnalloc_v2_x, + .vboxIIDFromUUID = _vboxIIDFromUUID_v2_x, +# endif /* !WIN32 */ +#else /* VBOX_API_VERSION != 2002000 */ + .vboxIIDUnalloc = _vboxIIDUnalloc_v3_x, + .vboxIIDFromUUID = _vboxIIDFromUUID_v3_x, +#endif /* VBOX_API_VERSION != 2002000 */ + .DEBUGIID = _DEBUGIID, + +#if (VBOX_XPCOMC_VERSION == 0x00010000U) || (VBOX_API_VERSION == 2002000) + /* No event queue functionality in 2.2.* as of now */ + .fWatchNeedInitialize = 0, +#else /* (VBOX_XPCOMC_VERSION != 0x00010000U && VBOX_API_VERSION != 2002000) */ + .fWatchNeedInitialize = 1, +#endif /* (VBOX_XPCOMC_VERSION != 0x00010000U && VBOX_API_VERSION != 2002000) */ + +#if VBOX_API_VERSION >= 4000000 + /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */ + .getMachineForSession = 1, +#else /* VBOX_API_VERSION < 4000000 */ + .getMachineForSession = 0, +#endif /* VBOX_API_VERSION < 4000000 */ +}; + +/* End of vboxUniformedAPI and Begin of common codes */ + static PRUnichar * vboxSocketFormatAddrUtf16(vboxGlobalData *data, virSocketAddrPtr addr) { @@ -915,58 +1099,6 @@ static virCapsPtr vboxCapsInit(void) return NULL; } -static int -vboxInitialize(vboxGlobalData *data) -{ - data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION); - - if (data->pFuncs == NULL) - goto cleanup; - -#if VBOX_XPCOMC_VERSION == 0x00010000U - data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession); -#else /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */ - data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj, - ISESSION_IID_STR, &data->vboxSession); - -# if VBOX_API_VERSION == 2002000 - - /* No event queue functionality in 2.2.* as of now */ - -# else /* !(VBOX_API_VERSION == 2002000) */ - - /* Initial the fWatch needed for Event Callbacks */ - data->fdWatch = -1; - - data->pFuncs->pfnGetEventQueue(&data->vboxQueue); - - if (data->vboxQueue == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("nsIEventQueue object is null")); - goto cleanup; - } - -# endif /* !(VBOX_API_VERSION == 2002000) */ -#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */ - - if (data->vboxObj == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("IVirtualBox object is null")); - goto cleanup; - } - - if (data->vboxSession == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("ISession object is null")); - goto cleanup; - } - - return 0; - - cleanup: - return -1; -} - static int vboxExtractVersion(vboxGlobalData *data) { int ret = -1; @@ -2093,67 +2225,6 @@ vboxDomainGetState(virDomainPtr dom, return ret; } -static int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED) -{ - VBOX_OBJECT_CHECK(dom->conn, int, -1); - IConsole *console = NULL; - vboxIID iid = VBOX_IID_INITIALIZER; - IMachine *machine = NULL; - nsresult rc; - - /* VirtualBox currently doesn't support saving to a file - * at a location other then the machine folder and thus - * setting path to ATTRIBUTE_UNUSED for now, will change - * this behaviour once get the VirtualBox API in right - * shape to do this - */ - - /* Open a Session for the machine */ - vboxIIDFromUUID(&iid, dom->uuid); -#if VBOX_API_VERSION >= 4000000 - /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */ - rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine); - if (NS_FAILED(rc)) { - virReportError(VIR_ERR_NO_DOMAIN, "%s", - _("no domain with matching uuid")); - return -1; - } -#endif - - rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine); - if (NS_SUCCEEDED(rc)) { - rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console); - if (NS_SUCCEEDED(rc) && console) { - IProgress *progress = NULL; - - console->vtbl->SaveState(console, &progress); - - if (progress) { -#if VBOX_API_VERSION == 2002000 - nsresult resultCode; -#else - PRInt32 resultCode; -#endif - - progress->vtbl->WaitForCompletion(progress, -1); - progress->vtbl->GetResultCode(progress, &resultCode); - if (NS_SUCCEEDED(resultCode)) { - ret = 0; - } - VBOX_RELEASE(progress); - } - VBOX_RELEASE(console); - } - VBOX_SESSION_CLOSE(); - } - - DEBUGIID("UUID of machine being saved:", iid.value); - - VBOX_RELEASE(machine); - vboxIIDUnalloc(&iid); - return ret; -} - static int vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, unsigned int flags) -- 1.7.9.5

In vbox_common.c: vboxInitialize and vboxDomainSave are rewrited with vboxUniformedAPI. In vbox_common.h Some common definitions in vbox_CAPI_v*.h are directly extracted to this file. Some other incompatible defintions are simplified here. So we can write common code with it. --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/vbox/vbox_common.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++ src/vbox/vbox_common.h | 151 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 303 insertions(+) create mode 100644 src/vbox/vbox_common.c create mode 100644 src/vbox/vbox_common.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 31a8381..8c1b712 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -213,6 +213,7 @@ src/util/virxml.c src/vbox/vbox_MSCOMGlue.c src/vbox/vbox_XPCOMCGlue.c src/vbox/vbox_driver.c +src/vbox/vbox_common.c src/vbox/vbox_snapshot_conf.c src/vbox/vbox_tmpl.c src/vmware/vmware_conf.c diff --git a/src/Makefile.am b/src/Makefile.am index c1e3f45..7a935e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -674,6 +674,7 @@ VBOX_DRIVER_SOURCES = \ vbox/vbox_V4_2_20.c vbox/vbox_CAPI_v4_2_20.h \ vbox/vbox_V4_3.c vbox/vbox_CAPI_v4_3.h \ vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h \ + vbox/vbox_common.c vbox/vbox_common.h \ vbox/vbox_uniformed_api.h VBOX_DRIVER_EXTRA_DIST = \ diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c new file mode 100644 index 0000000..27211a0 --- /dev/null +++ b/src/vbox/vbox_common.c @@ -0,0 +1,150 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@gmail.com) + * + * 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.1 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, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <unistd.h> + +#include "internal.h" +#include "datatypes.h" +#include "domain_conf.h" +#include "domain_event.h" +#include "virlog.h" + +#include "vbox_common.h" +#include "vbox_uniformed_api.h" + +/* Common codes for vbox driver. With the definitions in vbox_common.h, + * it treats vbox structs as a void*. Though vboxUniformedAPI + * it call vbox functions. This file is a high level implement about + * the vbox driver. + */ + +#define VIR_FROM_THIS VIR_FROM_VBOX + +VIR_LOG_INIT("vbox.vbox_common"); + +#define RC_SUCCEEDED(rc) NS_SUCCEEDED(rc.resultCode) +#define RC_FAILED(rc) NS_FAILED(rc.resultCode) + +#define VBOX_RELEASE(arg) \ + do { \ + if (arg) { \ + pVBoxAPI->nsisupportsRelease((void *)arg); \ + (arg) = NULL; \ + } \ + } while (0) + +#define VBOX_OBJECT_CHECK(conn, type, value) \ +vboxGlobalData *data = conn->privateData;\ +type ret = value;\ +if (!data->vboxObj) {\ + return ret;\ +} + +static vboxUniformedAPI *pVBoxAPI; + +void vboxRegisterUniformedAPI(vboxUniformedAPI *vboxAPI) +{ + VIR_DEBUG("VirtualBox Uniformed API has been registered"); + pVBoxAPI = vboxAPI; +} + +int vboxInitialize(vboxGlobalData *data) +{ + if (pVBoxAPI->pfnInitialize(data) != 0) + goto cleanup; + + if (pVBoxAPI->fWatchNeedInitialize && pVBoxAPI->initializeFWatch(data) != 0) + goto cleanup; + + if (data->vboxObj == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("IVirtualBox object is null")); + goto cleanup; + } + + if (data->vboxSession == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("ISession object is null")); + goto cleanup; + } + + return 0; + + cleanup: + return -1; +} + +int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED) +{ + VBOX_OBJECT_CHECK(dom->conn, int, -1); + IConsole *console = NULL; + vboxIIDUnion iid; + IMachine *machine = NULL; + nsresult rc; + + pVBoxAPI->initializeVboxIID(&iid); + /* VirtualBox currently doesn't support saving to a file + * at a location other then the machine folder and thus + * setting path to ATTRIBUTE_UNUSED for now, will change + * this behaviour once get the VirtualBox API in right + * shape to do this + */ + + /* Open a Session for the machine */ + pVBoxAPI->vboxIIDFromUUID(data, &iid, dom->uuid); + if (pVBoxAPI->getMachineForSession) { + /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */ + rc = pVBoxAPI->objectGetMachine(data, &iid, &machine); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + return -1; + } + } + + rc = pVBoxAPI->sessionOpenExisting(data, &iid, machine); + if (NS_SUCCEEDED(rc)) { + rc = pVBoxAPI->sessionGetConsole(data->vboxSession, &console); + if (NS_SUCCEEDED(rc) && console) { + IProgress *progress = NULL; + + pVBoxAPI->consoleSaveState(console, &progress); + + if (progress) { + resultCodeUnion resultCode; + + pVBoxAPI->progressWaitForCompletion(progress, -1); + pVBoxAPI->progressGetResultCode(progress, &resultCode); + if (RC_SUCCEEDED(resultCode)) { + ret = 0; + } + VBOX_RELEASE(progress); + } + VBOX_RELEASE(console); + } + pVBoxAPI->sessionClose(data->vboxSession); + } + + pVBoxAPI->DEBUGIID("UUID of machine being saved:", &iid); + + VBOX_RELEASE(machine); + pVBoxAPI->vboxIIDUnalloc(data, &iid); + return ret; +} diff --git a/src/vbox/vbox_common.h b/src/vbox/vbox_common.h new file mode 100644 index 0000000..bf0d106 --- /dev/null +++ b/src/vbox/vbox_common.h @@ -0,0 +1,151 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@gmail.com) + * + * 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.1 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, see + * <http://www.gnu.org/licenses/>. + */ + +#ifndef VBOX_COMMON_H +# define VBOX_COMMON_H + +# ifdef ___VirtualBox_CXPCOM_h +# error this file should not be included after vbox_CAPI_v*.h +# endif + +# include "internal.h" +# include <stddef.h> +# include "wchar.h" + +/* This file extracts some symbols defined in + * vbox_CAPI_v*.h. It tells the vbox_common.c + * how to treat with this symbols. This file + * can't be included with files such as + * vbox_CAPI_v*.h, or it would casue multiple + * definitions. + * + * You can see the more informations in vbox_api.h + */ + +/* Copied definitions from vbox_CAPI_*.h. + * We must MAKE SURE these codes are compatible. */ + +typedef unsigned char PRUint8; +# if (defined(HPUX) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus < 199707L) \ + || (defined(SCO) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus == 1L) +typedef char PRInt8; +# else +typedef signed char PRInt8; +# endif + +# define PR_INT8_MAX 127 +# define PR_INT8_MIN (-128) +# define PR_UINT8_MAX 255U + +typedef unsigned short PRUint16; +typedef short PRInt16; + +# define PR_INT16_MAX 32767 +# define PR_INT16_MIN (-32768) +# define PR_UINT16_MAX 65535U + +typedef unsigned int PRUint32; +typedef int PRInt32; +# define PR_INT32(x) x +# define PR_UINT32(x) x ## U + +# define PR_INT32_MAX PR_INT32(2147483647) +# define PR_INT32_MIN (-PR_INT32_MAX - 1) +# define PR_UINT32_MAX PR_UINT32(4294967295) + +typedef long PRInt64; +typedef unsigned long PRUint64; +typedef int PRIntn; +typedef unsigned int PRUintn; + +typedef double PRFloat64; +typedef size_t PRSize; + +typedef ptrdiff_t PRPtrdiff; + +typedef unsigned long PRUptrdiff; + +typedef PRIntn PRBool; + +# define PR_TRUE 1 +# define PR_FALSE 0 + +typedef PRUint8 PRPackedBool; + +/* +** Status code used by some routines that have a single point of failure or +** special status return. +*/ +typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; + +# ifndef __PRUNICHAR__ +# define __PRUNICHAR__ +# if defined(WIN32) || defined(XP_MAC) +typedef wchar_t PRUnichar; +# else +typedef PRUint16 PRUnichar; +# endif +# endif + +typedef long PRWord; +typedef unsigned long PRUword; + +# define nsnull 0 +typedef PRUint32 nsresult; + +# if defined(__GNUC__) && (__GNUC__ > 2) +# define NS_LIKELY(x) (__builtin_expect((x), 1)) +# define NS_UNLIKELY(x) (__builtin_expect((x), 0)) +# else +# define NS_LIKELY(x) (x) +# define NS_UNLIKELY(x) (x) +# endif + +# define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000)) +# define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000))) + +/** + * An "interface id" which can be used to uniquely identify a given + * interface. + * A "unique identifier". This is modeled after OSF DCE UUIDs. + */ + +struct nsID { + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; +}; + +typedef struct nsID nsID; +typedef nsID nsIID; + +/* Simplied definitions in vbox_CAPI_*.h */ + +typedef void const *PCVBOXXPCOM; +typedef void IVirtualBox; +typedef void ISession; +typedef void IVirtualBoxCallback; +typedef void nsIEventQueue; +typedef void IConsole; +typedef void IMachine; +typedef void IProgress; + +#endif /* VBOX_COMMON_H */ -- 1.7.9.5

On 26.06.2014 15:51, Taowei wrote:
In vbox_common.c: vboxInitialize and vboxDomainSave are rewrited with vboxUniformedAPI.
In vbox_common.h Some common definitions in vbox_CAPI_v*.h are directly extracted to this file. Some other incompatible defintions are simplified here. So we can write common code with it.
--- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/vbox/vbox_common.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++ src/vbox/vbox_common.h | 151 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 303 insertions(+) create mode 100644 src/vbox/vbox_common.c create mode 100644 src/vbox/vbox_common.h
diff --git a/po/POTFILES.in b/po/POTFILES.in index 31a8381..8c1b712 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -213,6 +213,7 @@ src/util/virxml.c src/vbox/vbox_MSCOMGlue.c src/vbox/vbox_XPCOMCGlue.c src/vbox/vbox_driver.c +src/vbox/vbox_common.c src/vbox/vbox_snapshot_conf.c src/vbox/vbox_tmpl.c src/vmware/vmware_conf.c diff --git a/src/Makefile.am b/src/Makefile.am index c1e3f45..7a935e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -674,6 +674,7 @@ VBOX_DRIVER_SOURCES = \ vbox/vbox_V4_2_20.c vbox/vbox_CAPI_v4_2_20.h \ vbox/vbox_V4_3.c vbox/vbox_CAPI_v4_3.h \ vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h \ + vbox/vbox_common.c vbox/vbox_common.h \ vbox/vbox_uniformed_api.h
VBOX_DRIVER_EXTRA_DIST = \ diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c new file mode 100644 index 0000000..27211a0 --- /dev/null +++ b/src/vbox/vbox_common.c @@ -0,0 +1,150 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@gmail.com) + * + * 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.1 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, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <unistd.h> + +#include "internal.h" +#include "datatypes.h" +#include "domain_conf.h" +#include "domain_event.h" +#include "virlog.h" + +#include "vbox_common.h" +#include "vbox_uniformed_api.h" + +/* Common codes for vbox driver. With the definitions in vbox_common.h, + * it treats vbox structs as a void*. Though vboxUniformedAPI + * it call vbox functions. This file is a high level implement about + * the vbox driver. + */ + +#define VIR_FROM_THIS VIR_FROM_VBOX + +VIR_LOG_INIT("vbox.vbox_common"); + +#define RC_SUCCEEDED(rc) NS_SUCCEEDED(rc.resultCode) +#define RC_FAILED(rc) NS_FAILED(rc.resultCode) + +#define VBOX_RELEASE(arg) \ + do { \ + if (arg) { \ + pVBoxAPI->nsisupportsRelease((void *)arg); \ + (arg) = NULL; \ + } \ + } while (0) + +#define VBOX_OBJECT_CHECK(conn, type, value) \ +vboxGlobalData *data = conn->privateData;\ +type ret = value;\ +if (!data->vboxObj) {\ + return ret;\ +} + +static vboxUniformedAPI *pVBoxAPI; + +void vboxRegisterUniformedAPI(vboxUniformedAPI *vboxAPI) +{ + VIR_DEBUG("VirtualBox Uniformed API has been registered"); + pVBoxAPI = vboxAPI; +} + +int vboxInitialize(vboxGlobalData *data) +{ + if (pVBoxAPI->pfnInitialize(data) != 0) + goto cleanup; + + if (pVBoxAPI->fWatchNeedInitialize && pVBoxAPI->initializeFWatch(data) != 0) + goto cleanup; + + if (data->vboxObj == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("IVirtualBox object is null")); + goto cleanup; + } + + if (data->vboxSession == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("ISession object is null")); + goto cleanup; + } + + return 0; + + cleanup: + return -1; +} + +int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED) +{ + VBOX_OBJECT_CHECK(dom->conn, int, -1); + IConsole *console = NULL; + vboxIIDUnion iid; + IMachine *machine = NULL; + nsresult rc; + + pVBoxAPI->initializeVboxIID(&iid); + /* VirtualBox currently doesn't support saving to a file + * at a location other then the machine folder and thus + * setting path to ATTRIBUTE_UNUSED for now, will change + * this behaviour once get the VirtualBox API in right + * shape to do this + */ +
This down here ..
+ /* Open a Session for the machine */ + pVBoxAPI->vboxIIDFromUUID(data, &iid, dom->uuid); + if (pVBoxAPI->getMachineForSession) { + /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */ + rc = pVBoxAPI->objectGetMachine(data, &iid, &machine); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + return -1; + } + }
.. I guess is going to be used fairly frequently, so maybe it can be turned into a separate function.
+ + rc = pVBoxAPI->sessionOpenExisting(data, &iid, machine); + if (NS_SUCCEEDED(rc)) { + rc = pVBoxAPI->sessionGetConsole(data->vboxSession, &console); + if (NS_SUCCEEDED(rc) && console) { + IProgress *progress = NULL; + + pVBoxAPI->consoleSaveState(console, &progress); + + if (progress) { + resultCodeUnion resultCode; + + pVBoxAPI->progressWaitForCompletion(progress, -1); + pVBoxAPI->progressGetResultCode(progress, &resultCode); + if (RC_SUCCEEDED(resultCode)) { + ret = 0; + } + VBOX_RELEASE(progress); + } + VBOX_RELEASE(console); + } + pVBoxAPI->sessionClose(data->vboxSession); + }
I find this still distant to the rest of our code. I mean, we use this pattern: if (func() < 0) goto cleanup; rc = func2(); if (rc < 0) goto cleanup; So maybe we can use the same here: rc = pVBoxAPI->sessionOpenExisting(data, &iid, machine); if (NS_FAILED(rc) < 0) goto cleanup; rc = pVBoxAPI->sessionGetConsole(data->vboxSession, &console); if (NS_FAILED(rc) < 0) goto cleanup; ... ret = 0; cleanup: VBOX_RELEASE(progress); VBOX_RELEASE(console); pVBoxAPI->sessionClose(data->vboxSession); ... return ret;
+ + pVBoxAPI->DEBUGIID("UUID of machine being saved:", &iid); + + VBOX_RELEASE(machine); + pVBoxAPI->vboxIIDUnalloc(data, &iid); + return ret; +} diff --git a/src/vbox/vbox_common.h b/src/vbox/vbox_common.h new file mode 100644 index 0000000..bf0d106 --- /dev/null +++ b/src/vbox/vbox_common.h @@ -0,0 +1,151 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@gmail.com) + * + * 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.1 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, see + * <http://www.gnu.org/licenses/>. + */ + +#ifndef VBOX_COMMON_H +# define VBOX_COMMON_H + +# ifdef ___VirtualBox_CXPCOM_h +# error this file should not be included after vbox_CAPI_v*.h +# endif + +# include "internal.h" +# include <stddef.h> +# include "wchar.h" + +/* This file extracts some symbols defined in + * vbox_CAPI_v*.h. It tells the vbox_common.c + * how to treat with this symbols. This file + * can't be included with files such as + * vbox_CAPI_v*.h, or it would casue multiple + * definitions. + * + * You can see the more informations in vbox_api.h + */ + +/* Copied definitions from vbox_CAPI_*.h. + * We must MAKE SURE these codes are compatible. */ + +typedef unsigned char PRUint8; +# if (defined(HPUX) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus < 199707L) \ + || (defined(SCO) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus == 1L) +typedef char PRInt8; +# else +typedef signed char PRInt8; +# endif + +# define PR_INT8_MAX 127 +# define PR_INT8_MIN (-128) +# define PR_UINT8_MAX 255U + +typedef unsigned short PRUint16; +typedef short PRInt16; + +# define PR_INT16_MAX 32767 +# define PR_INT16_MIN (-32768) +# define PR_UINT16_MAX 65535U
Are these really necessary? I know we already have them, I'm just asking.
+ +typedef unsigned int PRUint32; +typedef int PRInt32; +# define PR_INT32(x) x +# define PR_UINT32(x) x ## U + +# define PR_INT32_MAX PR_INT32(2147483647) +# define PR_INT32_MIN (-PR_INT32_MAX - 1) +# define PR_UINT32_MAX PR_UINT32(4294967295) + +typedef long PRInt64; +typedef unsigned long PRUint64; +typedef int PRIntn; +typedef unsigned int PRUintn; + +typedef double PRFloat64; +typedef size_t PRSize; + +typedef ptrdiff_t PRPtrdiff; + +typedef unsigned long PRUptrdiff; + +typedef PRIntn PRBool; + +# define PR_TRUE 1 +# define PR_FALSE 0 + +typedef PRUint8 PRPackedBool; + +/* +** Status code used by some routines that have a single point of failure or +** special status return. +*/ +typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; + +# ifndef __PRUNICHAR__ +# define __PRUNICHAR__ +# if defined(WIN32) || defined(XP_MAC) +typedef wchar_t PRUnichar; +# else +typedef PRUint16 PRUnichar; +# endif +# endif + +typedef long PRWord; +typedef unsigned long PRUword; + +# define nsnull 0 +typedef PRUint32 nsresult; + +# if defined(__GNUC__) && (__GNUC__ > 2) +# define NS_LIKELY(x) (__builtin_expect((x), 1)) +# define NS_UNLIKELY(x) (__builtin_expect((x), 0)) +# else +# define NS_LIKELY(x) (x) +# define NS_UNLIKELY(x) (x) +# endif + +# define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000)) +# define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000)))
Wow, I didn't know we are using likely and unlikely in libvirt.
+ +/** + * An "interface id" which can be used to uniquely identify a given + * interface. + * A "unique identifier". This is modeled after OSF DCE UUIDs. + */ + +struct nsID { + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; +}; + +typedef struct nsID nsID; +typedef nsID nsIID; + +/* Simplied definitions in vbox_CAPI_*.h */ + +typedef void const *PCVBOXXPCOM; +typedef void IVirtualBox; +typedef void ISession; +typedef void IVirtualBoxCallback; +typedef void nsIEventQueue; +typedef void IConsole; +typedef void IMachine; +typedef void IProgress; + +#endif /* VBOX_COMMON_H */

The most code in vbox_common.h is extracted from the vbox_CAPI_v*.h. I know some symbols like PR_INT16_MAX or PR_INT16_MIN may not be necessary, as well as the definition of the NS_LIKELY and NS_UNLIKEY. But I put it here because I treat these codes as a whole thing and not separate them. I think your suggestion on handling API fails is better than mine, I would take it.

2014-07-02 17:12 GMT+08:00 Michal Privoznik <mprivozn@redhat.com>:
On 26.06.2014 15:51, Taowei wrote:
In vbox_common.c: vboxInitialize and vboxDomainSave are rewrited with vboxUniformedAPI.
In vbox_common.h Some common definitions in vbox_CAPI_v*.h are directly extracted to this file. Some other incompatible defintions are simplified here. So we can write common code with it.
--- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/vbox/vbox_common.c | 150 ++++++++++++++++++++++++++++++ +++++++++++++++++ src/vbox/vbox_common.h | 151 ++++++++++++++++++++++++++++++ ++++++++++++++++++ 4 files changed, 303 insertions(+) create mode 100644 src/vbox/vbox_common.c create mode 100644 src/vbox/vbox_common.h
diff --git a/po/POTFILES.in b/po/POTFILES.in index 31a8381..8c1b712 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -213,6 +213,7 @@ src/util/virxml.c src/vbox/vbox_MSCOMGlue.c src/vbox/vbox_XPCOMCGlue.c src/vbox/vbox_driver.c +src/vbox/vbox_common.c src/vbox/vbox_snapshot_conf.c src/vbox/vbox_tmpl.c src/vmware/vmware_conf.c diff --git a/src/Makefile.am b/src/Makefile.am index c1e3f45..7a935e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -674,6 +674,7 @@ VBOX_DRIVER_SOURCES = \ vbox/vbox_V4_2_20.c vbox/vbox_CAPI_v4_2_20.h \ vbox/vbox_V4_3.c vbox/vbox_CAPI_v4_3.h \ vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h \ + vbox/vbox_common.c vbox/vbox_common.h \ vbox/vbox_uniformed_api.h
VBOX_DRIVER_EXTRA_DIST = \ diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c new file mode 100644 index 0000000..27211a0 --- /dev/null +++ b/src/vbox/vbox_common.c @@ -0,0 +1,150 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@gmail.com) + * + * 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.1 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, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <unistd.h> + +#include "internal.h" +#include "datatypes.h" +#include "domain_conf.h" +#include "domain_event.h" +#include "virlog.h" + +#include "vbox_common.h" +#include "vbox_uniformed_api.h" + +/* Common codes for vbox driver. With the definitions in vbox_common.h, + * it treats vbox structs as a void*. Though vboxUniformedAPI + * it call vbox functions. This file is a high level implement about + * the vbox driver. + */ + +#define VIR_FROM_THIS VIR_FROM_VBOX + +VIR_LOG_INIT("vbox.vbox_common"); + +#define RC_SUCCEEDED(rc) NS_SUCCEEDED(rc.resultCode) +#define RC_FAILED(rc) NS_FAILED(rc.resultCode) + +#define VBOX_RELEASE(arg) \ + do { \ + if (arg) { \ + pVBoxAPI->nsisupportsRelease((void *)arg); \ + (arg) = NULL; \ + } \ + } while (0) + +#define VBOX_OBJECT_CHECK(conn, type, value) \ +vboxGlobalData *data = conn->privateData;\ +type ret = value;\ +if (!data->vboxObj) {\ + return ret;\ +} + +static vboxUniformedAPI *pVBoxAPI; + +void vboxRegisterUniformedAPI(vboxUniformedAPI *vboxAPI) +{ + VIR_DEBUG("VirtualBox Uniformed API has been registered"); + pVBoxAPI = vboxAPI; +} + +int vboxInitialize(vboxGlobalData *data) +{ + if (pVBoxAPI->pfnInitialize(data) != 0) + goto cleanup; + + if (pVBoxAPI->fWatchNeedInitialize && pVBoxAPI->initializeFWatch(data) != 0) + goto cleanup; + + if (data->vboxObj == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("IVirtualBox object is null")); + goto cleanup; + } + + if (data->vboxSession == NULL) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("ISession object is null")); + goto cleanup; + } + + return 0; + + cleanup: + return -1; +} + +int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED) +{ + VBOX_OBJECT_CHECK(dom->conn, int, -1); + IConsole *console = NULL; + vboxIIDUnion iid; + IMachine *machine = NULL; + nsresult rc; + + pVBoxAPI->initializeVboxIID(&iid); + /* VirtualBox currently doesn't support saving to a file + * at a location other then the machine folder and thus + * setting path to ATTRIBUTE_UNUSED for now, will change + * this behaviour once get the VirtualBox API in right + * shape to do this + */ +
This down here ..
+ /* Open a Session for the machine */
+ pVBoxAPI->vboxIIDFromUUID(data, &iid, dom->uuid); + if (pVBoxAPI->getMachineForSession) { + /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */ + rc = pVBoxAPI->objectGetMachine(data, &iid, &machine); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching uuid")); + return -1; + } + }
.. I guess is going to be used fairly frequently, so maybe it can be turned into a separate function.
pVBoxAPI->vboxIIDFromUUID(data, &iid, dom->uuid); rc = pVBoxAPI->objectGetMachine(data, &iid, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO_DOMAIN, "%s", _("no domain with matching uuid")); return -1; } This part indeed be used frequently, but some places check the flag getMachineForSession while other places don't. So the prototype would be this:
int openSessionForMachine(vboxGlobaldata *data, vboxIID *iid, unsigned char* dom_uuid, IMachine *machine, bool checkflag); Is this okay (or too complex)? Meanwhile, When NS_FAILED(rc), some functions returned -1 (like this one), but some else goto the cleanup and unalloc the vboxIID, I perfer to make all NS_FAILED(rc) goto cleanup, what's your opinion?
+
+ rc = pVBoxAPI->sessionOpenExisting(data, &iid, machine); + if (NS_SUCCEEDED(rc)) { + rc = pVBoxAPI->sessionGetConsole(data->vboxSession, &console); + if (NS_SUCCEEDED(rc) && console) { + IProgress *progress = NULL; + + pVBoxAPI->consoleSaveState(console, &progress); + + if (progress) { + resultCodeUnion resultCode; + + pVBoxAPI->progressWaitForCompletion(progress, -1); + pVBoxAPI->progressGetResultCode(progress, &resultCode); + if (RC_SUCCEEDED(resultCode)) { + ret = 0; + } + VBOX_RELEASE(progress); + } + VBOX_RELEASE(console); + } + pVBoxAPI->sessionClose(data->vboxSession); + }
I find this still distant to the rest of our code. I mean, we use this pattern:
if (func() < 0) goto cleanup;
rc = func2(); if (rc < 0) goto cleanup;
So maybe we can use the same here:
rc = pVBoxAPI->sessionOpenExisting(data, &iid, machine); if (NS_FAILED(rc) < 0) goto cleanup;
rc = pVBoxAPI->sessionGetConsole(data->vboxSession, &console); if (NS_FAILED(rc) < 0) goto cleanup;
...
ret = 0; cleanup: VBOX_RELEASE(progress); VBOX_RELEASE(console); pVBoxAPI->sessionClose(data->vboxSession); ... return ret;
+
+ pVBoxAPI->DEBUGIID("UUID of machine being saved:", &iid); + + VBOX_RELEASE(machine); + pVBoxAPI->vboxIIDUnalloc(data, &iid); + return ret; +} diff --git a/src/vbox/vbox_common.h b/src/vbox/vbox_common.h new file mode 100644 index 0000000..bf0d106 --- /dev/null +++ b/src/vbox/vbox_common.h @@ -0,0 +1,151 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@gmail.com) + * + * 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.1 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, see + * <http://www.gnu.org/licenses/>. + */ + +#ifndef VBOX_COMMON_H +# define VBOX_COMMON_H + +# ifdef ___VirtualBox_CXPCOM_h +# error this file should not be included after vbox_CAPI_v*.h +# endif + +# include "internal.h" +# include <stddef.h> +# include "wchar.h" + +/* This file extracts some symbols defined in + * vbox_CAPI_v*.h. It tells the vbox_common.c + * how to treat with this symbols. This file + * can't be included with files such as + * vbox_CAPI_v*.h, or it would casue multiple + * definitions. + * + * You can see the more informations in vbox_api.h + */ + +/* Copied definitions from vbox_CAPI_*.h. + * We must MAKE SURE these codes are compatible. */ + +typedef unsigned char PRUint8; +# if (defined(HPUX) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus < 199707L) \ + || (defined(SCO) && defined(__cplusplus) \ + && !defined(__GNUC__) && __cplusplus == 1L) +typedef char PRInt8; +# else +typedef signed char PRInt8; +# endif + +# define PR_INT8_MAX 127 +# define PR_INT8_MIN (-128) +# define PR_UINT8_MAX 255U + +typedef unsigned short PRUint16; +typedef short PRInt16; + +# define PR_INT16_MAX 32767 +# define PR_INT16_MIN (-32768) +# define PR_UINT16_MAX 65535U
Are these really necessary? I know we already have them, I'm just asking.
+
+typedef unsigned int PRUint32; +typedef int PRInt32; +# define PR_INT32(x) x +# define PR_UINT32(x) x ## U + +# define PR_INT32_MAX PR_INT32(2147483647) +# define PR_INT32_MIN (-PR_INT32_MAX - 1) +# define PR_UINT32_MAX PR_UINT32(4294967295) + +typedef long PRInt64; +typedef unsigned long PRUint64; +typedef int PRIntn; +typedef unsigned int PRUintn; + +typedef double PRFloat64; +typedef size_t PRSize; + +typedef ptrdiff_t PRPtrdiff; + +typedef unsigned long PRUptrdiff; + +typedef PRIntn PRBool; + +# define PR_TRUE 1 +# define PR_FALSE 0 + +typedef PRUint8 PRPackedBool; + +/* +** Status code used by some routines that have a single point of failure or +** special status return. +*/ +typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus; + +# ifndef __PRUNICHAR__ +# define __PRUNICHAR__ +# if defined(WIN32) || defined(XP_MAC) +typedef wchar_t PRUnichar; +# else +typedef PRUint16 PRUnichar; +# endif +# endif + +typedef long PRWord; +typedef unsigned long PRUword; + +# define nsnull 0 +typedef PRUint32 nsresult; + +# if defined(__GNUC__) && (__GNUC__ > 2) +# define NS_LIKELY(x) (__builtin_expect((x), 1)) +# define NS_UNLIKELY(x) (__builtin_expect((x), 0)) +# else +# define NS_LIKELY(x) (x) +# define NS_UNLIKELY(x) (x) +# endif + +# define NS_FAILED(_nsresult) (NS_UNLIKELY((_nsresult) & 0x80000000)) +# define NS_SUCCEEDED(_nsresult) (NS_LIKELY(!((_nsresult) & 0x80000000)))
Wow, I didn't know we are using likely and unlikely in libvirt.
+
+/** + * An "interface id" which can be used to uniquely identify a given + * interface. + * A "unique identifier". This is modeled after OSF DCE UUIDs. + */ + +struct nsID { + PRUint32 m0; + PRUint16 m1; + PRUint16 m2; + PRUint8 m3[8]; +}; + +typedef struct nsID nsID; +typedef nsID nsIID; + +/* Simplied definitions in vbox_CAPI_*.h */ + +typedef void const *PCVBOXXPCOM; +typedef void IVirtualBox; +typedef void ISession; +typedef void IVirtualBoxCallback; +typedef void nsIEventQueue; +typedef void IConsole; +typedef void IMachine; +typedef void IProgress; + +#endif /* VBOX_COMMON_H */

On 02.07.2014 15:45, Taowei Luo wrote:
2014-07-02 17:12 GMT+08:00 Michal Privoznik <mprivozn@redhat.com <mailto:mprivozn@redhat.com>>:
On 26.06.2014 15 <tel:26.06.2014%2015>:51, Taowei wrote:
In vbox_common.c: vboxInitialize and vboxDomainSave are rewrited with vboxUniformedAPI.
In vbox_common.h Some common definitions in vbox_CAPI_v*.h are directly extracted to this file. Some other incompatible defintions are simplified here. So we can write common code with it.
--- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/vbox/vbox_common.c | 150 ++++++++++++++++++++++++++++++__+++++++++++++++++ src/vbox/vbox_common.h | 151 ++++++++++++++++++++++++++++++__++++++++++++++++++ 4 files changed, 303 insertions(+) create mode 100644 src/vbox/vbox_common.c create mode 100644 src/vbox/vbox_common.h
diff --git a/po/POTFILES.in b/po/POTFILES.in index 31a8381..8c1b712 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -213,6 +213,7 @@ src/util/virxml.c src/vbox/vbox_MSCOMGlue.c src/vbox/vbox_XPCOMCGlue.c src/vbox/vbox_driver.c +src/vbox/vbox_common.c src/vbox/vbox_snapshot_conf.c src/vbox/vbox_tmpl.c src/vmware/vmware_conf.c diff --git a/src/Makefile.am b/src/Makefile.am index c1e3f45..7a935e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -674,6 +674,7 @@ VBOX_DRIVER_SOURCES = \ vbox/vbox_V4_2_20.c vbox/vbox_CAPI_v4_2_20.h \ vbox/vbox_V4_3.c vbox/vbox_CAPI_v4_3.h \ vbox/vbox_V4_3_4.c vbox/vbox_CAPI_v4_3_4.h \ + vbox/vbox_common.c vbox/vbox_common.h \ vbox/vbox_uniformed_api.h
VBOX_DRIVER_EXTRA_DIST = \ diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c new file mode 100644 index 0000000..27211a0 --- /dev/null +++ b/src/vbox/vbox_common.c @@ -0,0 +1,150 @@ +/* + * Copyright 2014, Taowei Luo (uaedante@gmail.com <mailto:uaedante@gmail.com>) + * + * 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.1 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, see + * <http://www.gnu.org/licenses/>__. + */ + +#include <config.h> + +#include <unistd.h> + +#include "internal.h" +#include "datatypes.h" +#include "domain_conf.h" +#include "domain_event.h" +#include "virlog.h" + +#include "vbox_common.h" +#include "vbox_uniformed_api.h" + +/* Common codes for vbox driver. With the definitions in vbox_common.h, + * it treats vbox structs as a void*. Though vboxUniformedAPI + * it call vbox functions. This file is a high level implement about + * the vbox driver. + */ + +#define VIR_FROM_THIS VIR_FROM_VBOX + +VIR_LOG_INIT("vbox.vbox___common"); + +#define RC_SUCCEEDED(rc) NS_SUCCEEDED(rc.resultCode) +#define RC_FAILED(rc) NS_FAILED(rc.resultCode) + +#define VBOX_RELEASE(arg) \ + do { \ + if (arg) { \ + pVBoxAPI->nsisupportsRelease((__void *)arg); \ + (arg) = NULL; \ + } \ + } while (0) + +#define VBOX_OBJECT_CHECK(conn, type, value) \ +vboxGlobalData *data = conn->privateData;\ +type ret = value;\ +if (!data->vboxObj) {\ + return ret;\ +} + +static vboxUniformedAPI *pVBoxAPI; + +void vboxRegisterUniformedAPI(__vboxUniformedAPI *vboxAPI) +{ + VIR_DEBUG("VirtualBox Uniformed API has been registered"); + pVBoxAPI = vboxAPI; +} + +int vboxInitialize(vboxGlobalData *data) +{ + if (pVBoxAPI->pfnInitialize(data) != 0) + goto cleanup; + + if (pVBoxAPI->__fWatchNeedInitialize && pVBoxAPI->initializeFWatch(__data) != 0) + goto cleanup; + + if (data->vboxObj == NULL) { + virReportError(VIR_ERR___INTERNAL_ERROR, "%s", + _("IVirtualBox object is null")); + goto cleanup; + } + + if (data->vboxSession == NULL) { + virReportError(VIR_ERR___INTERNAL_ERROR, "%s", + _("ISession object is null")); + goto cleanup; + } + + return 0; + + cleanup: + return -1; +} + +int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED) +{ + VBOX_OBJECT_CHECK(dom->conn, int, -1); + IConsole *console = NULL; + vboxIIDUnion iid; + IMachine *machine = NULL; + nsresult rc; + + pVBoxAPI->initializeVboxIID(&__iid); + /* VirtualBox currently doesn't support saving to a file + * at a location other then the machine folder and thus + * setting path to ATTRIBUTE_UNUSED for now, will change + * this behaviour once get the VirtualBox API in right + * shape to do this + */ +
This down here ..
+ /* Open a Session for the machine */ + pVBoxAPI->vboxIIDFromUUID(__data, &iid, dom->uuid); + if (pVBoxAPI->__getMachineForSession) { + /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */ + rc = pVBoxAPI->objectGetMachine(__data, &iid, &machine); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_NO___DOMAIN, "%s", + _("no domain with matching uuid")); + return -1; + } + }
.. I guess is going to be used fairly frequently, so maybe it can be turned into a separate function.
pVBoxAPI->vboxIIDFromUUID(__data, &iid, dom->uuid); rc = pVBoxAPI->objectGetMachine(__data, &iid, &machine); if (NS_FAILED(rc)) { virReportError(VIR_ERR_NO___DOMAIN, "%s", _("no domain with matching uuid")); return -1; } This part indeed be used frequently, but some places check the flag getMachineForSession while other places don't. So the prototype would be this:
int openSessionForMachine(vboxGlobaldata *data, vboxIID *iid, unsigned char* dom_uuid, IMachine *machine, bool checkflag);
Is this okay (or too complex)?
Looks good to me.
Meanwhile, When NS_FAILED(rc), some functions returned -1 (like this one), but some else goto the cleanup and unalloc the vboxIID, I perfer to make all NS_FAILED(rc) goto cleanup, what's your opinion?
Well, I don't think that's a good idea, since functions can have different labels. If you want to do this, then I think: NS_FAILED_GOTO(rc, cleanup); is better idea. Michal

Install the uniformed API for common code. --- src/vbox/vbox_driver.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/vbox/vbox_driver.c b/src/vbox/vbox_driver.c index 7d004b2..e90b7ef 100644 --- a/src/vbox/vbox_driver.c +++ b/src/vbox/vbox_driver.c @@ -39,6 +39,9 @@ #include "vbox_glue.h" #include "virerror.h" #include "virutil.h" +#include "domain_event.h" +#include "domain_conf.h" +#include "vbox_uniformed_api.h" #define VIR_FROM_THIS VIR_FROM_VBOX @@ -47,33 +50,43 @@ VIR_LOG_INIT("vbox.vbox_driver"); extern virDriver vbox22Driver; extern virNetworkDriver vbox22NetworkDriver; extern virStorageDriver vbox22StorageDriver; +extern vboxUniformedAPI vbox22UniformedAPI; extern virDriver vbox30Driver; extern virNetworkDriver vbox30NetworkDriver; extern virStorageDriver vbox30StorageDriver; +extern vboxUniformedAPI vbox30UniformedAPI; extern virDriver vbox31Driver; extern virNetworkDriver vbox31NetworkDriver; extern virStorageDriver vbox31StorageDriver; +extern vboxUniformedAPI vbox31UniformedAPI; extern virDriver vbox32Driver; extern virNetworkDriver vbox32NetworkDriver; extern virStorageDriver vbox32StorageDriver; +extern vboxUniformedAPI vbox32UniformedAPI; extern virDriver vbox40Driver; extern virNetworkDriver vbox40NetworkDriver; extern virStorageDriver vbox40StorageDriver; +extern vboxUniformedAPI vbox40UniformedAPI; extern virDriver vbox41Driver; extern virNetworkDriver vbox41NetworkDriver; extern virStorageDriver vbox41StorageDriver; +extern vboxUniformedAPI vbox41UniformedAPI; extern virDriver vbox42Driver; extern virNetworkDriver vbox42NetworkDriver; extern virStorageDriver vbox42StorageDriver; +extern vboxUniformedAPI vbox42UniformedAPI; extern virDriver vbox42_20Driver; extern virNetworkDriver vbox42_20NetworkDriver; extern virStorageDriver vbox42_20StorageDriver; +extern vboxUniformedAPI vbox42_20UniformedAPI; extern virDriver vbox43Driver; extern virNetworkDriver vbox43NetworkDriver; extern virStorageDriver vbox43StorageDriver; +extern vboxUniformedAPI vbox43UniformedAPI; extern virDriver vbox43_4Driver; extern virNetworkDriver vbox43_4NetworkDriver; extern virStorageDriver vbox43_4StorageDriver; +extern vboxUniformedAPI vbox43_4UniformedAPI; static virDriver vboxDriverDummy; @@ -84,6 +97,7 @@ int vboxRegister(void) virDriverPtr driver; virNetworkDriverPtr networkDriver; virStorageDriverPtr storageDriver; + vboxUniformedAPI *vboxAPI; uint32_t uVersion; /* @@ -95,6 +109,7 @@ int vboxRegister(void) driver = &vboxDriverDummy; networkDriver = &vbox22NetworkDriver; storageDriver = &vbox22StorageDriver; + vboxAPI = &vbox22UniformedAPI; /* Init the glue and get the API version. */ if (VBoxCGlueInit(&uVersion) == 0) { @@ -113,51 +128,61 @@ int vboxRegister(void) driver = &vbox22Driver; networkDriver = &vbox22NetworkDriver; storageDriver = &vbox22StorageDriver; + vboxAPI = &vbox22UniformedAPI; } else if (uVersion >= 2002051 && uVersion < 3000051) { VIR_DEBUG("VirtualBox API version: 3.0"); driver = &vbox30Driver; networkDriver = &vbox30NetworkDriver; storageDriver = &vbox30StorageDriver; + vboxAPI = &vbox30UniformedAPI; } else if (uVersion >= 3000051 && uVersion < 3001051) { VIR_DEBUG("VirtualBox API version: 3.1"); driver = &vbox31Driver; networkDriver = &vbox31NetworkDriver; storageDriver = &vbox31StorageDriver; + vboxAPI = &vbox31UniformedAPI; } else if (uVersion >= 3001051 && uVersion < 3002051) { VIR_DEBUG("VirtualBox API version: 3.2"); driver = &vbox32Driver; networkDriver = &vbox32NetworkDriver; storageDriver = &vbox32StorageDriver; + vboxAPI = &vbox32UniformedAPI; } else if (uVersion >= 3002051 && uVersion < 4000051) { VIR_DEBUG("VirtualBox API version: 4.0"); driver = &vbox40Driver; networkDriver = &vbox40NetworkDriver; storageDriver = &vbox40StorageDriver; + vboxAPI = &vbox40UniformedAPI; } else if (uVersion >= 4000051 && uVersion < 4001051) { VIR_DEBUG("VirtualBox API version: 4.1"); driver = &vbox41Driver; networkDriver = &vbox41NetworkDriver; storageDriver = &vbox41StorageDriver; + vboxAPI = &vbox41UniformedAPI; } else if (uVersion >= 4001051 && uVersion < 4002020) { VIR_DEBUG("VirtualBox API version: 4.2"); driver = &vbox42Driver; networkDriver = &vbox42NetworkDriver; storageDriver = &vbox42StorageDriver; + vboxAPI = &vbox42UniformedAPI; } else if (uVersion >= 4002020 && uVersion < 4002051) { - VIR_DEBUG("VirtualBox API version: 4.2.20 or higher"); - driver = &vbox42_20Driver; - networkDriver = &vbox42_20NetworkDriver; - storageDriver = &vbox42_20StorageDriver; + VIR_DEBUG("VirtualBox API version: 4.2.20 or higher"); + driver = &vbox42_20Driver; + networkDriver = &vbox42_20NetworkDriver; + storageDriver = &vbox42_20StorageDriver; + vboxAPI = &vbox42_20UniformedAPI; } else if (uVersion >= 4002051 && uVersion < 4003004) { VIR_DEBUG("VirtualBox API version: 4.3"); driver = &vbox43Driver; networkDriver = &vbox43NetworkDriver; storageDriver = &vbox43StorageDriver; + vboxAPI = &vbox43UniformedAPI; } else if (uVersion >= 4003004 && uVersion < 4003051) { VIR_DEBUG("VirtualBox API version: 4.3.4 or higher"); driver = &vbox43_4Driver; networkDriver = &vbox43_4NetworkDriver; storageDriver = &vbox43_4StorageDriver; + vboxAPI = &vbox43_4UniformedAPI; } else { VIR_DEBUG("Unsupported VirtualBox API version: %u", uVersion); } @@ -172,6 +197,8 @@ int vboxRegister(void) if (virRegisterStorageDriver(storageDriver) < 0) return -1; + vboxRegisterUniformedAPI(vboxAPI); + return 0; } -- 1.7.9.5

On 26.06.2014 15:51, Taowei wrote:
Use vboxUniformedAPI to rewrite vbox driver. vboxInitialize and vboxDomainSave are rewrited in this way.
Taowei (4): add definitions for vboxUniformedAPI implement vboxUniformedAPI in vbox_tmpl.c use vboxUniformedAPI to generate common code install vboxUniformedAPI
po/POTFILES.in | 1 + src/Makefile.am | 4 +- src/vbox/vbox_common.c | 150 +++++++++++++++ src/vbox/vbox_common.h | 151 +++++++++++++++ src/vbox/vbox_driver.c | 35 +++- src/vbox/vbox_tmpl.c | 419 ++++++++++++++++++++++++----------------- src/vbox/vbox_uniformed_api.h | 168 +++++++++++++++++ 7 files changed, 749 insertions(+), 179 deletions(-) create mode 100644 src/vbox/vbox_common.c create mode 100644 src/vbox/vbox_common.h create mode 100644 src/vbox/vbox_uniformed_api.h
My overall feeling is good. We are not seeing the code removal yet, but we will as the old code is transformed into the new one. I think you can start rewriting the whole driver then. Michal

So, what the next checkpoint would be? When I have rewritten the whole driver or just after rewriting some more functions?

On 02.07.2014 12:08, Taowei Luo wrote:
So, what the next checkpoint would be? When I have rewritten the whole driver or just after rewriting some more functions?
Yes, rewrite some more functions and post patches to review and I can start reviewing and (hopefully) merging them. Michal
participants (3)
-
Michal Privoznik
-
Taowei
-
Taowei Luo