0

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.

someCoder
  • 185
  • 3
  • 15
  • Which line in the C code segfaults? – user253751 Aug 28 '20 at 11:24
  • @user253751 in this code I'm showing, I'm not getting the segfault (just the failed timer_delete). The line that used to segfail was after the timer_delete if-statement in ResetTimer, where I would call timer = new tmr_data() and then subsequentially call _StartTimer from within ResetTimer. – someCoder Aug 28 '20 at 11:36
  • If you print out the timer ID in *C*, is the timer_delete TID the same as the timer_create TID? – user253751 Aug 28 '20 at 12:45
  • 1
    Also did you notice that timer_delete takes a timer ID, not a pointer to one? – user253751 Aug 28 '20 at 12:46
  • @user253751 that was it. The timer_delete pointer. While porting this code from the other component of the project I completely missed that. You solved it! – someCoder Aug 28 '20 at 13:00

0 Answers0