Prevent timers being added in a call

This commit is contained in:
Kovid Goyal 2017-09-09 14:00:15 +05:30
parent 0aecae288f
commit fb820faf11
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 8 additions and 0 deletions

View File

@ -258,6 +258,7 @@ typedef struct {
TimerEvent *events, *buf1, *buf2;
size_t capacity;
size_t count;
bool in_call;
} Timers;
PyTypeObject Timers_Type;

View File

@ -56,6 +56,7 @@ new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
self = (Timers *)type->tp_alloc(type, 0);
self->capacity = 1024;
self->count = 0;
self->in_call = false;
self->buf1 = (TimerEvent*)PyMem_Calloc(2 * self->capacity, sizeof(TimerEvent));
if (self->buf1 == NULL) { Py_CLEAR(self); return PyErr_NoMemory(); }
self->events = self->buf1;
@ -98,6 +99,7 @@ _add(Timers *self, double at, PyObject *callback, PyObject *args) {
static inline bool
timers_add_(Timers *self, double at, bool update, PyObject *callback, PyObject *args) {
if (self->in_call) { PyErr_SetString(PyExc_ValueError, "Cannot add timers in a timer handler"); return false; }
for (size_t i = 0; i < self->count; i++) {
if (self->events[i].callback == callback) {
self->events[i].at = update ? at : MIN(at, self->events[i].at);
@ -130,6 +132,7 @@ add(Timers *self, PyObject *fargs) {
bool
timers_add_if_before(Timers *self, double delay, PyObject *callback, PyObject *args) {
double at = monotonic_() + delay;
if (self->in_call) { PyErr_SetString(PyExc_ValueError, "Cannot add timers in a timer handler"); return false; }
for (size_t i = 0; i < self->count; i++) {
if (self->events[i].at < at) {
return true;
@ -152,6 +155,7 @@ add_if_before(Timers *self, PyObject *fargs) {
bool
timers_add_if_missing(Timers *self, double delay, PyObject *callback, PyObject *args) {
if (self->in_call) { PyErr_SetString(PyExc_ValueError, "Cannot add timers in a timer handler"); return false; }
for (size_t i = 0; i < self->count; i++) {
if (self->events[i].callback == callback) {
return true;
@ -177,6 +181,7 @@ remove_event(Timers *self, PyObject *callback) {
#define remove_event_doc "remove(callback) -> Remove the event with the specified callback, if present"
TimerEvent *other = self->events == self->buf1 ? self->buf2 : self->buf1;
size_t i, j;
if (self->in_call) { PyErr_SetString(PyExc_ValueError, "Cannot remove timers in a timer handler"); return false; }
for (i = 0, j = 0; i < self->count; i++) {
if (self->events[i].callback != callback) {
other[j].callback = self->events[i].callback; other[j].at = self->events[i].at; other[j].args = self->events[i].args;
@ -211,6 +216,7 @@ timers_call(Timers *self) {
TimerEvent *other = self->events == self->buf1 ? self->buf2 : self->buf1;
double now = monotonic_();
size_t i, j;
self->in_call = true;
for (i = 0, j = 0; i < self->count; i++) {
if (self->events[i].at <= now) { // expired, call it
/* PyObject_Print(self->events[i].callback, stdout, 1); */
@ -228,6 +234,7 @@ timers_call(Timers *self) {
}
self->events = other;
self->count = j;
self->in_call = false;
}
static PyObject *