From ce0973a45a60e0aec022b5d59cb71acc530a2769 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 29 Nov 2024 14:02:50 -0800 Subject: [PATCH 01/10] Filled out struct for mode capsule --- python/lib/modal_models/impl.c | 56 +++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/python/lib/modal_models/impl.c b/python/lib/modal_models/impl.c index c8cdff1f2..8a8487236 100644 --- a/python/lib/modal_models/impl.c +++ b/python/lib/modal_models/impl.c @@ -46,12 +46,14 @@ static PyObject* py_mode_set(PyObject* mode_capsule, PyObject* args) { lf_print_error("Null pointer received."); exit(1); } + Py_INCREF(m->mode); self_base_t* self = PyCapsule_GetPointer(m->lf_self, "lf_self"); if (self == NULL) { lf_print_error("Null pointer received."); exit(1); } + Py_INCREF(m->lf_self); _LF_SET_MODE_WITH_TYPE(mode, m->change_type); @@ -61,6 +63,24 @@ static PyObject* py_mode_set(PyObject* mode_capsule, PyObject* args) { //////////// Python Struct ///////////// +/** + * Called when an mode in Python is to be created. Note that this is not normally + * used because modes are not created in Python. + * + * To initialize the mode_capsule, this function first calls the tp_alloc + * method of type mode_capsule_struct_t and then assign default values of NULL, NULL, 0 + * to the members of the generic_mode_capsule_struct. + */ +PyObject* py_mode_capsule_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { + mode_capsule_struct_t* self = (mode_capsule_struct_t*)type->tp_alloc(type, 0); + if (self != NULL) { + self->mode = NULL; + self->lf_self = NULL; + self->change_type = 0; + } + return (PyObject*)self; +} + /* * The function members of mode_capsule. * The set function is used to set a new mode. @@ -69,6 +89,37 @@ static PyMethodDef mode_capsule_methods[] = { {"set", (PyCFunction)py_mode_set, METH_NOARGS, "Set a new mode."}, {NULL} /* Sentinel */ }; +/** + * Initialize the mode capsule "self" with NULL pointers and default change_type. + */ +static int py_mode_capsule_init(mode_capsule_struct_t* self, PyObject* args, PyObject* kwds) { + self->mode = NULL; + self->lf_self = NULL; + self->change_type = 0; + return 0; +} + +/** + * Called when an mode capsule in Python is deallocated (generally + * called by the Python grabage collector). + * @param self + */ +void py_mode_capsule_dealloc(mode_capsule_struct_t* self) { + Py_XDECREF(self->mode); + Py_XDECREF(self->lf_self); + Py_TYPE(self)->tp_free((PyObject*)self); +} + +/* + * The members of a mode_capsule that are accessible from a Python program, used to define + * a native Python type. + */ +PyMemberDef py_mode_capsule_members[] = { + {"mode", T_OBJECT, offsetof(mode_capsule_struct_t, mode), 0, "The pointer to the C mode struct"}, + {"lf_self", T_OBJECT, offsetof(mode_capsule_struct_t, lf_self), 0, "Pointer to LF self"}, + {NULL} /* Sentinel */ +}; + /* * The definition of mode_capsule type object, which is * used to describe how mode_capsule behaves. @@ -79,7 +130,10 @@ static PyTypeObject mode_capsule_t = { .tp_basicsize = sizeof(mode_capsule_struct_t), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_new = PyType_GenericNew, + .tp_new = py_mode_capsule_new, + .tp_init = (initproc)py_mode_capsule_init, + .tp_dealloc = (destructor)py_mode_capsule_dealloc, + .tp_members = py_mode_capsule_members, .tp_methods = mode_capsule_methods, }; From 9a9e492ec1d63817b7a058de1d7c2ac4e47b08f0 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 29 Nov 2024 15:15:16 -0800 Subject: [PATCH 02/10] Slightly more careful reference count decrementing --- python/include/python_port.h | 1 - python/lib/python_port.c | 20 ++++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/python/include/python_port.h b/python/include/python_port.h index 7752b16c8..cc50524c6 100644 --- a/python/include/python_port.h +++ b/python/include/python_port.h @@ -97,5 +97,4 @@ typedef struct { FEDERATED_CAPSULE_EXTENSION } generic_port_capsule_struct; -void python_count_decrement(void* py_object); #endif diff --git a/python/lib/python_port.c b/python/lib/python_port.c index 62f4b4732..571024946 100644 --- a/python/lib/python_port.c +++ b/python/lib/python_port.c @@ -47,7 +47,7 @@ PyTypeObject py_port_capsule_t; * Python can free its memory. * @param py_object A PyObject with count 1 or greater. */ -void python_count_decrement(void* py_object) { Py_XDECREF((PyObject*)py_object); } +static void python_count_decrement(void* py_object) { Py_XDECREF((PyObject*)py_object); } //////////// set Function(s) ///////////// /** @@ -94,14 +94,13 @@ PyObject* py_port_set(PyObject* self, PyObject* args) { } if (val) { - LF_PRINT_DEBUG("Setting value %p with reference count %d.", val, (int)Py_REFCNT(val)); - // Py_INCREF(val); // python_count_decrement(port->value); lf_token_t* token = lf_new_token((void*)port, val, 1); lf_set_destructor(port, python_count_decrement); lf_set_token(port, token); Py_INCREF(val); + LF_PRINT_DEBUG("Setting value %p with reference count %d.", val, (int)Py_REFCNT(val)); // Also set the values for the port capsule. p->value = val; @@ -117,9 +116,9 @@ PyObject* py_port_set(PyObject* self, PyObject* args) { * garbage collector). * @param self An instance of generic_port_instance_struct* */ -void py_port_capsule_dealloc(generic_port_capsule_struct* self) { - Py_XDECREF(self->port); - Py_XDECREF(self->value); +static void py_port_capsule_dealloc(generic_port_capsule_struct* self) { + Py_CLEAR(self->port); + Py_CLEAR(self->value); Py_TYPE(self)->tp_free((PyObject*)self); } @@ -147,7 +146,8 @@ PyObject* py_port_capsule_new(PyTypeObject* type, PyObject* args, PyObject* kwds generic_port_capsule_struct* self; self = (generic_port_capsule_struct*)type->tp_alloc(type, 0); if (self != NULL) { - self->port = NULL; + Py_INCREF(Py_None); + self->port = Py_None; Py_INCREF(Py_None); self->value = Py_None; self->is_present = false; @@ -325,7 +325,7 @@ PyMappingMethods py_port_as_mapping = {(lenfunc)py_port_length, (binaryfunc)py_p */ int py_port_capsule_init(generic_port_capsule_struct* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = {"port", "value", "is_present", "width", "current_index", NULL}; - PyObject *value = NULL, *tmp, *port = NULL; + PyObject *value = NULL, *port = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOp", kwlist, &port, &value, &self->is_present, &self->width, &self->current_index)) { @@ -333,14 +333,14 @@ int py_port_capsule_init(generic_port_capsule_struct* self, PyObject* args, PyOb } if (value) { - tmp = self->value; + PyObject *tmp = self->value; Py_INCREF(value); self->value = value; Py_XDECREF(tmp); } if (port) { - tmp = self->port; + PyObject *tmp = self->port; Py_INCREF(port); self->port = port; Py_XDECREF(tmp); From 76bcf3282d4c8d58178da56a32720736379895f6 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 29 Nov 2024 15:21:10 -0800 Subject: [PATCH 03/10] Replace deprecated function --- python/lib/pythontarget.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/python/lib/pythontarget.c b/python/lib/pythontarget.c index 8e41f40f9..0847cac6e 100644 --- a/python/lib/pythontarget.c +++ b/python/lib/pythontarget.c @@ -603,7 +603,14 @@ PyObject* get_python_function(string module, string class, int instance_id, stri mbstowcs(wcwd, cwd, PATH_MAX); - Py_SetPath(wcwd); + // Deprecated: Py_SetPath(wcwd); + // Replace with the following more verbose version: + PyConfig config; + PyConfig_InitPythonConfig(&config); + // Add paths to the configuration + PyWideStringList_Append(&config.module_search_paths, wcwd); + // Initialize Python with the custom configuration + Py_InitializeFromConfig(&config); LF_PRINT_DEBUG("Loading module %s in %s.", module, cwd); From eecb56c428f0d3e757c13ea4e34619f9be047dc7 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Fri, 29 Nov 2024 17:59:04 -0800 Subject: [PATCH 04/10] Made function not static, apparently needed for Docker --- python/include/python_port.h | 1 + python/lib/python_port.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/python/include/python_port.h b/python/include/python_port.h index cc50524c6..7752b16c8 100644 --- a/python/include/python_port.h +++ b/python/include/python_port.h @@ -97,4 +97,5 @@ typedef struct { FEDERATED_CAPSULE_EXTENSION } generic_port_capsule_struct; +void python_count_decrement(void* py_object); #endif diff --git a/python/lib/python_port.c b/python/lib/python_port.c index 571024946..aceff28a7 100644 --- a/python/lib/python_port.c +++ b/python/lib/python_port.c @@ -47,7 +47,7 @@ PyTypeObject py_port_capsule_t; * Python can free its memory. * @param py_object A PyObject with count 1 or greater. */ -static void python_count_decrement(void* py_object) { Py_XDECREF((PyObject*)py_object); } +void python_count_decrement(void* py_object) { Py_XDECREF((PyObject*)py_object); } //////////// set Function(s) ///////////// /** From 441e3ad6e31f70467651a070829d4fe5c1759445 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Mon, 2 Dec 2024 10:25:47 -0800 Subject: [PATCH 05/10] Issue error message on failure --- python/lib/modal_models/impl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/python/lib/modal_models/impl.c b/python/lib/modal_models/impl.c index 8a8487236..e212436e5 100644 --- a/python/lib/modal_models/impl.c +++ b/python/lib/modal_models/impl.c @@ -154,6 +154,7 @@ void initialize_mode_capsule_t(PyObject* current_module) { if (PyModule_AddObject(current_module, "mode_capsule", (PyObject*)&mode_capsule_t) < 0) { Py_DECREF(&mode_capsule_t); Py_DECREF(current_module); + lf_print_error_and_exit("Failed to initialize mode_capsule."); return; } } From 601e633beddc51e6f5ca492319b1ec4caf05c278 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Thu, 5 Dec 2024 15:12:31 -0800 Subject: [PATCH 06/10] Point reactor-c to lingua-franca master --- lingua-franca-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lingua-franca-ref.txt b/lingua-franca-ref.txt index edf165c42..8b25206ff 100644 --- a/lingua-franca-ref.txt +++ b/lingua-franca-ref.txt @@ -1 +1 @@ -fix-concurrency \ No newline at end of file +master \ No newline at end of file From fe1ee790b313c4ee0ced0e80e7b58319d5a8090a Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sat, 7 Dec 2024 10:53:09 -0800 Subject: [PATCH 07/10] Use Python_New not Python_GC_New --- python/lib/modal_models/impl.c | 6 +++++- python/lib/python_tag.c | 3 ++- python/lib/pythontarget.c | 8 ++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/python/lib/modal_models/impl.c b/python/lib/modal_models/impl.c index e212436e5..f47c7135f 100644 --- a/python/lib/modal_models/impl.c +++ b/python/lib/modal_models/impl.c @@ -164,16 +164,19 @@ void initialize_mode_capsule_t(PyObject* current_module) { */ PyObject* convert_C_mode_to_py(reactor_mode_t* mode, self_base_t* lf_self, lf_mode_change_type_t change_type) { // Create the mode struct in Python - mode_capsule_struct_t* cap = (mode_capsule_struct_t*)PyObject_GC_New(mode_capsule_struct_t, &mode_capsule_t); + mode_capsule_struct_t* cap = (mode_capsule_struct_t*)PyObject_New(mode_capsule_struct_t, &mode_capsule_t); + if (cap == NULL) { lf_print_error_and_exit("Failed to convert mode."); } + Py_INCREF(cap); // Create the capsule to hold the reactor_mode_t* mode PyObject* capsule = PyCapsule_New(mode, "mode", NULL); if (capsule == NULL) { lf_print_error_and_exit("Failed to convert mode."); } + Py_INCREF(capsule); // Fill in the Python mode struct. cap->mode = capsule; @@ -182,6 +185,7 @@ PyObject* convert_C_mode_to_py(reactor_mode_t* mode, self_base_t* lf_self, lf_mo if (self_capsule == NULL) { lf_print_error_and_exit("Failed to convert self."); } + Py_INCREF(self_capsule); cap->lf_self = self_capsule; cap->change_type = change_type; diff --git a/python/lib/python_tag.c b/python/lib/python_tag.c index 991f94f64..f32eb0e9d 100644 --- a/python/lib/python_tag.c +++ b/python/lib/python_tag.c @@ -191,10 +191,11 @@ PyTypeObject PyTagType = { * @return PyObject* The tag in Python. */ py_tag_t* convert_C_tag_to_py(tag_t c_tag) { - py_tag_t* py_tag = PyObject_GC_New(py_tag_t, &PyTagType); + py_tag_t* py_tag = PyObject_New(py_tag_t, &PyTagType); if (py_tag == NULL) { lf_print_error_and_exit("Failed to convert tag from C to Python."); } + Py_INCREF(py_tag); py_tag->tag = c_tag; return py_tag; } diff --git a/python/lib/pythontarget.c b/python/lib/pythontarget.c index 0847cac6e..cc5c51c24 100644 --- a/python/lib/pythontarget.c +++ b/python/lib/pythontarget.c @@ -445,16 +445,18 @@ void destroy_action_capsule(PyObject* capsule) { free(PyCapsule_GetPointer(capsu */ PyObject* convert_C_port_to_py(void* port, int width) { // Create the port struct in Python - PyObject* cap = (PyObject*)PyObject_GC_New(generic_port_capsule_struct, &py_port_capsule_t); + PyObject* cap = (PyObject*)PyObject_New(generic_port_capsule_struct, &py_port_capsule_t); if (cap == NULL) { lf_print_error_and_exit("Failed to convert port."); } + Py_INCREF(cap); // Create the capsule to hold the void* port PyObject* capsule = PyCapsule_New(port, "port", NULL); if (capsule == NULL) { lf_print_error_and_exit("Failed to convert port."); } + Py_INCREF(capsule); // Fill in the Python port struct ((generic_port_capsule_struct*)cap)->port = capsule; @@ -512,16 +514,18 @@ PyObject* convert_C_action_to_py(void* action) { trigger_t* trigger = ((lf_action_base_t*)action)->trigger; // Create the action struct in Python - PyObject* cap = (PyObject*)PyObject_GC_New(generic_action_capsule_struct, &py_action_capsule_t); + PyObject* cap = (PyObject*)PyObject_New(generic_action_capsule_struct, &py_action_capsule_t); if (cap == NULL) { lf_print_error_and_exit("Failed to convert action."); } + Py_INCREF(cap); // Create the capsule to hold the void* action PyObject* capsule = PyCapsule_New(action, "action", NULL); if (capsule == NULL) { lf_print_error_and_exit("Failed to convert action."); } + Py_INCREF(capsule); // Fill in the Python action struct ((generic_action_capsule_struct*)cap)->action = capsule; From 3152ea31eb24980d7fe5c0baaec9c0e403d77db4 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 9 Dec 2024 18:18:53 -0800 Subject: [PATCH 08/10] Run clang-format --- python/lib/python_port.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/lib/python_port.c b/python/lib/python_port.c index aceff28a7..be12861d5 100644 --- a/python/lib/python_port.c +++ b/python/lib/python_port.c @@ -333,14 +333,14 @@ int py_port_capsule_init(generic_port_capsule_struct* self, PyObject* args, PyOb } if (value) { - PyObject *tmp = self->value; + PyObject* tmp = self->value; Py_INCREF(value); self->value = value; Py_XDECREF(tmp); } if (port) { - PyObject *tmp = self->port; + PyObject* tmp = self->port; Py_INCREF(port); self->port = port; Py_XDECREF(tmp); From 6c7379e658aed9aa22d53163cb004e77a82d31eb Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 9 Dec 2024 18:57:02 -0800 Subject: [PATCH 09/10] Update to clang-format v19.1.5 --- .github/workflows/clang-format.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 11028dd38..2f099df81 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -5,12 +5,15 @@ on: [pull_request] jobs: clang-format: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v2 - - name: Install clang-tidy + - name: Install clang-tidy and clang-format run: | sudo apt-get update sudo apt-get install -y clang-tidy + sudo apt-get install -y pipx + pipx install clang-format + clang-format --version - name: Analyze run: make format-check From 8cd66aa792954589d4125ddd17800c1ea5816739 Mon Sep 17 00:00:00 2001 From: erlingrj Date: Mon, 9 Dec 2024 18:57:45 -0800 Subject: [PATCH 10/10] Run clang-format 19.1.5 --- core/federated/federate.c | 6 +++--- include/core/utils/impl/hashmap.h | 2 +- include/core/utils/impl/pointer_hashmap.h | 2 +- tag/api/tag.h | 9 +++------ 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/core/federated/federate.c b/core/federated/federate.c index 9be45fdd7..2bfc3656a 100644 --- a/core/federated/federate.c +++ b/core/federated/federate.c @@ -1951,9 +1951,9 @@ void lf_connect_to_rti(const char* hostname, int port) { if (result < 0) continue; // Connect failed. - // Have connected to an RTI, but not sure it's the right RTI. - // Send a MSG_TYPE_FED_IDS message and wait for a reply. - // Notify the RTI of the ID of this federate and its federation. + // Have connected to an RTI, but not sure it's the right RTI. + // Send a MSG_TYPE_FED_IDS message and wait for a reply. + // Notify the RTI of the ID of this federate and its federation. #ifdef FEDERATED_AUTHENTICATED LF_PRINT_LOG("Connected to an RTI. Performing HMAC-based authentication using federation ID."); diff --git a/include/core/utils/impl/hashmap.h b/include/core/utils/impl/hashmap.h index e64774887..94d5969a7 100644 --- a/include/core/utils/impl/hashmap.h +++ b/include/core/utils/impl/hashmap.h @@ -19,7 +19,7 @@ #define V void* #endif #ifndef HASH_OF -#define HASH_OF(key) (size_t) key +#define HASH_OF(key) (size_t)key #endif #ifndef HASHMAP #define HASHMAP(token) hashmap##_##token diff --git a/include/core/utils/impl/pointer_hashmap.h b/include/core/utils/impl/pointer_hashmap.h index 2184518b3..c2a60aef1 100644 --- a/include/core/utils/impl/pointer_hashmap.h +++ b/include/core/utils/impl/pointer_hashmap.h @@ -30,7 +30,7 @@ #define HASHMAP(token) hashmap_object2int##_##token #define K void* #define V int -#define HASH_OF(key) (size_t) key +#define HASH_OF(key) (size_t)key #include "hashmap.h" #undef HASHMAP #undef K diff --git a/tag/api/tag.h b/tag/api/tag.h index c40e490f8..ab6b9ccbc 100644 --- a/tag/api/tag.h +++ b/tag/api/tag.h @@ -37,15 +37,12 @@ #define NEVER_TAG \ (tag_t) { .time = NEVER, .microstep = NEVER_MICROSTEP } // Need a separate initializer expression to comply with some C compilers -#define NEVER_TAG_INITIALIZER \ - { NEVER, NEVER_MICROSTEP } +#define NEVER_TAG_INITIALIZER {NEVER, NEVER_MICROSTEP} #define FOREVER_TAG \ (tag_t) { .time = FOREVER, .microstep = FOREVER_MICROSTEP } // Need a separate initializer expression to comply with some C compilers -#define FOREVER_TAG_INITIALIZER \ - { FOREVER, FOREVER_MICROSTEP } -#define ZERO_TAG \ - (tag_t) { .time = 0LL, .microstep = 0u } +#define FOREVER_TAG_INITIALIZER {FOREVER, FOREVER_MICROSTEP} +#define ZERO_TAG (tag_t){.time = 0LL, .microstep = 0u} // Returns true if timeout has elapsed. #define CHECK_TIMEOUT(start, duration) (lf_time_physical() > ((start) + (duration)))