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 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/python/lib/modal_models/impl.c b/python/lib/modal_models/impl.c index c8cdff1f2..f47c7135f 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, }; @@ -100,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; } } @@ -109,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; @@ -127,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_port.c b/python/lib/python_port.c index 62f4b4732..be12861d5 100644 --- a/python/lib/python_port.c +++ b/python/lib/python_port.c @@ -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); 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 8e41f40f9..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; @@ -603,7 +607,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); 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)))