reactor-c
C Runtime for Lingua Franca
Loading...
Searching...
No Matches
pythontarget.c File Reference
#include "pythontarget.h"
#include "modal_models/definitions.h"
#include "platform.h"
#include "python_action.h"
#include "python_port.h"
#include "python_tag.h"
#include "python_time.h"
#include "reactor.h"
#include "tag.h"
#include "util.h"
#include "environment.h"
#include "api/schedule.h"

Functions

PyObject * py_schedule (PyObject *self, PyObject *args)
 
PyObject * py_schedule_copy (PyObject *self, PyObject *args)
 
int lf_reactor_c_main (int argc, const char *argv[])
 
void lf_request_stop (void)
 Request a stop to execution as soon as possible.
 
PyObject * py_request_stop (PyObject *self, PyObject *args)
 
PyObject * py_source_directory (PyObject *self, PyObject *args)
 Return the source directory path (where the main .lf file is) as a string.
 
PyObject * py_package_directory (PyObject *self, PyObject *args)
 Return the root project directory path as a string.
 
const char ** _lf_py_parse_argv_impl (PyObject *py_argv, size_t *argc)
 
void py_initialize_interpreter (void)
 Initialize the Python interpreter if it hasn't already been.
 
PyObject * py_main (PyObject *self, PyObject *py_args)
 
PyMODINIT_FUNC GEN_NAME (PyInit_, MODULE_NAME)
 
void destroy_action_capsule (PyObject *capsule)
 
PyObject * convert_C_port_to_py (void *port, int width)
 
PyObject * convert_C_action_to_py (void *action)
 
PyObject * get_python_function (string module, string class, int instance_id, string func)
 
PyObject * load_serializer (string package_name)
 
PyObject * custom_serialize (PyObject *obj, PyObject *custom_serializer)
 
PyObject * custom_deserialize (PyObject *serialized_pyobject, PyObject *custom_serializer)
 

Variables

PyObject * globalPythonModule = NULL
 
PyObject * globalPythonModuleDict = NULL
 
PyObject * global_pickler = NULL
 
environment_ttop_level_environment = NULL
 

Detailed Description

Author
Soroush Bateni (sorou.nosp@m.sh@u.nosp@m.tdall.nosp@m.as.e.nosp@m.du)
Hou Seng Wong (house.nosp@m.ngw@.nosp@m.berke.nosp@m.ley..nosp@m.edu)

LICENSE

Copyright (c) 2022, The University of California at Berkeley. Copyright (c) 2021, The University of Texas at Dallas.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

DESCRIPTION

Implementation of functions defined in

See also
pythontarget.h

Function Documentation

◆ _lf_py_parse_argv_impl()

const char ** _lf_py_parse_argv_impl ( PyObject * py_argv,
size_t * argc )

Parse Python's 'argv' (from sys.argv()) into a pair of C-style 'argc' (the size of command-line parameters array) and 'argv' (an array of char* containing the command-line parameters).

This function assumes that argc is already allocated, and will fail if it isn't.

Parameters
py_argvThe returned value by 'sys.argv()'
argcWill contain an integer which is the number of arguments passed on the command line.
Returns
A list of char*, where each item contains an individual command-line argument.

◆ convert_C_action_to_py()

PyObject * convert_C_action_to_py ( void * action)

A helper function to convert C actions to Python action capsules

See also
xtext/org.icyphy.linguafranca/src/org/icyphy/generator/CGenerator.xtend for details about C actions Python actions have the following fields (for more informatino
generic_action_capsule_struct): PyObject_HEAD PyObject* action; PyObject* value; bool is_present;

The input to this function is a pointer to a C action, which might or might not contain a value and an is_present field. To simplify the assumptions made by this function, the "value" and "is_present" are passed to the function instead of expecting them to exist.

The void* pointer to the C action instance is encapsulated in a PyCapsule instead of passing an exposed pointer through Python.

See also
https://docs.python.org/3/c-api/capsule.html This encapsulation is done by calling PyCapsule_New(action, "name_of_the_container_in_the_capsule", NULL), where "name_of_the_container_in_the_capsule" is an agreed-upon container name inside the capsule. This capsule can then be treated as a PyObject* and safely passed through Python code. On the other end (which is in schedule functions), PyCapsule_GetPointer(received_action,"action") can be called to retrieve the void* pointer into received_action.

◆ convert_C_port_to_py()

PyObject * convert_C_port_to_py ( void * port,
int width )

A function that is called any time a Python reaction is called with ports as inputs and outputs. This function converts ports that are either a multiport or a non-multiport into a port_capsule.

First, the void* pointer is stored in a PyCapsule. If the port is not a multiport, the value and is_present fields are copied verbatim. These feilds then can be accessed from the Python code as port.value and port.is_present. If the value is absent, it will be set to None.

