#include "cReactor.h"
#include <sys/time.h>
#include <unistd.h>
static int next_call_id = 1;
struct _cReactorMethod
{
int call_id;
PyObject * callable;
PyObject * args;
PyObject * kw;
cReactorMethod * next;
};
PyObject *cReactorUtil_FromImport(const char *name, const char *from_item)
{
PyObject *from_list;
PyObject *module;
PyObject *item;
from_list = PyList_New(1);
PyList_SetItem(from_list, 0, PyString_FromString(from_item));
module = PyImport_ImportModuleEx((char *)name, NULL, NULL, from_list);
Py_DECREF(from_list);
if (!module)
{
return NULL;
}
item = PyObject_GetAttrString(module, (char *)from_item);
Py_DECREF(module);
return item;
}
int
cReactorUtil_AddMethod(cReactorMethod **list,
PyObject *callable,
PyObject *args,
PyObject *kw)
{
cReactorMethod *method, **node;
method = (cReactorMethod *)malloc(sizeof(cReactorMethod));
memset(method, 0x00, sizeof(cReactorMethod));
method->call_id = next_call_id++;
Py_INCREF(callable);
method->callable = callable;
if (!args)
{
method->args = PyTuple_New(0);
}
else
{
Py_INCREF(args);
method->args = args;
}
if (!kw)
{
method->kw = PyDict_New();
}
else
{
Py_INCREF(kw);
method->kw = kw;
}
node = list;
while(*node) {
node = &((*node)->next);
}
method->next = *node;
*node = method;
return method->call_id;
}
cDelayedCall *
cReactorUtil_AddDelayedCall(cReactor *reactor,
int delay_ms,
PyObject *callable,
PyObject *args,
PyObject *kw)
{
cDelayedCall *call;
call = cDelayedCall_new(delay_ms, callable, args, kw);
if (!call)
return NULL;
cReactorUtil_InsertDelayedCall(reactor, call);
return call;
}
int
cReactorUtil_RemoveMethod(cReactorMethod **list, int call_id)
{
cReactorMethod *node;
cReactorMethod *shadow;
shadow = NULL;
node = *list;
while (node)
{
if (node->call_id == call_id)
{
if (shadow)
{
shadow->next = node->next;
}
else
{
*list = node->next;
}
Py_DECREF(node->callable);
Py_XDECREF(node->args);
Py_XDECREF(node->kw);
free(node);
return 0;
}
shadow = node;
node = node->next;
}
return -1;
}
int
cReactorUtil_RunDelayedCalls(cReactor *reactor)
{
cDelayedCall *node;
cDelayedCall *method;
cDelayedCall **list = &reactor->timed_methods;
PyObject *result;
struct timeval now;
int delay;
gettimeofday(&now, NULL);
node = *list;
while (node)
{
if ( (node->call_time.tv_sec > now.tv_sec)
|| (node->call_time.tv_usec > now.tv_usec))
{
break;
}
method = node;
node = node->next;
*list = node;
method->reactor = NULL;
method->called = 1;
result = PyEval_CallObjectWithKeywords(method->callable, method->args, method->kw);
if (!result)
{
PyErr_Print();
}
else
{
Py_DECREF(result);
}
Py_DECREF(method);
}
if (node)
{
delay = ((node->call_time.tv_sec - now.tv_sec) * 1000)
+ ((node->call_time.tv_usec - now.tv_usec) / 1000);
}
else
{
delay = -1;
}
return delay;
}
void
cReactorUtil_DestroyMethods(cReactorMethod *list)
{
cReactorMethod *node;
while (list)
{
node = list;
list = list->next;
Py_DECREF(node->callable);
Py_XDECREF(node->args);
Py_XDECREF(node->kw);
free(node);
}
}
void
cReactorUtil_ForEachMethod(cReactorMethod *list,
cReactorMethodListIterator func,
void *user_data)
{
while (list)
{
(*func)(list->callable, list->args, list->kw, user_data);
list = list->next;
}
}
int
cReactorUtil_NextMethodDelay(cReactor *reactor)
{
int delay;
struct timeval now;
cDelayedCall *list = reactor->timed_methods;
if (!list)
{
return -1;
}
gettimeofday(&now, NULL);
delay = ((list->call_time.tv_sec - now.tv_sec) * 1000)
+ ((list->call_time.tv_usec - now.tv_usec) / 1000);
if (delay < 0)
{
delay = 0;
}
return delay;
}
PyObject *
cReactorUtil_MakeImplements(const char **names, unsigned int num_names)
{
PyObject *obj;
PyObject *impl_tup;
const char **s;
unsigned int u;
impl_tup = PyTuple_New(num_names);
for (s = names, u = 0; u < num_names; ++s, ++u)
{
obj = cReactorUtil_FromImport("twisted.internet.interfaces", *s);
if ( (!obj)
|| (PyTuple_SetItem(impl_tup, u, obj) < 0))
{
Py_DECREF(impl_tup);
return NULL;
}
}
return impl_tup;
}
PyObject *
cReactorUtil_CreateDeferred(void)
{
PyObject *defer_class;
defer_class = cReactorUtil_FromImport("twisted.internet.defer", "Deferred");
if (!defer_class)
{
return NULL;
}
return PyObject_CallFunction(defer_class, "()");
}
int
cReactorUtil_ConvertDelay(PyObject *delay_obj)
{
int delay;
double delay_float;
if (!PyNumber_Check(delay_obj))
{
PyErr_SetString(PyExc_ValueError, "delay arg must be a number!");
return -1;
}
delay_obj = PyNumber_Float(delay_obj);
if (!delay_obj)
{
return -1;
}
delay_float = PyFloat_AsDouble(delay_obj);
Py_DECREF(delay_obj);
delay = (int)(delay_float * 1000.0f);
if (delay < 0)
{
PyErr_SetString(PyExc_ValueError, "delay is negative!");
}
return delay;
}
void
cReactorUtil_InsertDelayedCall(cReactor *reactor, cDelayedCall *call)
{
cDelayedCall *node, *shadow;
cDelayedCall **list = &reactor->timed_methods;
node = *list;
shadow = NULL;
while (node)
{
if ( (call->call_time.tv_sec < node->call_time.tv_sec)
&& (call->call_time.tv_usec < node->call_time.tv_usec))
{
break;
}
shadow = node;
node = node->next;
}
call->reactor = reactor;
call->next = node;
if (shadow)
{
shadow->next = call;
}
else
{
*list = call;
}
Py_INCREF((PyObject *)call);
}
int
cReactorUtil_RemoveDelayedCall(cReactor *reactor, cDelayedCall *call)
{
cDelayedCall *node;
cDelayedCall *shadow;
cDelayedCall **list = &reactor->timed_methods;
shadow = NULL;
node = *list;
while (node)
{
if (node == call)
{
if (shadow)
{
shadow->next = node->next;
}
else
{
*list = node->next;
}
node->reactor = NULL;
Py_DECREF(node);
return 0;
}
shadow = node;
node = node->next;
}
PyErr_Format(PyExc_ValueError, "no such cDelayedCall");
return -1;
}
int
cReactorUtil_ReInsertDelayedCall(cReactor *reactor, cDelayedCall *call)
{
int rc;
Py_INCREF(call);
rc = cReactorUtil_RemoveDelayedCall(reactor, call);
if (rc == 0)
cReactorUtil_InsertDelayedCall(reactor, call);
Py_DECREF(call);
return rc;
}
void
cReactorUtil_DestroyDelayedCalls(cReactor *reactor)
{
cDelayedCall *list = reactor->timed_methods;
cDelayedCall *node;
while (list)
{
node = list;
list = list->next;
node->reactor = NULL;
Py_DECREF(node);
}
}