I'll try to keep it as short as possible. I'm making a python application which uses a C Extension (hw_timer). This extension is in charge of creating a timer.
The Python application starts by calling hw_timer.StartTimer which instantiates a timer object. After that, inside an infinite loop, the Python keeps calling hw_timer.ResetTimer and hw_timer.StartTimer. Reset timer de facto destroys the timer and then a new one is created with StartTimer and so on.
The code went through several changes since, no matter what, I kept getting segmentation faults whenever I tried to create a new timer.
However the situation now is VERY strange.
Here's the Python code: you'll notice I've removed the infinite loop I described before because I wanted to create a very simple scenario to showcase my issue
if __name__ == "__main__":
timerPtr = hw_timer.StartTimer(os.getpid()) #start timer returns a tuple
print("timer,tid,pid -> {}".format(timerPtr))
print("Result of reset timer: {}".format(hw_timer.ResetTimer(timerPtr[0])))
print("---------")
time.sleep(10)
timerPtr=hw_timer.StartTimer(os.getpid())
print("timer,tid,pid -> {}".format(timerPtr))
print("Result of reset timer: {}".format(hw_timer.ResetTimer(timerPtr[0])))
print("---------")
time.sleep(10)
And this is the output
timer,tid,pid -> (16985424, 16598768, 45975)
Result of reset timer: (16985424, 16598768, 45975)
---------
timer,tid,pid -> (16598768, 15553760, 45975)
timer_delete: Invalid argument
As you can see, despite replicating the same code twice, the second time, system method time_delete fails during the computation of ResetTimer.
Now the following is the C code (I've removed as much Python.h related content as possible to make it more readable)
#include <Python.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
struct tmr_struct
{
timer_t* tid;
int pid;
};
typedef struct sigevent signal_event;
typedef struct tmr_struct tmr_data;
typedef struct itimerspec tmr_spec;
static const int TIMER_SECOND = 5;
//Method called after timer expiration
void signal_handler (int sv)
{
exit(1);
}
//Creation of a new timer_t object stored inside a tmr_data struct
static void _StartTimer(tmr_data* timer)
{
timer->tid = new timer_t();
signal_event sev;
signal(SIGUSR1, signal_handler);
sev.sigev_notify = SIGEV_THREAD_ID;
sev.sigev_notify_function = NULL;
sev._sigev_un._tid = timer->pid;
sev.sigev_signo = SIGUSR1;
sev.sigev_notify_attributes = NULL;
tmr_spec ts;
if (timer_create(CLOCK_REALTIME, &sev, timer->tid) == -1) {
perror("timer_create");
exit(1);
}
memset(&ts,0,sizeof(ts));
ts.it_value.tv_nsec = 0;
ts.it_value.tv_sec = TIMER_SECOND;
ts.it_interval.tv_nsec = 0;
ts.it_interval.tv_sec = 0;
if (timer_settime(*(timer->tid), 0, &ts, NULL) == -1) {
perror("timer_settime");
exit(1);
}
return;
}
//Start timer method called from the Python application
//Accepts the PID of the Python App and later passes it to _StartTimer using the tmr_data struct
static PyObject* StartTimer(PyObject* self, PyObject* args) {
int pid;
tmr_data* timer = new tmr_data();
if (!PyArg_ParseTuple(args, "i", &pid)) {
return NULL;
}
timer->pid = pid;
_StartTimer(timer);
return Py_BuildValue("iii", timer,timer->tid,timer->pid);
}
//Receives a pointer to a tmr_data struct object, deletes the timer contained inside it
static PyObject* ResetTimer(PyObject* self, PyObject* args)
{
tmr_data* timer;
long ptr_timer;
if (!PyArg_ParseTuple(args, "i", &ptr_timer)) {
return NULL;
}
timer = (tmr_data*)ptr_timer;
if(timer_delete(timer->tid) != 0)
{
perror("timer_delete");
exit(1);
}
return Py_BuildValue("iii", timer,timer->tid,timer->pid);
}
Now consider that the entire code of _StartTimer is correct: it's already been used in other parts of the project for pure C applications and, indeed, the timer does work here as well, at least the first time.
But still, this stuff is all over the place: originally I had ResetTimer calling _StartTimer, but whenever I'd call "timer = new tmr_data()" I would get segmentation fault, so I'm starting to think that the entire timer implementation might be somewhat tricky or prone to errors.