Writing a C actor¶
You need an editor (vi, emacs,...), a compiler (gcc) and the API described further. You can use library example available in Narval generic actor sources as skeleton for your code. (or this example https://forge.in2p3.fr/attachments/download/1274/narval.lib.examples.tgz)
Topology informations¶
In the topology file you need to use as binary_code : generic_consumer, generic_producer or generic_filter.
Here is an example of a topology using the three type of generic actors:
<configuration>
<producer>
<name>data_transmitter</name>
<hostname>localhost</hostname>
<binary_code>generic_producer</binary_code>
<output_buffer_name>data</output_buffer_name>
<size output_buffer="data">1_000_000</size>
<port output_buffer="data">fifo</port>
<log_level>info</log_level>
</producer>
<intermediary input_buffers="1" output_buffers="1">
<name>data_filter</name>
<hostname>localhost</hostname>
<binary_code>generic_filter</binary_code>
<data_source source_port="fifo" source_buffer="data">data_transmitter</data_source>
<output_buffer_name>data_filtered</output_buffer_name>
<size output_buffer="data_filtered">1_000_000</size>
<port output_buffer="data_filtered">fifo</port>
</intermediary>
<consumer>
<name>data_receiver</name>
<hostname>localhost</hostname>
<binary_code>generic_consumer</binary_code>
<data_source source_port="fifo" source_buffer="data_filtered">data_filter</data_source>
<debug>info</debug>
</consumer>
</configuration>
see Configuration Files pages for more information.
Loading in Narval¶
You can use this script to launch your actors:
launch mysubsystem localhost set configuration_file mytopology.xml mysubsystem set action configure mysubsystem set action load mysubsystem set action initialise mysubsystem set action start mysubsystem
but you need to add the library load:
set library libproduce.so $1 data_transmitter set library libfilter.so $1 data_filter set library libconsume.so $1 data_receiver
If the "set library" are in a script named like the topology file it will be automatically load during the load action! In our example the script have to be named mytopology.
Linking C library with Narval actor¶
You can use this Makefile:
CC=gcc
CFLAGS=-Wall -Iinclude -fPIC
libs:libproducer.so libfilter.so libconsumer.so
%.so: %.o
$(CC) -o $@ -shared $<
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
We assume that you want to compile a producer named libproducer.c, a filter named libfilter.c and a consumer libconsumer.c
API for C actor¶
This API is based on John Cresswell and Xavier Grave document : AGATA PSA and Tracking Algorithm Integration.
C consumer¶
void process_block (struct my_struct *algo_data,
void *input_buffer,
unsigned int size_of_input_buffer,
unsigned int *error_code);
The process_block function will be called when an incoming data block is received and requires processing. The algorithm code must use the argument values given on entry for buffer pointers and not keep values in local variables between calls. The size arguments are all in units of bytes.
The function needs to return a valid value in error_code.
C producer¶
void process_block (struct my_struct *algo_data,
void *output_buffer,
unsigned int size_of_output_buffer,
unsigned int *used_size_of_output_buffer,
unsigned int *error_code);
The process_block function will be called in loop between the commands start and stop. The algorithm code must use the argument values given on entry for buffer pointers and not keep values in local variables between calls. The size arguments are all in units of bytes.
The function needs to return the updated value of used_size_of_output_buffer, and error_code.
C intermediary¶
void process_block (struct my_struct *algo_data,
void *input_buffer,
unsigned int size_of_input_buffer,
void *output_buffer,
unsigned int size_of_output_buffer,
unsigned int *used_size_of_output_buffer,
unsigned int *error_code);
The process_block function will be called when an incoming data block is received and requires processing. The algorithm code must use the argument values given on entry for buffer pointers and not keep values in local variables between calls. The size arguments are all in units of bytes.
The function needs to return the updated value of used_size_of_output_buffer, and error_code.
Common API for producers, consumers and filters¶
void process_config (char *directory_path, unsigned int *error_code);
The process_config function will be called once by the system before any other calls. It will supply a directory path argument specifying where config data is to be found. This value should be stored locally for use by all multi-processing threads. Since configuration data is likely to be very memory hungry, it will be necessary to load only one copy of read-only data per multi-processing motherboard, and share the data with all running algorithm processes. This routine has the responsibility to read all necessary config data that is read-only into local arrays. The process_config function call must return a valid value in error_code.
struct my_struct{int id;};
struct my_struct *process_register (unsigned int *error_code);
The process_register function will be called by the system once only at program load time for each algorithm process instance. It has to return a pointer to a data struct that the user defines. The only requirement for the data struct is that the first element be defined as the id of the execution instance. This struct pointer is then provided as the first argument of each of the following function calls. It allows instance-specific data to be remembered and passed to each function call. The struct may contain any variable that the algorithm routines need.
The process_register function call must return a valid value in error_code.
void process_initialise (struct my_struct *algo_data,
unsigned int *error_code);
The process_initialise function will be called once per instance every time an initialisation of the loaded program is required. After the initial process_initialise function call, any further call will follow a process_reset function call.The process_initialise function call must return a valid value in error_code.
Optional common API for producers, consumers and filters¶
void process_reset (struct my_struct *algo_data,
unsigned int *error_code);
The process_reset function will be called once per instance every time the system needs to be returned to a state ready for initialisation. The process_reset function call must return a valid value in error_code.
void process_start (struct my_struct *algo_data,
unsigned int *error_code);
The process_start function will be called once per instance every time the system starts data acquisition The process_start function call must return a valid value in error_code.
void process_stop (struct my_struct *algo_data,
unsigned int *error_code);
The process_stop function will be called once per instance every time the system stops data acquisition The process_stop function call must return a valid value in error_code.
void process_pause (struct my_struct *algo_data,
unsigned int *error_code);
The process_pause function will be called once per instance every time the system pauses data acquisition The process_pause function call must return a valid value in error_code.
void process_resume (struct my_struct *algo_data,
unsigned int *error_code);
The process_resume function will be called once per instance every time the system resumes data acquisition after a pause. The process_resume function call must return a valid value in error_code.
void process_unload (struct my_struct *algo_data,
unsigned int *error_code);
The process_unload function will be called once per instance every time the system requests exit of the algorithm library code The process_unload function call must return a valid value in error_code.