For multiports, the value of the port_capsule (i.e., port.value) is always set to None and is_present is set to false. Individual ports can then later be accessed in Python code as port[idx].

◆ custom_deserialize()

PyObject * custom_deserialize ( PyObject * serialized_pyobject,
PyObject * custom_serializer )

Deserialize Python object from a bytes object using external serializer

Parameters
serialized_pyobjectThe serialized bytes Python object
custom_serializerThe custom Serializer class
Returns
Deserialized Python object

◆ custom_serialize()

PyObject * custom_serialize ( PyObject * obj,
PyObject * custom_serializer )

Serialize Python object to a bytes object using external serializer

Parameters
objThe Python object to serialize
custom_serializerThe custom Serializer class
Returns
Serialized Python bytes object

◆ destroy_action_capsule()

void destroy_action_capsule ( PyObject * capsule)

Python Helper Functions These functions are called in generated C code for various reasons. Their main purpose is to facilitate C runtime's communication with Python code. A function that destroys action capsules

◆ GEN_NAME()

PyMODINIT_FUNC GEN_NAME ( PyInit_ ,
MODULE_NAME  )

◆ get_python_function()

PyObject * get_python_function ( string module,
string class,
int instance_id,
string func )

Invoke a Python func in class[instance_id] from module. Class instances in generated Python code are always instantiated in a list of template classs[_class(params), _class(params), ...] (note the extra s) regardless of whether a bank is used or not. If there is no bank, or a bank of width 1, the list will be instantiated as classs[_class(params)].

This function would thus call classs[0] to access the first instance in a bank and so on.

Possible optimizations include: - Not loading the module each time (by storing it in global memory),

  • Keeping a persistent argument table
    Parameters
    moduleThe Python module to load the function from. In embedded mode, it should be set to "__main__"
    classThe name of the list of classes in the generated Python code
    instance_idThe element number in the list of classes. class[instance_id] points to a class instance
    funcThe reaction functino to be called
    pArgsthe PyList of arguments to be sent to function func()
    Returns
    The function or NULL on error.

◆ lf_reactor_c_main()

int lf_reactor_c_main ( int argc,
const char * argv[] )

Prototype for the main function.

The main loop of the LF program.

An unambiguous function name that can be called by external libraries.

Note: In target languages that use the C core library, there should be an unambiguous way to execute the LF program's main function that will not conflict with other main functions that might get resolved and linked at compile time.

◆ lf_request_stop()

void lf_request_stop ( void )

Request a stop to execution as soon as possible.

Prototype for lf_request_stop().

See also
reactor.h

In a non-federated execution with only a single enclave, this will occur one microstep later than the current tag. In a federated execution or when there is more than one enclave, it will likely occur at a later tag determined by the RTI so that all federates and enclaves stop at the same tag.

◆ load_serializer()

PyObject * load_serializer ( string package_name)

Load the Serializer class from package name

Parameters
package_nameName of the python package to load
Returns
Initialized Serializer class

◆ py_initialize_interpreter()

void py_initialize_interpreter ( void )

Initialize the Python interpreter if it hasn't already been.

◆ py_main()

PyObject * py_main ( PyObject * self,
PyObject * py_args )

The main function of this Python module.

Parameters
py_argsA single object, which should be a list of arguments taken from sys.argv().

◆ py_package_directory()

PyObject * py_package_directory ( PyObject * self,
PyObject * args )

Return the root project directory path as a string.

Parameters
selfThe lf object.
argsEmpty.
Returns
PyObject* A Python string.

◆ py_request_stop()

PyObject * py_request_stop ( PyObject * self,
PyObject * args )

Stop execution at the conclusion of the current logical time.

◆ py_schedule()

PyObject * py_schedule ( PyObject * self,
PyObject * args )

Schedule an action to occur with the specified time offset with no payload (no value conveyed). This function is callable in Python by calling action_name.schedule(offset). Some examples include: action_name.schedule(5) action_name.schedule(NSEC(5)) See schedule_token(), which this uses, for details.

Parameters
selfPointer to the calling object.
argscontains:
  • action: Pointer to an action on the self struct.
  • offset: The time offset over and above that in the action.

◆ py_schedule_copy()

PyObject * py_schedule_copy ( PyObject * self,
PyObject * args )

Schedule an action to occur with the specified value and time offset with a copy of the specified value. See reactor.h for documentation.

◆ py_source_directory()

PyObject * py_source_directory ( PyObject * self,
PyObject * args )

Return the source directory path (where the main .lf file is) as a string.

Parameters
selfThe lf object.
argsEmpty.
Returns
PyObject* A Python string.

Variable Documentation

◆ global_pickler

PyObject* global_pickler = NULL

◆ globalPythonModule

PyObject* globalPythonModule = NULL

◆ globalPythonModuleDict

PyObject* globalPythonModuleDict = NULL

◆ top_level_environment

environment_t* top_level_environment = NULL