Page 1 of 1

Interfaces: correct way of using Clone() method

Posted: Sun Oct 07, 2012 9:41 am
by AlfredOne
I need help to understand the correct way of using Clone() method in order tor clone interfaces.

What the Clone() method should do in his implementation?
How should be obtained or released a cloned interface?

Thanks.

Alfredo

Re: Interfaces: correct way of using Clone() method

Posted: Mon Jan 28, 2013 11:26 pm
by centaurz
Hi,

Clone() is expected to build a new interface (by means of MakeInterface()), flag it as IFLF_CLONED, initialize its private data and return a pointer to it.
In this case, Expunge() shall also be implemented in order to undo what was done in Clone() (free memory, etc...).
Such interfaces are also supposed to perform garbage collecting in Release() when their usage counter reach 0 (i.e. call DeleteInterface() on themselves if the IFLF_CLONED flag is set).

Clone() is automatically used by the system (namely GetInterface()) for interfaces declared as IFLF_PRIVATE. In this case a clone of the private interface is returned on each call. I suppose you could also use it as a real copy constructor on an existing interface like it is suggested in the SDK...

Note that this usage only makes sense for libraries that export interfaces in an object oriented fashion (that is, hardly any but application.library dockies and expansion.library pci devices). Most libraries only export a single shared interface which is just a function table (but if you ask the question you probably already know that...).

Re: Interfaces: correct way of using Clone() method

Posted: Tue Jan 29, 2013 11:51 am
by Hans-Joerg Frieden
AlfredOne wrote:What the Clone() method should do in his implementation?
How should be obtained or released a cloned interface?
What centaurz said. Also, here's an example Clone() implementation I use in Gallium:

Code: Select all

struct Interface * _EGL_Clone(struct EGLIFace *Self)
{
	uint32 size = Self->Data.PositiveSize + Self->Data.NegativeSize;
	uint8 *newInterface = IExec->AllocVecTags(size, TAG_DONE);

	struct Interface *retValue = NULL;

	if (newInterface)
	{

		retValue = (struct Interface *)(newInterface + Self->Data.NegativeSize);
		uint8 *base = ((uint8 *)Self) - Self->Data.NegativeSize;
		IExec->CopyMem(base, newInterface, size);

		retValue -> Data.Flags = IFLF_CLONED;
		retValue -> Data.RefCount = 0;

		((eglinstance_t *)newInterface)->ITLS = (struct TLSIFace *)IExec->GetInterfaceTags(TLSBase, "main", 1, NULL);
		((eglinstance_t *)newInterface)->eglGlobalData = NULL;
		((eglinstance_t *)newInterface)->importTable = NULL;
		((eglinstance_t *)newInterface)->patchStart = NULL;
		((eglinstance_t *)newInterface)->patchEnd = NULL;
		((eglinstance_t *)newInterface)->FuncData = NULL;
		((eglinstance_t *)newInterface)->resolveFunc = NULL;
		((eglinstance_t *)newInterface)->unloadFunc = NULL;
		((eglinstance_t *)newInterface)->_eglModules = NULL;
		((eglinstance_t *)newInterface)->eglModuleMutex = IExec->AllocSysObjectTags(ASOT_MUTEX,
						ASOMUTEX_Recursive, TRUE,
						TAG_DONE);

	}
	return retValue;
}

There is nothing special you need to do, just GetInterface() this as usual; if an interface is flagged private and has a clone method, you will receive a "blank" copy of the interface that is not shared with anyone else.
centaurz wrote:Note that this usage only makes sense for libraries that export interfaces in an object oriented fashion (that is, hardly any but application.library dockies and expansion.library pci devices). Most libraries only export a single shared interface which is just a function table (but if you ask the question you probably already know that...).
Not necessarily. In this case, I made the interface private and cloned it because it requires a per-task/thread-local data. In this case, OpenGL and EGL require task-specific data (like the current error and such) so the library keeps track of that through a private interface. There is nothing "object oriented" about this, in fact, since egl functions are supposed to be called like "eglXXXX()" without an interface, the caller will not even notice that there is anything like that going on :)