SimGrid
|
Defines | |
#define | GRAS_DEFINE_TYPE(name, def) |
Automatically parse C code. | |
#define | GRAS_DEFINE_TYPE_EXTERN |
if this symbol is defined, the GRAS_DEFINE_TYPE symbols live in another file. | |
#define | GRAS_DEFINE_TYPE_LOCAL(name, def) |
Define a symbol to be automatically parsed, disregarding GRAS_DEFINE_TYPE_EXTERN. | |
#define | gras_datadesc_by_symbol(name) |
Retrieve a datadesc which was previously parsed. | |
#define | GRAS_ANNOTE(key, val) |
Add an annotation to a type to be automatically parsed. | |
Functions | |
void | gras_datadesc_set_const (const char *name, int value) |
Defines the value of a define to the datatype parsing infrastructure. |
If you need to declare a new datatype, this is the simplest way to describe it to GRAS. Simply enclose its type definition into a GRAS_DEFINE_TYPE macro call, and you're set. Here is an type declaration example:
GRAS_DEFINE_TYPE(mytype,struct mytype { int myfirstfield; char mysecondfield; });
The type is then both copied verbatim into your source file and stored for further parsing. This allows you to let GRAS parse the exact version you are actually using in your program. You can then retrieve the corresponding type description with gras_datadesc_by_symbol. Don't worry too much for the performances, the type is only parsed once and a binary representation is stored and used in any subsequent calls.
If your structure contains any pointer, you have to explain GRAS the size of the pointed array. This can be 1 in the case of simple references, or more in the case of regular arrays. For that, use the GRAS_ANNOTE macro within the type declaration you are passing to GRAS_DEFINE_TYPE. This macro rewrites itself to nothing in the declaration (so they won't pollute the type definition copied verbatim into your code), and give some information to GRAS about your pointer.
GRAS_ANNOTE takes two arguments being the key name and the key value. For now, the only accepted key name is "size", to specify the length of the pointed array. It can either be:
Here is an example:
GRAS_DEFINE_TYPE(s_clause, struct s_array { xbt_string_t name; struct s_array *father GRAS_ANNOTE(size,1); int length; int *data GRAS_ANNOTE(size,length); int rows; int cols; int *matrix GRAS_ANNOTE(size,rows*cols); } ;)
It specifies that the structure s_array contains six fields, that the name field is a classical null-terminated char* string (xbt_string_t is just an helper type defined exactly to help the parsing macro to specify the semantic of the pointer), that father field is a simple reference, that the size of the array pointed by data is the length field, and that the matrix field is an arraywhich size is the result of rows times cols.
int a, b;
int a; int b;
If you want to exchange arrays which size is given at compilation time by a #defined constant, you need to keep GRAS informed. It would be done the following way:
#define BLOCK_SIZE 32 GRAS_DEFINE_TYPE(s_toto, struct { double data[BLOCK_SIZE]; } s_toto;) void register_messages() { gras_datadesc_type_t toto_type; gras_datadesc_set_const("BLOCK_SIZE",BLOCK_SIZE); toto_type = gras_datadesc_by_symbol(s_toto); }
The form gras_datadesc_set_const("BLOCK_SIZE",BLOCK_SIZE);
ensures that when you change the definition of the constant, GRAS keeps informed of the right value. Passing the numerical value of the constant as second argument would be a bad idea to that regard. Of course, the call to gras_datadesc_set_const() should come before any gras_datadesc_by_symbol() containing references to it.
The mecanism for multidimensional arrays is known to be fragile and cumbersome. If you want to use it, you have to understand how it is implemented: the multiplication is performed using the sizes stack. In previous example, a gras_datadesc_cb_push_int callback is added to the rows field and a gras_datadesc_cb_push_int_mult one is added to cols. So, when the structure is sent, the rows field push its value onto the stack, then the cols field retrieve this value from the stack, compute (and push) the multiplication value. The matrix field can then retrieve this value by poping the array. There is several ways for this to go wrong:
If you cannot express your datadescs with this mechanism, you'll have to use the more advanced (and somehow complex) one described in the Data description with Callback Persistant State: Full featured interface.
GRAS_DEFINE_TYPE declares some symbols to work, it needs some special care when used in several files. In such case, you want the regular type definition in all files, but the gras specific symbol defined in only one file. For example, consider the following gras project sketch.
#include <gras.h> GRAS_DEFINE_TYPE(my_type,struct my_type { int a; int b; double c; }); int client(int argc, char *argv[]) { ... } int server(int argc, char *argv[]) { ... }
If you want to split this in two files (one for each kind of processes), you need to put the GRAS_DEFINE_TYPE block in a separate header (so that each process kind see the associated C type definition). But then you cannot include this right away in all files because the extra symbols containing the GRAS definition would be dupplicated.
You thus have to decide in which C file the symbols will live. In that file, include the header without restriction:
#include "my_header.h" int client(int argc, char *argv[]) { ... }
And in the other files needing the C definitions without the extra GRAS symbols, declare the symbol GRAS_DEFINE_TYPE_EXTERN before loading gras.h:
#define GRAS_DEFINE_TYPE_EXTERN #include <gras.h> #include "my_header.h" int server(int argc, char *argv[]) { ... }
Sometimes, the situation is even more complicated: There is some shared messages that you want to see from every file, and some private messages that you want to be defined only in one C file. In that case, use the previous trick for common messages, and use GRAS_DEFINE_TYPE_LOCAL for the private messages.
For now, there is no way to have semi-private symbols (for example shared in all files of a library), sorry. Use functions as interface to your library instead of publishing directly the messages.
#define GRAS_DEFINE_TYPE_LOCAL | ( | name, | |
def | |||
) |
Define a symbol to be automatically parsed, disregarding GRAS_DEFINE_TYPE_EXTERN.
Call this macro instead of GRAS_DEFINE_TYPE if you had to define GRAS_DEFINE_TYPE_EXTERN to load some external symbols, but if you now want to automatically parse the content of your private messages.
Back to the main Simgrid Documentation page |
The version of Simgrid documented here is v3.6.1. Documentation of other versions can be found in their respective archive files (directory doc/html). |
Generated for SimGridAPI by
![]() |