The heart of the CPM module is the CPM scanner. The scanner reads a C source file. When it sees the keyword CpmInvokable in front of one of the user's function declarations, it generates a launcher for that particular function. The launcher is a function whose name is Cpm_ concatenated to the name of the user's function. The launcher accepts the same arguments as the user's function, plus a destination argument. Calling the launcher transmits a message to another processor determined by the destination argument. When the message arrives and is handled, the user's function is called.
For example, if the CPM scanner sees the following function declaration
The scanner will generate a launcher named Cpm_myfunc. The launcher has this prototype:
If one were to call Cpm_myfunc as follows:
a message would be sent to processor 3 ordering it to call myfunc(8,9). Notice that the destination argument isn't just an integer processor number. The possible destinations for a message are described later.
When the CPM scanner is applied to a C source file with a particular name, it generates a certain amount of parameter packing and unpacking code, and this code is placed in an include file named similarly to the original C file: the .c is replaced with .cpm.h. The include file must be included in the original .c file, after the declarations of the types which are being packed and unpacked, but before all uses of the CPM invocation mechanisms.
Note that the .cpm.h include file is not for prototyping. It contains the C code for the packing and unpacking mechanisms. Therefore, it should only be included in the one source file from which it was generated. If the user wishes to prototype his code, he must do so normally, by writing a header file of his own.
Each .cpm.h file contains a function CpmInitializeThisModule, which initializes the code in that .cpm.h file. The function is declared static, so it is possible to have one in each .cpm.h file without conflicts. It is the responsibility of the CPM user to call each of these CpmInitializeThisModule functions before using any of the CPM mechanisms.
We demonstrate the use of the CPM mechanisms using the following short program myprog.c:
\n", n);
Lines 3-6 of this program contain a simple C function that prints an integer. The function is marked with the word CpmInvokable. When the CPM scanner sees this word, it adds the function Cpm_print_integer to the file myprog.cpm.h. The program includes myprog.cpm.h on line 1, and initializes the code in there on line 12. Each call to Cpm_print_integer on line 15 builds a message that invokes print_integer. The destination-argument CpmSend(i) causes the message to be sent to the i'th processor.
The effect of this program is that the first processor orders each of the other processors to print a random number. Note that the example is somewhat minimalist since it doesn't contain any code for terminating itself. Also note that it would have been more efficient to use an explicit broadcast. Broadcasts are described later.
All launchers accept a CpmDestination as their first argument. A CpmDestination is actually a pointer to a small C structure containing routing and handling information. The CPM module has many built-in functions that return CpmDestinations. Therefore, any of these can be used as the first argument to a launcher:
All the functions shown above accept processor numbers as arguments. Instead of supplying a processor number, one can also supply the special symbols CPM_ALL or CPM_OTHERS, causing a broadcast. For example,
would broadcast a message to all the processors causing each processor to create a thread, which would in turn invoke print_integer with the argument 5.
November 23, 2009
Charm Homepage