How do programs run plugins?
-
On 09/08/2013 at 07:09, xxxxxxxx wrote:
User Information:
Cinema 4D Version: R14
Platform: Windows ;
Language(s) : C++ ;---------
Hi Folks,just seeking a bit of c++ knowledge here... When a plugin inside cinema is called/run/executed, does the plugin have to search through the whole .cdl code to find a particular function/method etc? Or are these stored at an address the program can find without having to search the plugin's code?
That might not make much sense, so here's a scenario I'm pondering. When I add an object to a scene, does Cinema (the program) have to run through the entire .cdl file coding to find the GetDDescription() function? Or is the plugin stored in memory where 'shortcuts' to functions are marked with an address of where that function begins in memory?
I'm asking purely out of interest mainly, but also because I seem to recall reading a comment in a thread where it was mentioned that using a .res file might be better than doing it all through the GetDDescription() because the program would only need to scroll through a smaller file (the .res file) in order to run the function - i.e. Cinema won't have to scroll through the .cdl file to locate the description function (that bit wasn't mentioned, that's just my interpretation of what I read).
Hope that query makes some sense... Perhaps another way of wording my question might be "is there any advantage/disadvantage in speed of having external files" (not worried about other benefits etc, just speed in operating and doing things)?
Any thoughts/ideas/clarification appreciated! Cheers big ears!
WP.
-
On 09/08/2013 at 08:52, xxxxxxxx wrote:
Originally posted by xxxxxxxx
When I add an object to a scene, does Cinema (the program) have to run through the entire .cdl file coding to find the GetDDescription() function? Or is the plugin stored in memory where 'shortcuts' to functions are marked with an address of where that function begins in memory?
A function is also just a memory address. The shared library has an entry point that is called "c4d_main". This is (typically) the only named function in the library. Cinema loads the library and searches for the "c4d_main" function. But once it is found, it does not have to search through it again since it already knows where the function is located.
This is the only function Cinema invokes on your plugin library _intentionally_. PluginStart(), PluginMessage() and PluginEnd() are called from c4d_main() which you can find in the c4d_plugin.cpp API file.
PluginStart() etc. then again register plugin implementations to Cinema. These are again nothing but memory addresses. When you register an ObjectPlugin for instance, you do it like this:
NodeData* AllocMyObjectPlugin(); // ... RegisterObjectPlugin(PLUGIN_ID, "My Object Plugin", OBJECT_GENERATOR, **AllocMyObjectPlugin** , "Omyplugin", NULL, PLUGIN_DISKLEVEL); NodeData* AllocMyObjectPlugin() { return gNew MyObjectPluginData; }
Cinema knows what to do with the value passed as the 4th parameter: It assumes it to be a function which allocates a NodeData object and returns its memory address. And by passing "AllocMyObjectPlugin" for this parameter, you do exactly what Cinema expects you to do.
But it does not have to search through your CDL/Dylib, it knows exactly where the function is located. The same applies for methods which are just the same as function pointers. However, these function pointers are stored in the virtual method table of an object which is generated automatically.
(Well, the statement is not 100% correct in Cinema's plugin system, but very similar. This would lead to deep into the API and would be quite complex to explain).
Hope this helps,
-Niklas -
On 09/08/2013 at 09:08, xxxxxxxx wrote:
No, there is no searching for functions involved - C++ is not an interpreter language. That's why you link against the API. The API provides the access pointers to all of C4D's internal functions. When a plugin is loaded, it basically receives the base address of the current function pointer table through which it can access the C4D core. So, your compiled plugin will just use its offsets to retrieve the proper function. The whole thing is transparent for the programmer and happens during the static and dynamic linking phase (compling the plugin and loading the plugin). The same is valid for any string resource that you embed as a constant.
Now, other files like .res are a different beast since they may not be handled by the compiler (some files are actually valid C++ though). These files are loaded at some point by the C4D code into an internal data structure, which takes a little time at runtime. After the loading however the content is stored internally in a data structure. Access to that data structure (like hashtable or array) is of course faster than the hard disk access, but slower than a programmatic constant.
The question about "advantage/disadvantage in external files" can be easily summed up by
static link or constant
is faster than
dynamic link or indirect reference
is faster than
hashtable access
is faster than
array access
is faster than
loading from diskbut it is equally pointless since you normally want external files for other reasons than speed. The res files are for easy change of the GUI and the internationalization without recompiling the program.
(And "using a .res file" conveniently hides the fact that C4D has to parse that file and then call its internal functions to build up the GUI, which has little to do with the loading time of the .res file...)
-
On 11/08/2013 at 02:31, xxxxxxxx wrote:
Thanks Niklas & Cairyn,
that all seems to make sense. Though just something else, what about the inside of the function itself - such as a whole bunch of if() statements? Example, if there are two if() statements, and the first one is very large, does the program need to scroll through the first statement to find the ending bracket before it can look at the second one? Or are things like this "tabled" with memory addresses etc too?
WP.
-
On 11/08/2013 at 02:55, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Thanks Niklas & Cairyn,
that all seems to make sense. Though just something else, what about the inside of the function itself - such as a whole bunch of if() statements? Example, if there are two if() statements, and the first one is very large, does the program need to scroll through the first statement to find the ending bracket before it can look at the second one? Or are things like this "tabled" with memory addresses etc too?
WP.The source code you write, with brackets and all, is what we humans need to write in order to talk to the compiler in an efficient way. When you compile the source code in C++, the compiler will convert your English source into machine code. It is all about memory addresses, data and operation codes.
Take this:
LONG a = 2
LONG b = 3
LONG c = a * b
When the program executes, it will read all he machine code, telling it to
Move 2 into a register A
Move 3 into register B
Multiply A with B and move the result into register C
When it runs out of registers, RAM memory is used.
There is no "scrolling" in the source code. Because the source code is not there anymore when the program executes. It is just jumping back and forth between addresses, moving values in and out of registers in the CPU and reading machine code telling the CPU what to do with the values currently in the registers.> before it can look at the second one
This "looking" is done when your program is compiled, not when executed. -
On 11/08/2013 at 03:17, xxxxxxxx wrote:
Thanks ingvarai,
I think what you've touched on there is perhaps where my wondering thoughts are leading me. To extend on my query a bit further, in the case of your post, I'm now wondering how would the program know what registers to look at when wanting to get the machine code LONG a = 2; etc. Is all of this "tabled" as well?
I know this topic is a bit beyond the plugin help as such, and getting a little technical, but it's just my curiosity at work. Just trying to 'picture' the operation in my head of how the software and machine transistors etc all work together. Probably a bit silly though, as I doubt I really need to know!
Anyway, thanks all!
WP.
-
On 11/08/2013 at 03:51, xxxxxxxx wrote:
If it hasn't been mentioned yet, it should be noted that Cinema 4D 'plugins' are nothing more than dynamic-link libraries (dll's) just like all of the other dlls (or dylibs for MacOS) applications use. Cinema 4D loads these special dll's as plugins at startup and accesses them through their entry points (as Niklas mentioned).
-
On 11/08/2013 at 05:45, xxxxxxxx wrote:
You may want to read up about assembly languages and associated topics (opcodes, registers as mentioned by ingvarai, the von-neumann architecture). C/C++ code is (by most compilers) translated into assembly code first and then into machine code.
-
On 11/08/2013 at 06:23, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Thanks ingvarai,
I know this topic is a bit beyond the plugin help as such, and getting a little technical, but it's just my curiosity at work. Just trying to 'picture' the operation in my head of how the software and machine transistors etc all work together. Probably a bit silly though, as I doubt I really need to know!I like this attitude, you are just like me..
We just have to open the lid, to find out what makes the clock tick.
Here, looks good:
http://www.codeproject.com/Articles/315505/How-processor-assembler-and-programming-languagesAnd the Internet is chock full of information on this.
-
On 11/08/2013 at 08:04, xxxxxxxx wrote:
Originally posted by xxxxxxxx
You may want to read up about assembly languages and associated topics (opcodes, registers as mentioned by ingvarai, the von-neumann architecture). C/C++ code is (by most compilers) translated into assembly code first and then into machine code.
Most definitely. This is how I started in learning programming. At first, it was BASIC, but then it went into assembler and cpu codes and such. At the very bottom, it is about the cpu instructions, memory, io, and the system architecture.
-
On 11/08/2013 at 16:48, xxxxxxxx wrote:
Howdy,
Originally posted by xxxxxxxx
...Example, if there are two if() statements, and the first one is very large, does the program need to scroll through the first statement to find the ending bracket before it can look at the second one?...
Not if the first if statement is false. It'll then skip the brackets and move onto the next if statement.
Also if you have an if statement with several tests like this:
BaseObject *op = tag->GetObject(); if(op && op->GetType() == ID_MYPLUGINTYPE) { //do something }
... if "op" is NULL, then the second test will be ignored, and it will jump to the end bracked.
You might want to consider, for learning purposes, setting some breakpoints, running your code in the debugger and have it display both the C++ source and the Assembler:
... Then you can step through the code and see what it's doing.
Adios,
Cactus Dan