In order to allow GRAS to send data over the network (or simply to
dupplicate it in SG), you have to describe the structure of data attached
with each message. This mecanism is stolen from NWS message passing
interface.
For each message, you have to declare a structure representing the
data to send as payload with the message.
Sending (or receiving) simple structures
Let's imagin you want to declare a STORE_STATE
message, which will send some data to the memory server for inclusion in
the database. Here is the structure we want to send:
struct state {
char id[STATE_NAME_SIZE];
int rec_size;
int rec_count;
double seq_no;
double time_out;
};
And here is the structure description GRAS needs to be able to send
this over the network:
const static DataDescriptor stateDescriptor[] =
{SIMPLE_MEMBER(CHAR_TYPE, STATE_NAME_SIZE, offsetof(struct state, id)),
SIMPLE_MEMBER(INT_TYPE, 1, offsetof(struct state, rec_size)),
SIMPLE_MEMBER(INT_TYPE, 1, offsetof(struct state, rec_count)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(struct state, seq_no)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(struct state, time_out))};
Contrary to what one could think when you first see it, it's pretty
easy. A structure descriptor is a list of descriptions, describing each
field of the structure. For example, for the first field, you say that
the base type is CHAR_TYPE, that there is
STATE_NAME_SIZE element of this type and that it's
position in the structure is computed by offsetof(struct state,
id). This leads to two remarks:
it's impossible to send dynamic sized strings that way. It's a
known limitation, but I think we can live with it.
Yes, the offsetof(struct state, id)
construction is C ANSI and is portable.
Sending (or receiving) complex structure
How to send non-flat structures, do you ask? It's not harder. Let's
imagin you want to send the following structure:
typedef struct {
unsigned long address;
unsigned long port;
} CliqueMember;
typedef struct {
char name[MAX_CLIQUE_NAME_SIZE];
double whenGenerated;
double instance;
char skill[MAX_SKILL_SIZE];
char options[MAX_OPTIONS_SIZE];
double period;
double timeOut;
CliqueMember members[MAX_MEMBERS];
unsigned int count;
unsigned int leader;
} Clique;
As you can see, this structure contains an array of another user
defined structure. To be able to send struct Clique,
you have to describe each structures that way:
static const DataDescriptor cliqueMemberDescriptor[] =
{SIMPLE_MEMBER(UNSIGNED_LONG_TYPE, 1, offsetof(CliqueMember, address)),
SIMPLE_MEMBER(UNSIGNED_LONG_TYPE, 1, offsetof(CliqueMember, port))};
static const DataDescriptor cliqueDescriptor[] =
{SIMPLE_MEMBER(CHAR_TYPE, MAX_CLIQUE_NAME_SIZE, offsetof(Clique, name)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(Clique, whenGenerated)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(Clique, instance)),
SIMPLE_MEMBER(CHAR_TYPE, MAX_SKILL_SIZE, offsetof(Clique, skill)),
SIMPLE_MEMBER(CHAR_TYPE, MAX_OPTIONS_SIZE, offsetof(Clique, options)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(Clique, period)),
SIMPLE_MEMBER(DOUBLE_TYPE, 1, offsetof(Clique, timeOut)),
{STRUCT_TYPE, MAX_MEMBERS, offsetof(Clique, members),
(DataDescriptor *)&cliqueMemberDescriptor, cliqueMemberDescriptorLength,
PAD_BYTES(CliqueMember, port, unsigned long, 1)},
SIMPLE_MEMBER(UNSIGNED_INT_TYPE, 1, offsetof(Clique, count)),
SIMPLE_MEMBER(UNSIGNED_INT_TYPE, 1, offsetof(Clique, leader))};
So, even if less natural, it is possible to send structures
containing structures with these tools.
You can see that it's not only impossible to send dynamic-sized
strings, it impossible to send dynamic-sized arrays. Here,
MAX_MEMBERS is the maximum of members a clique can
contain. In NWS, this value is defined to 100. I'm not
sure, but I think that all the 100 values are sent each time, even if
there is only 3 non-null members. Yes, that's
bad.
The DataDescriptor_t MUST be const. Malloc'ing them and
then casting them on argument passing IS NOT OK. This is because we get
the number of elements in the array with the sizeof(dd)/sizeof(dd[0]).
Describing the data
DataDescriptor API
Dynamic arrays
ErrLog
Handling sockets
Sockets API
comm_callbacks
comm_cb
Advanced ways to describe data (for experts)
Advanced Data description
Data description callbacks persistant state
config
Data description callbacks persistant state
Implementation of data description
dico
This module provide the quite usual dynamic array facility.
Dynamic array
dynar
This document introduce the GRAS library (Grid Reality
And Simulation, or according to my english dictionary,
Generally Recognized As Safe ;).
Overview
The purpose of the GRAS is to allow the developpement of
distributed programs which will work with as few as possible
modification both on the SimGrid simulator (SG), and in the Real Life
(RL).
Here are the problems when you want to do so:
Communication in SG is done by passing tasks, while in
RL, you have to deal with sockets (or any wrapper to it).
In RL, each process should provide a main()
function, and it's obviously not the case in SG.
Application class target
If you want to run your code both in RL and in SG, you won't be
able to use the full set of features offered by any of those two
worlds. GRAS tries to provide a suffisent set of features to develop
your application, and implement them in both worlds.
GRAS uses the paradigm of event-driven
programming, which is an extension to the message-passing
one. Any process of a typical event-driven application declares
callback to incoming events, which can be messages from other
processes, timers or others.
All messages have an header, specifying its type, and attached
data, represented as one or several C structures. In order to send
the data over the network in RL, a type-description mecanism is
provided, and the RL version of GRAS implements CDR
functionnalities. That is to say that the data are sent in the native
format of the sender host, and converted on the destination host only
if needed.
In order to not reimplement the wheel, GRAS use existing code,
and adapt them to make them work together. The SG version naturally
use the SimGrid toolkit, while the RL version is based over the
communication library used in NWS (note that this library was somehow
modified, since the previous version use XDR, ie both the sender and
the receiver convert the data from/to a so called network
format). That's why some basic knowledge about how NWS work is
supposed in this document. But don't worry, you only have to know the
basics about NWS, the internals needed to understand the document
will be presented when needed.
Overview of the GRAS library
Overview
./gras-sections.txt.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml
./gras-sections.txt.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml
./gras-sections.txt.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml
./gras-sections.txt.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml
./gras-sections.txt.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml
./gras-sections.txt.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml
./gras-sections.txt.sgml.sgml.sgml.sgml.sgml.sgml.sgml
./gras-sections.txt.sgml.sgml.sgml.sgml.sgml.sgml
./gras-sections.txt.sgml.sgml.sgml.sgml.sgml
./gras-sections.txt.sgml.sgml.sgml.sgml
./gras-sections.txt.sgml.sgml.sgml
./gras-sections.txt.sgml.sgml
./gras-sections.txt.sgml
./gras-sections.txt
gras
gras_private
Implementation of GRAS suited for real life.
RL
SimGrid was designed to ease the comparison of algorithms and
heuristics. That way, a lot of complicated notion from the system layer
were volontary left off. For example, migrating a process from an host to
another is as easy as: MSG_process_change_host(process, new_host).
No need to tell that performing this operation on real platform is really
harder. This simplification is a very good thing when you want to rapidly
prototype code, but makes things somehow more complicated in GRAS since
we want to have a realistic API, since it have to be implemented in
reality also.
The best example of complexity in GRAS_SG induced by simplicity in
SimGrid is the sockets handling. There is no "socket" in SG, but only
m_channel_t. In contrary to sockets from RL, no special treatment is
needed for a process before writing or reading on/from a channel. So, a
given channel can be pooled by more than one process. Likewise, you can
send data to a channel that nobody is actually listening to.
The SG implementation of GRAS repport as an error the fact that nobody is
listening to the socket when trying to open a socket, or send stuff using
a previously openned socket. That way, the SG version can be used to
debug all syncronization issues. For that, we store mainly the PID of
both the sender and the receiver in the socket structure, and then
resolve PID->process at the lastest moment. This search is a bit
expensive, but as long as there is no real garbage collection in SG, with
the information "dead process" within the structure, it's the only
solution to make sure that we won't dereference pointers to an old freed
structure when the process on the other side of the structure did finish
since the creation of the socket.
As said in the overview, the processes can declare to hear on several
sockets, but all incoming messages are handled by the same loop. So, we
can use only one channel per process, and use a table on each host to
determine to which process a message should be delivered depending on the
socket number provided by the sender.
RL, the implementation suited for real life.
Implementation of GRAS on top of the simulator.
SG
nws_comm
Configuration facilities.
Config
Data container associating data to a string key.
Dictionnary
This module provide the quite usual dynamic array facility.
Use arrays, forget about malloc
Dynamic array
Error reporting
Errors handling
This is an adaptation of the log4c project, which is dead upstream, and which
I was given the permission to fork under the LGPL licence by the authors. log4c
itself was loosely based on the Apache project's Log4J, Log4CC,
etc. project. Because C is not object oriented, a lot had to change.
Overview
There is 3 main concepts: category, priority and appender. These three
concepts work together to enable developers to log messages according to
message type and priority, and to control at runtime how these messages are
formatted and where they are reported.
Category hierarchy
The first and foremost advantage of any logging API over plain printf()
resides in its ability to disable certain log statements while allowing
others to print unhindered. This capability assumes that the logging space,
that is, the space of all possible logging statements, is categorized
according to some developer-chosen criteria.
This observation led to choosing category as the central concept of the
system. Every category is declared by providing a name and an optional
parent. If no parent is explicitly named, the root category, LOG_ROOT_CAT
is the category's parent.
A category is created by a macro call at the top level of a file. A
category can be created with any one of the following macros:
@GRAS_LOG_NEW_CATEGORY(MyCat);
create a new root
@GRAS_LOG_NEW_SUBCATEGORY(MyCat, ParentCat);
Create a new category being child of the category ParentCat
@GRAS_LOG_NEW_DEFAULT_CATEGORY(MyCat);
Like GRAS_LOG_NEW_CATEGORY, but the new category is the default one
in this file
@GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(MyCat, ParentCat);
Like GRAS_LOG_NEW_SUBCATEGORY, but the new category is the default one
in this file
The parent cat can be defined in the same file or in another file, but each
category may have only one definition.
Typically, there will be a Category for each module and sub-module, so you
can independently control logging for each module.
Priority
A category may be assigned a threshold priorty. The set of priorites are
defined by the @gras_log_priority_t enum. Their values are DEBUG, VERBOSE,
INFO, WARNING, ERROR and CRITICAL.
If a given category is not assigned a threshold priority, then it inherits
one from its closest ancestor with an assigned threshold.
To ensure that all categories can eventually inherit a threshold, the root
category always has an assigned threshold priority.
Logging requests are made by invoking a logging macro on a category. All
of the macros have a printf-style format string followed by arguments.
Because most C compilers do not support vararg macros, there is a version
of the macro for any number of arguments from 0 to 6. The macro name ends
with the total number of arguments.
Here is an example of the most basic type of macro:
CLOG5(MyCat, gras_log_priority_warning, "Values are: %d and '%s'", 5, "oops");
This is a logging request with priority WARN.
A logging request is said to be enabled if its priority is higher than or
equal to the threshold priority of its category. Otherwise, the request is
said to be disabled. A category without an assigned priority will inherit
one from the hierarchy.
It is possible to use any non-negative integer as a priority. If, as in the
example, one of the standard priorites is used, then there is a convenience
macro that is typically used instead. For example, the above example is
equivalent to the shorter:
CWARN4(MyCat, "Values are: %d and '%s'", 5, "oops");
Default category
If @GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(MyCat, Parent) or
@GRAS_LOG_NEW_DEFAULT_CATEGORY(MyCat) is used to create the category, then
the even shorter form can be used:
WARN3("Values are: %d and '%s'", 5, "oops");
Only one default category can be created per file, though multiple
non-defaults can be created and used.
Example
Here is a more complete example:
#include "gras.h"
/* create a category and a default subcategory */
GRAS_LOG_NEW_CATEGORY(VSS);
GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(SA, VSS);
main() {
/* Now set the parent's priority.
(the string would typcially be a runtime option) */
gras_log_control_set("SA.thresh=3");
/* This request is enabled, because WARNING >= INFO. */
CWARN2(VSS, "Low fuel level.");
/* This request is disabled, because DEBUG < INFO. */
CDEBUG2(VSS, "Starting search for nearest gas station.");
/* The default category SA inherits its priority from VSS. Thus,
the following request is enabled because INFO >= INFO. */
INFO1("Located nearest gas station.");
/* This request is disabled, because DEBUG < INFO. */
DEBUG1("Exiting gas station search");
}
Configuration
Configuration is typically done during program initialization by invoking
the gras_log_control_set() method. The control string passed to it
typically comes from the command line. Look at the doucmentation for that
function for the format of the control string.
Performance
Clever design insures efficiency. Except for the first invocation, a
disabled logging request requires an a single comparison of a static
variable to a constant.
There is also compile time constant, @GRAS_LOG_STATIC_THRESHOLD, which
causes all logging requests with a lower priority to be optimized to 0 cost
by the compiler. By setting it to gras_log_priority_infinite, all logging
requests are statically disabled and cost nothing. Released executables
might typically be compiled with
"-DGRAS_LOG_STATIC_THRESHOLD=gras_log_priority_infinite".
Appenders
Each category has an optional appender. An appender is a pointer to a
structure whcih starts with a pointer to a doAppend() function. DoAppend()
prints a message to a log.
WHen a category is passed a message by one of the logging macros, the
category performs the following actions:
if the category has an appender, the message is passed to the
appender's doAppend() function,
if 'willLogToParent' is true for the category, the message is passed
to the category's parent.
By default, all categories except root have no appender and
'willLogToParent' is true. This situation causes all messages to be
logged by the root category's appender.
Typically, you would only change the root category's appender when you
wanted, say, a different output format. Copying defaultLogAppender.c
would be a good start.
The default appender function currently prints to stderr, but more
would be needed, like the one able to send the logs to a remote
dedicated server.
Misc and Caveats
Do not use any of the macros that start with '_'.
The current set of macros force each file to use categories declared in
that file. This is intentional. Make the category a child of the file's
module category.
Log4J has a 'rolling file appender' which you can select with a run-time
option and specify the max file size. This would be a nice default for
non-kernel applications.
Careful, category names are global variables.
An easy-to-use, fast and flexible message logging architecture.
Logging facilities
Data storage for very quick retrieve
Data set
Sockets
xbt_cfg
xbt_dico
Errors
xbt_swag.sgml.sgml.sgml.sgml.sgml.sgml.sgml.sgml
xbt_swag.sgml.sgml.sgml.sgml.sgml.sgml.sgml
xbt_swag.sgml.sgml.sgml.sgml.sgml.sgml
xbt_swag.sgml.sgml.sgml.sgml.sgml
xbt_swag.sgml.sgml.sgml.sgml
xbt_swag.sgml.sgml.sgml
xbt_swag.sgml.sgml
xbt_swag.sgml
@c:
@f:
@c:
@f:
@a1:
@c:
@f:
@a1:
@a2:
@c:
@f:
@a1:
@a2:
@a3:
@c:
@f:
@a1:
@a2:
@a3:
@a4:
@c:
@f:
@a1:
@a2:
@a3:
@a4:
@a5:
@c:
@f:
@c:
@f:
@a1:
@c:
@f:
@a1:
@a2:
@c:
@f:
@a1:
@a2:
@a3:
@c:
@f:
@a1:
@a2:
@a3:
@a4:
@c:
@f:
@a1:
@a2:
@a3:
@a4:
@a5:
@c:
@f:
@c:
@f:
@a1:
@c:
@f:
@a1:
@a2:
@c:
@f:
@a1:
@a2:
@a3:
@c:
@f:
@a1:
@a2:
@a3:
@a4:
@c:
@f:
@a1:
@a2:
@a3:
@a4:
@a5:
@c:
@f:
@c:
@f:
@a1:
@c:
@f:
@a1:
@a2:
@c:
@f:
@a1:
@a2:
@a3:
@c:
@f:
@a1:
@a2:
@a3:
@a4:
@c:
@f:
@a1:
@a2:
@a3:
@a4:
@a5:
@c:
@p:
@f:
@c:
@p:
@f:
@a1:
@c:
@p:
@f:
@a1:
@a2:
@c:
@p:
@f:
@a1:
@a2:
@a3:
@c:
@p:
@f:
@a1:
@a2:
@a3:
@a4:
@c:
@p:
@f:
@a1:
@a2:
@a3:
@a4:
@a5:
@c:
@p:
@f:
@a1:
@a2:
@a3:
@a4:
@a5:
@a6:
@f:
@f:
@a1:
@f:
@a1:
@a2:
@f:
@a1:
@a2:
@a3:
@f:
@a1:
@a2:
@a3:
@a4:
@f:
@a1:
@a2:
@a3:
@a4:
@a5:
@c:
@f:
@a1:
@a2:
@a3:
@a4:
@a5:
@a6:
@addr:
@Param2:
@sock:
@timeOut:
@Returns:
@sock:
@waitForPeer:
@Returns:
@destination:
@source:
@description:
@length:
@sourceFormat:
@pid:
@parentToChild:
@childToParent:
@Returns:
@sock:
@Returns:
@description:
@length:
@format:
@Returns:
@CHAR_TYPE:
@DOUBLE_TYPE:
@FLOAT_TYPE:
@INT_TYPE:
@LONG_TYPE:
@SHORT_TYPE:
@UNSIGNED_INT_TYPE:
@UNSIGNED_LONG_TYPE:
@UNSIGNED_SHORT_TYPE:
@STRUCT_TYPE:
@LAST_TYPE:
@whatType:
@Returns:
@Returns:
@whatType:
@Returns:
@Param1:
@Param2:
@ear:
@earPort:
@Returns:
@HOST_FORMAT:
@NETWORK_FORMAT:
@cname:
@cname:
@catName:
@priority:
@catName:
@desc:
@cname:
@desc:
@cname:
@parent:
@desc:
@catName:
@parent:
@desc:
@destination:
@source:
@whatType:
@repetitions:
@sourceFormat:
@whatType:
@repetitions:
@format:
@Returns:
@addr:
@Returns:
@addr:
@Returns:
@addr:
@Returns:
@addr:
@Returns:
@machineOrAddress:
@address:
@machineOrAddress:
@addressList:
@atMost:
@Returns:
@timeOut:
@sd:
@ldap:
@Returns:
@sd:
@Returns:
@sd:
@Returns:
@machineOrAddress:
@p:
@f:
@a1:
@a2:
@a3:
@a4:
@a5:
@a6:
@Returns:
@notifyFn:
@addr:
@Param2:
@sock:
@Returns:
@Param1:
@Param2:
@ear:
@earPort:
@Returns:
@structType:
@lastMember:
@memberType:
@repetitions:
@sock:
@child:
@Returns:
@sd:
@Returns:
@sd:
@Returns:
@sd:
@Returns:
@destination:
@source:
@whatType:
@repetitions:
@format:
@type:
@repetitions:
@type:
@repetitions:
@offset:
@sig:
@Param1:
@sd:
@Returns:
@sd:
@Returns:
@f:
@a1:
@a2:
@a3:
@a4:
@a5:
@a6:
@sd:
@msgType:
@vdata:
@sock:
@Returns:
@dd1:
@c1:
@dd2:
@c2:
@Returns:
@description:
@description:
@Returns:
@sd:
@data:
@description:
@description_length:
@repetition:
@Returns:
@sd:
@data:
@description:
@description_length:
@repetition:
@Returns:
@description:
@ft:
@Returns:
@no_error:
@malloc_error:
@mismatch_error:
@sanity_error:
@system_error:
@network_error:
@timeout_error:
@thread_error:
@unknown_error:
@Returns:
@sd:
@size:
@id:
@Returns:
@msg:
@timeOut:
@msgId:
@dataSize:
@seqCount:
@Returns:
@msgId:
@free_data_on_free:
@seqCount:
@Varargs:
@Returns:
@msg:
@timeout:
@Returns:
@sd:
@message:
@name:
@sequence_count:
@Varargs:
@Returns:
@sd:
@message:
@sequence_count:
@Varargs:
@Returns:
@sd:
@timeout:
@message:
@sequence_count:
@Varargs:
@Returns:
@Returns:
@host:
@Param2:
@sock:
@Returns:
@Param1:
@Param2:
@sock:
@Returns:
@sd:
@Returns:
@sd:
@Returns:
@sd:
@data:
@description:
@Returns:
@message:
@TTL:
@cb:
@sd:
@data:
@description:
@Returns:
@Returns:
@type:
@ud:
@cfg:
@Returns:
@tocopy:
@whereto:
@Returns:
@name:
@indent:
@cfg:
@cfg:
@name:
@Returns:
@cfg:
@cfg:
@name:
@val:
@Returns:
@cfg:
@name:
@dynar:
@Returns:
@cfg:
@name:
@host:
@port:
@Returns:
@cfg:
@name:
@val:
@Returns:
@cfg:
@name:
@val:
@Returns:
@Returns:
@whereto:
@cfg:
@name:
@type:
@min:
@max:
@Returns:
@cfg:
@entry:
@Returns:
@cfg:
@name:
@val:
@Returns:
@cfg:
@name:
@host:
@port:
@Returns:
@cfg:
@name:
@val:
@Returns:
@cfg:
@name:
@val:
@Returns:
@cfg:
@Varargs:
@Returns:
@cfg:
@name:
@val:
@Returns:
@cfg:
@name:
@host:
@port:
@Returns:
@cfg:
@name:
@val:
@Returns:
@cfg:
@options:
@Returns:
@cfg:
@name:
@val:
@Returns:
@cfg:
@pa:
@Returns:
@type:
@post:
@type:
@pre:
@d1:
@d2:
@Returns:
@dd1:
@c1:
@dd2:
@c2:
@dd:
@c:
@data:
@name:
@elm_type:
@size:
@code:
@name:
@element_type:
@fixed_size:
@dynamic_size:
@post:
@code:
@Returns:
@name:
@element_type:
@dynamic_size:
@dst:
@Returns:
@elm_type:
@code:
@name:
@element_type:
@fixed_size:
@dst:
@Returns:
@name:
@referenced_type:
@dst:
@Returns:
@ref_type:
@code:
@name:
@referenced_type:
@discriminant:
@post:
@code:
@Returns:
@name:
@discriminant:
@code:
@name:
@discriminant:
@dst:
@Returns:
@name:
@dst:
@Returns:
@code:
@struct_code:
@field_name:
@field_type_code:
@struct_code:
@field_name:
@field_code:
@pre_cb:
@post_cb:
@Returns:
@struct_code:
@field_name:
@field_type_name:
@struct_code:
@field_name:
@field_type_name:
@pre_cb:
@post_cb:
@Returns:
@struct_type:
@name:
@field_type:
@Returns:
@struct_type:
@name:
@field_type_name:
@Returns:
@name:
@pre_cb:
@post_cb:
@code:
@Returns:
@struct_type:
@name:
@selector:
@dst:
@Returns:
@code:
@union_code:
@field_name:
@field_type_code:
@union_code:
@field_name:
@field_code:
@pre_cb:
@post_cb:
@Returns:
@union_code:
@field_name:
@field_type_name:
@union_code:
@field_name:
@field_type_name:
@pre_cb:
@post_cb:
@Returns:
@union_type:
@name:
@field_type:
@Returns:
@union_type:
@name:
@field_type_name:
@Returns:
@name:
@field_count:
@post:
@code:
@Returns:
@union_type:
@name:
@desc:
@howmany:
@code:
@Returns:
@dst:
@name:
@desc:
@howmany:
@dst:
@Returns:
@name:
@Cdefinition:
@dst:
@Returns:
@code:
@def:
@ps:
@ps:
@ps:
@name:
@ddt:
@ps:
@name:
@ddt:
@ps:
@name:
@data:
@ddt:
@ps:
@name:
@data:
@ddt:
@type:
@code:
@type:
@Returns:
@name:
@type:
@Returns:
@name:
@element_type:
@fixed_size:
@dynamic_size:
@post:
@dst:
@Returns:
@name:
@desc:
@howmany:
@dst:
@Returns:
@name:
@default_value:
@free_func:
@size:
@alignment:
@post:
@dst:
@Returns:
@name:
@C_definition:
@dst:
@Returns:
@name:
@referenced_type:
@discriminant:
@post:
@dst:
@Returns:
@name:
@type:
@Returns:
@name:
@pre:
@post:
@dst:
@Returns:
@struct_type:
@name:
@field_type:
@pre:
@post:
@Returns:
@name:
@field_count:
@post:
@dst:
@Returns:
@union_type:
@name:
@field_type:
@pre:
@post:
@Returns:
@type:
@Returns:
@cursor:
@Returns:
@cursor:
@data:
@Returns:
@cursor:
@key:
@Returns:
@head:
@Returns:
@cursor:
@cursor:
@Returns:
@cursor:
@Returns:
@head:
@output:
@Returns:
@dict:
@cursor:
@key:
@data:
@dict:
@Returns:
@head:
@key:
@data:
@Returns:
@head:
@key:
@key_len:
@data:
@Returns:
@head:
@key:
@data:
@free_ctn:
@Returns:
@head:
@key:
@key_len:
@data:
@free_ctn:
@Returns:
@Returns:
@dict:
@data:
@data:
@head:
@key:
@Returns:
@head:
@key:
@key_len:
@Returns:
@head:
@key:
@data:
@Returns:
@head:
@key:
@key_len:
@data:
@Returns:
@head:
@key:
@data:
@free_ctn:
@Returns:
@head:
@key:
@key_len:
@data:
@free_ctn:
@Returns:
@dynar:
@cursor:
@dynar:
@cursor:
@whereto:
@Returns:
@dynar:
@cursor:
@dynar:
@cursor:
@dynar:
@cursor:
@Returns:
@_dynar:
@_cursor:
@_data:
@_whereto:
@dynar:
@Returns:
@dynar:
@Returns:
@dynar:
@idx:
@dst:
@whereto:
@Returns:
@dynar:
@idx:
@src:
@Returns:
@object:
@dynar:
@Returns:
@dynar:
@operator:
@Returns:
@Param1:
@free_func:
@Returns:
@whereto:
@elm_size:
@dynar:
@cursor:
@whereto:
@Returns:
@dynar:
@dst:
@whereto:
@dynar:
@src:
@Returns:
@object:
@dynar:
@idx:
@object:
@Returns:
@dynar:
@idx:
@object:
@Returns:
@dynar:
@Returns:
@dynar:
@idx:
@src:
@Returns:
@object:
@dynar:
@dst:
@whereto:
@Returns:
@dynar:
@src:
@Returns:
@object:
@no_error: no error
@mismatch_error: Not found
@system_error: a syscall did fail
@network_error: error while sending/receiving data
@timeout_error: not quick enough, dude
@thread_error: error while [un]locking
@unknown_error: no idea
@Returns:
@cat:
@app:
@cs:
@Returns:
@cat:
@parent:
@gras_log_priority_none:
@gras_log_priority_trace:
@gras_log_priority_debug:
@gras_log_priority_verbose:
@gras_log_priority_info:
@gras_log_priority_warning:
@gras_log_priority_error:
@gras_log_priority_critical:
@gras_log_priority_infinite:
@gras_log_priority_uninitialized:
@cat:
@thresholdPriority:
@sd:
@size:
@msg:
@msgId:
@free_data_on_free:
@seqCount:
@Varargs:
@Returns:
@msgId:
@name:
@sequence_count:
@Varargs:
@Returns:
@set:
@elm:
@free_func:
@Returns:
@set:
@cursor:
@elm:
@set:
@set:
@id:
@dst:
@Returns:
@set:
@key:
@dst:
@Returns:
@set:
@name:
@name_len:
@dst:
@Returns:
@Returns:
@dst:
@Param1:
@Param2:
@host:
@Param2:
@sock:
@Returns:
@sock:
@Returns:
@sd:
@Returns:
@sd:
@Returns:
@Param1:
@Param2:
@sock:
@Returns:
@Returns:
@Returns:
@no_error:
@mismatch_error:
@system_error:
@network_error:
@timeout_error:
@thread_error:
@unknown_error:
@remote_mismatch_error:
@remote_system_error:
@remote_network_error:
@remote_timeout_error:
@remote_thread_error:
@remote_unknown_error: