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.

5
  • Which line in the C code segfaults? Commented Aug 28, 2020 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. Commented Aug 28, 2020 at 11:36
  • If you print out the timer ID in C, is the timer_delete TID the same as the timer_create TID? Commented Aug 28, 2020 at 12:45
  • 1
    Also did you notice that timer_delete takes a timer ID, not a pointer to one? Commented Aug 28, 2020 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! Commented Aug 28, 2020 at 13:00

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.