Plan to rewrite vbox driver
Introduction:
The existing vbox driver codes use vbox API directly. But the vbox API is incompatible between different versions. To support all vbox API versions, the vbox_tmpl.c file provides a template to implement all vbox drivers. Each specified version of vbox driver includes the vbox_tmpl.c file, with the definition in the corresponding head file, they work well. As the vbox API defined in head files is conflict between different versions, even some behavior of vbox APIs are changed. The vbox_tmpl.c contains lots of codes such as “#if VBOX_API_VERSION < 4001000”. These codes is hard to manage or adding new features.
Plan:
The core idea of my rewriting work is to add a middle layer to uniform the API changes. This modification will not change any functions’ behavior or sematic.
The middle layer has a global structure which contains API changes. Like this:
struct vboxUniformedAPI {
A (*funcA)(A1 a, ….);
B (*funcB)(B1 a, ….);
}
If there is a code segment:
#if VBOX_API_VERSION < 4001000
adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
#else /* VBOX_API_VERSION >= 4001000 */
adapter->vtbl->GetBridgedInterface(adapter, &hostIntUtf16);
#endif /* VBOX_API_VERSION >= 4001000 */
This will result to a variable in vboxUniformedAPI structure:
RetType (*GetInterface)(INetworkAdapter *a, PRUnichar *b)
When using the vbox under 4.1, this variable will points to a function that calls GetHostInterface. When using the vbox later than 4.1 and the variable will points to a function which calls GetBridgedInterface.
When replace these code segments with a single function, we need to do living variable analyze and find out what is used and what is changed in these codes. I plan to do these analyze manually.
All conflict in function prototype or function implementation will be fixed up though this method.
When meeting a conflict in variable type, like:
#if VBOX_API_VERSION < 4001000
TypeA var;
#else /* VBOX_API_VERSION >= 4001000 */
TypeB var;
#endif /* VBOX_API_VERSION >= 4001000 */
I will add a union like this:
Union TypeC{
TypeA a;// used in some versions
TypeB b;// used in some other versions
}
If there is any operation using variables with such a union type (or functions use it as an argument or return value), I will add a new function in vboxUniformedAPI to handle this operation. These functions use TypeC as parameter type, dispatch it depends on the vbox version and return TypeC value to conceal type conflict.
We still have another kind of conflict. There are some versions have more variables, operations or function calls than other versions. I will reserve all variables even though they may not be used in some situation. And put an empty function if they have nothing to do in the specified function step. (I have a backup solution here. That is adding some flags to indicate whether the procession is necessary in the API version and prevent upper layer from calling a nonexistent function.)
Expected result:
After rewriting with the rules above, we will have a new vbox_tmpl.c. It gathers version specified code and common code respectively. The common codes use stable vbox API or functions in vboxUniformedAPI. A function named InstallvboxUnifromedAPI will fill the vboxUniformedAPI structure depends on the current vbox API version. In final step, I will put all vbox APIs into the vboxUniformedAPI and make the vbox driver codes use my API only. If this is done, the vbox driver will not be complied for each version anymore.
Implementation:
First, define the vboxUniformedAPI structure in vbox_tmpl.c, and write the InstallvboxUnifromedAPI function for every vbox API version.
Next, rewrite the functions which have conflict codes one by one. Each time rewrite a new function, we can do some tests (here, I am not sure what kind of tests is enough). When rewriting one function in vbox_tmpl.c, the others will not change.
At this point, there will split version specified codes and common codes But we still need to build the whole vbox_tmpl.c for each vbox API version.
If we want a single object file be generated by vbox_tmpl.c, we need to prevent vbox_tmpl.c from calling vbox API directly. This could be done by putting all of the vbox API calls into the middle vboxUniformedAPI layer, and moving common codes into vbox_common.c. The vbox_common.c should only use APIs in vboxUniformedAPI and will be complied only once.
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list