support python 3.2

This commit is contained in:
Michael Davidsaver
2013-04-07 08:40:00 -04:00
parent 3601974986
commit c9820d264f
9 changed files with 175 additions and 162 deletions

View File

@ -115,10 +115,21 @@ static PyObject* pyField_putval(pyField *self, PyObject* args)
OP(DOUBLE,epicsFloat64,PyFloat_AsDouble);
#undef OP
case DBF_STRING: {
char *fld = PyString_AsString(val);
strncpy(self->addr.pfield, fld, MAX_STRING_SIZE);
fld = self->addr.pfield;
fld[MAX_STRING_SIZE-1]='\0';
const char *fld;
char *dest=self->addr.pfield;
#if PY_MAJOR_VERSION >= 3
PyObject *data = PyUnicode_AsEncodedString(val, "ascii", "Encoding error:");
if(!data)
return NULL;
fld = PyUnicode_AS_DATA(data);
#else
fld = PyString_AsString(val);
#endif
strncpy(dest, fld, MAX_STRING_SIZE);
dest[MAX_STRING_SIZE-1]='\0';
#if PY_MAJOR_VERSION >= 3
Py_DECREF(data);
#endif
break;
}
default:
@ -166,6 +177,7 @@ static PyMethodDef pyField_methods[] = {
{NULL, NULL, 0, NULL}
};
#if PY_MAJOR_VERSION < 3
static Py_ssize_t pyField_buf_getcount(pyField *self, Py_ssize_t *totallen)
{
if(totallen)
@ -195,6 +207,7 @@ static Py_ssize_t pyField_buf_getcharbuf(pyField *self, Py_ssize_t bufid, char *
*data = self->addr.pfield;
return self->addr.field_size * self->addr.no_elements;
}
#endif
static int pyField_buf_getbufferproc(pyField *self, Py_buffer *buf, int flags)
{
@ -205,18 +218,24 @@ static int pyField_buf_getbufferproc(pyField *self, Py_buffer *buf, int flags)
}
static PyBufferProcs pyField_buf_methods = {
#if PY_MAJOR_VERSION < 3
(readbufferproc)pyField_buf_getbuf,
(writebufferproc)pyField_buf_getbuf,
(segcountproc)pyField_buf_getcount,
(charbufferproc)pyField_buf_getcharbuf,
#endif
(getbufferproc)pyField_buf_getbufferproc,
(releasebufferproc)NULL,
};
static PyTypeObject pyField_type = {
#if PY_MAJOR_VERSION >= 3
PyVarObject_HEAD_INIT(NULL, 0)
#else
PyObject_HEAD_INIT(NULL)
0,
#endif
"_dbapi._Field",
sizeof(pyField),
};
@ -226,7 +245,9 @@ int pyField_prepare(void)
size_t i;
pyField_type.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE;
#if PY_MAJOR_VERSION < 3
pyField_type.tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER|Py_TPFLAGS_HAVE_NEWBUFFER;
#endif
pyField_type.tp_methods = pyField_methods;
pyField_type.tp_as_buffer = &pyField_buf_methods;
pyField_type.tp_init = (initproc)pyField_Init;

View File

@ -24,7 +24,7 @@ typedef struct {
static void pyRecord_dealloc(pyRecord *self)
{
dbFinishEntry(&self->entry);
self->ob_type->tp_free((PyObject*)self);
Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject* pyRecord_new(PyTypeObject *type, PyObject *args, PyObject *kws)
@ -57,6 +57,7 @@ static PyObject* pyRecord_ispyrec(pyRecord *self)
return PyBool_FromLong(self->ispyrec);
}
#if PY_MAJOR_VERSION < 3
static int pyRecord_compare(pyRecord *A, pyRecord *B)
{
dbCommon *a=A->entry.precnode->precord,
@ -66,6 +67,7 @@ static int pyRecord_compare(pyRecord *A, pyRecord *B)
return 0;
return strcmp(a->name, b->name);
}
#endif
static PyObject* pyRecord_name(pyRecord *self)
{
@ -259,8 +261,12 @@ static PyMethodDef pyRecord_methods[] = {
};
static PyTypeObject pyRecord_type = {
#if PY_MAJOR_VERSION >= 3
PyVarObject_HEAD_INIT(NULL, 0)
#else
PyObject_HEAD_INIT(NULL)
0,
#endif
"_dbapi._Record",
sizeof(pyRecord),
};
@ -274,7 +280,9 @@ int pyRecord_prepare(void)
pyRecord_type.tp_new = (newfunc)pyRecord_new;
pyRecord_type.tp_dealloc = (destructor)pyRecord_dealloc;
pyRecord_type.tp_init = (initproc)pyRecord_Init;
#if PY_MAJOR_VERSION < 3
pyRecord_type.tp_compare = (cmpfunc)pyRecord_compare;
#endif
if(PyType_Ready(&pyRecord_type)<0)
return -1;

View File

@ -1,6 +1,16 @@
#ifndef PYDEVSUP_H
#define PYDEVSUP_H
#if PY_MAJOR_VERSION >= 3
#define PyInt_FromLong PyLong_FromLong
#define PyInt_AsLong PyLong_AsLong
#define PyString_FromString PyUnicode_FromString
#define MODINIT_RET(VAL) return (VAL)
#else
#define MODINIT_RET(VAL) return
#endif
void pyDBD_cleanup(void);
int pyField_prepare(void);

View File

@ -64,43 +64,6 @@ static pystate statenames[] = {
};
#undef INITST
static void pyhook(initHookState state);
static void cleanupPy(void *junk)
{
PyThreadState *state = PyGILState_GetThisThreadState();
PyEval_RestoreThread(state);
/* special "fake" hook for shutdown */
pyhook((initHookState)9999);
pyDBD_cleanup();
pyField_cleanup();
/* release extra reference for hooktable */
Py_DECREF(hooktable);
hooktable = NULL;
Py_Finalize();
}
/* Initialize the interpreter environment
*/
static epicsThreadOnceId setupPyOnceId = EPICS_THREAD_ONCE_INIT;
static void setupPyOnce(void *junk)
{
PyThreadState *state;
Py_Initialize();
PyEval_InitThreads();
state = PyEval_SaveThread();
epicsAtExit(&cleanupPy, NULL);
}
void evalPy(const char* code)
{
PyGILState_STATE state;
@ -193,8 +156,18 @@ static PyMethodDef devsup_methods[] = {
{NULL, NULL, 0, NULL}
};
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef dbapimodule = {
PyModuleDef_HEAD_INIT,
"_dbapi",
NULL,
-1,
devsup_methods
};
#endif
/* initialize "magic" builtin module */
static void init_dbapi(void)
PyMODINIT_FUNC init_dbapi(void)
{
PyObject *mod, *hookdict, *pysuptable;
pystate *st;
@ -203,23 +176,27 @@ static void init_dbapi(void)
hooktable = PyDict_New();
if(!hooktable)
return;
MODINIT_RET(NULL);
if(pyField_prepare())
return;
MODINIT_RET(NULL);
if(pyRecord_prepare())
return;
MODINIT_RET(NULL);
#if PY_MAJOR_VERSION >= 3
mod = PyModule_Create(&dbapimodule);
#else
mod = Py_InitModule("_dbapi", devsup_methods);
#endif
pysuptable = PySet_New(NULL);
if(!pysuptable)
return;
MODINIT_RET(NULL);
PyModule_AddObject(mod, "_supports", pysuptable);
hookdict = PyDict_New();
if(!hookdict)
return;
MODINIT_RET(NULL);
PyModule_AddObject(mod, "_hooks", hookdict);
for(st = statenames; st->name; st++) {
@ -231,6 +208,43 @@ static void init_dbapi(void)
pyField_setup(mod);
pyRecord_setup(mod);
MODINIT_RET(mod);
}
static void cleanupPy(void *junk)
{
PyThreadState *state = PyGILState_GetThisThreadState();
PyEval_RestoreThread(state);
/* special "fake" hook for shutdown */
pyhook((initHookState)9999);
pyDBD_cleanup();
pyField_cleanup();
/* release extra reference for hooktable */
Py_DECREF(hooktable);
hooktable = NULL;
Py_Finalize();
}
/* Initialize the interpreter environment
*/
static void setupPyInit(void)
{
PyThreadState *state;
PyImport_AppendInittab("_dbapi", init_dbapi);
Py_Initialize();
PyEval_InitThreads();
state = PyEval_SaveThread();
epicsAtExit(&cleanupPy, NULL);
}
#include <iocsh.h>
@ -251,7 +265,7 @@ static void pySetupReg(void)
{
PyGILState_STATE state;
epicsThreadOnce(&setupPyOnceId, &setupPyOnce, NULL);
setupPyInit();
iocshRegister(&codeDef, &codeRun);
iocshRegister(&fileDef, &fileRun);
initHookRegister(&pyhook);

View File

@ -1,7 +1,7 @@
try:
import _dbapi
except ImportError:
import _nullapi as _dbapi
import devsup._nullapi as _dbapi
__all__ = ['verinfo']

View File

@ -1,7 +1,7 @@
import threading, sys, traceback
from util import Worker
from devsup.util import Worker
try:
import _dbapi
@ -60,14 +60,11 @@ class IOScanListBlock(object):
self.lock = threading.Lock()
self.scan1 = IOScanListBlock()
def run(self):
try:
while self.shouldRun():
time.sleep(1)
with self.lock:
self.scan1.interrupt()
finally:
self.finish()
while self.shouldRun():
time.sleep(1)
with self.lock:
self.scan1.interrupt()
class MySup(object):
def __init__(self, driver):
self.driver = driver
@ -140,9 +137,9 @@ class IOScanListThread(IOScanListBlock):
with cls._worker_lock:
if cls._worker is not None:
return cls._worker
import hooks
import devsup.hooks
T = Worker(max=cls.queuelength)
hooks.addHook('AtIocExit', T.join)
devsup.hooks.addHook('AtIocExit', T.join)
T.start()
cls._worker = T
return T
@ -162,12 +159,9 @@ class IOScanListThread(IOScanListBlock):
super(MyDriver,self).__init__()
self.scan1 = IOScanListThread()
def run(self):
try:
while self.shouldRun():
time.sleep(1)
self.scan1.interrupt()
finally:
self.finish()
while self.shouldRun():
time.sleep(1)
self.scan1.interrupt()
class MySup(object):
def __init__(self, driver):
@ -234,7 +228,7 @@ class Record(_dbapi._Record):
if F is _no_such_field:
raise ValueError()
return F
except KeyError, e:
except KeyError as e:
try:
fld = Field("%s.%s"%(self.name(), name))
except ValueError:

View File

@ -3,73 +3,51 @@ from __future__ import print_function
import threading, traceback
class StoppableThread(threading.Thread):
"""A thread which can be required to stop.
"""A thread which can be requested to stop.
The thread run() method should periodically call the shouldRun()
method if this yields False, the finish() should be called before returning.
This is really only feasible by sub-classing.
method and return if this yields False.
>>> class TestThread(StoppableThread):
... def __init__(self):
... super(TestThread,self).__init__()
... self.E=threading.Event()
... def run(self):
... try:
... import time
... self.E.set()
... while self.shouldRun():
... time.sleep(0.01)
... finally:
... self.finish()
... import time
... self.cur = threading.current_thread()
... self.E.set()
... while self.shouldRun():
... time.sleep(0.01)
>>> T = TestThread()
>>> T.start()
>>> T.E.wait()
True
>>> T.cur is T
True
>>> T.join()
>>> T.is_alive()
False
"""
def __init__(self, max=0):
super(StoppableThread, self).__init__()
self._run, self._stop = False, False
self._sevt, self._lock = threading.Event(), threading.Lock()
def running(self):
with self._lock:
return self._run and not self._stop
self.__stop = True
self.__lock = threading.Lock()
def start(self):
with self._lock:
assert not self._stop
self._run = True
self._sevt.clear()
with self.__lock:
self.__stop = False
super(StoppableThread, self).start()
def join(self):
with self._lock:
if not self._run:
return
self._stop = True
self._sevt.wait()
with self.__lock:
self.__stop = True
super(StoppableThread, self).join()
def shouldRun(self):
with self._lock:
return not self._stop
def finish(self):
with self._lock:
self._run = self._stop = False
self._sevt.set()
def run(self, *args, **kws):
try:
super(StoppableThread, self).start(*args, **kws)
finally:
self.finish()
with self.__lock:
return not self.__stop
class Worker(threading.Thread):
"""A threaded work queue.
@ -89,89 +67,77 @@ class Worker(threading.Thread):
"""
def __init__(self, max=0):
super(Worker, self).__init__()
self._run, self._stop = False, None
self._lock = threading.Lock()
self._update = threading.Condition(self._lock)
self.__stop = None
self.__lock = threading.Lock()
self.__update = threading.Condition(self.__lock)
self.maxQ, self._Q = max, []
def running(self):
with self._lock:
return self._run and not self._stop
def start(self):
with self._lock:
if self._run or self._stop:
return
super(Worker, self).start()
self._run = True
def join(self, flush=True):
self._update.acquire()
self.__update.acquire()
try:
if self._stop:
if self.__stop is not None:
raise RuntimeError("Someone else is already trying to stop me")
self._stop = threading.Event()
self._update.notify()
self.__stop = threading.Event()
self.__update.notify()
self._update.release()
self.__update.release()
try:
self._stop.wait()
self.__stop.wait()
finally:
self._update.acquire()
self.__update.acquire()
self._stop = None
assert not self._run
self.__stop = None
if flush:
self._Q = []
finally:
self._update.release()
self.__update.release()
def __len__(self):
with self._lock:
with self.__lock:
return len(self._Q)
def add(self, func, args=(), kws={}):
with self._lock:
if not self._run or self._stop:
with self.__lock:
if self.__stop is not None:
return
elif self.maxQ>0 and len(self._Q)>=self.maxQ:
raise RuntimeError('Worker queue full')
self._Q.append((func,args,kws))
self._update.notify()
self.__update.notify()
def run(self):
self._update.acquire()
self.__update.acquire()
try:
assert self._run
while True:
while self._stop is None and len(self._Q)==0:
self._update.wait()
while self.__stop is None and len(self._Q)==0:
self.__update.wait()
if self._stop is not None:
if self.__stop is not None:
break
F, A, K = self._Q.pop(0)
self._update.release()
self.__update.release()
try:
F(*A,**K)
except:
print('Error running',F,A,K)
traceback.print_exc()
finally:
self._update.acquire()
self._run = False
self._stop.set()
self.__update.acquire()
self.__stop.set()
except:
traceback.print_exc()
finally:
self._update.release()
self.__update.release()
if __name__=='__main__':
import doctest

View File

@ -1,13 +1,14 @@
from __future__ import print_function
class MySup(object):
def __init__(self, rec):
print rec, rec.field('VAL').fieldinfo()
print 'VAL', rec.VAL
print(rec, rec.field('VAL').fieldinfo())
print('VAL', rec.VAL)
def process(self, rec, reason):
rec.VAL = 1+rec.VAL
def detach(self, rec):
print 'test1 detach',rec.name()
print('test1 detach',rec.name())
def build(rec, args):
print 'test1 build for',rec.name()
print('test1 build for',rec.name())
return MySup(rec)

View File

@ -1,3 +1,4 @@
from __future__ import print_function
import threading, time
from devsup.hooks import addHook
@ -7,7 +8,7 @@ from devsup.util import StoppableThread
insts = {}
def done(obj):
print obj,'Expires'
print(obj,'Expires')
class Driver(StoppableThread):
def __init__(self, name):
@ -19,19 +20,17 @@ class Driver(StoppableThread):
addHook('AtIocExit', self.join)
def run(self):
try:
while self.shouldRun():
time.sleep(1.0)
val = self.value
self.value += 1
self.scan.interrupt(reason=val)
finally:
self.finish()
print('Starting driver',self)
while self.shouldRun():
time.sleep(1.0)
val = self.value
self.value += 1
self.scan.interrupt(reason=val)
def addDrv(name):
print 'Create driver',name
insts[name] = Driver(name)
print('Created driver',name,insts[name])
class Device(object):
def __init__(self, rec, args):
@ -39,7 +38,7 @@ class Device(object):
self.allowScan = self.driver.scan.add
def detach(self, rec):
print 'detach',rec
print('detach',rec)
def process(self, rec, data):
if data is not None: