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

View File

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

View File

@ -1,6 +1,16 @@
#ifndef PYDEVSUP_H #ifndef PYDEVSUP_H
#define 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); void pyDBD_cleanup(void);
int pyField_prepare(void); int pyField_prepare(void);

View File

@ -64,43 +64,6 @@ static pystate statenames[] = {
}; };
#undef INITST #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) void evalPy(const char* code)
{ {
PyGILState_STATE state; PyGILState_STATE state;
@ -193,8 +156,18 @@ static PyMethodDef devsup_methods[] = {
{NULL, NULL, 0, NULL} {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 */ /* initialize "magic" builtin module */
static void init_dbapi(void) PyMODINIT_FUNC init_dbapi(void)
{ {
PyObject *mod, *hookdict, *pysuptable; PyObject *mod, *hookdict, *pysuptable;
pystate *st; pystate *st;
@ -203,23 +176,27 @@ static void init_dbapi(void)
hooktable = PyDict_New(); hooktable = PyDict_New();
if(!hooktable) if(!hooktable)
return; MODINIT_RET(NULL);
if(pyField_prepare()) if(pyField_prepare())
return; MODINIT_RET(NULL);
if(pyRecord_prepare()) if(pyRecord_prepare())
return; MODINIT_RET(NULL);
#if PY_MAJOR_VERSION >= 3
mod = PyModule_Create(&dbapimodule);
#else
mod = Py_InitModule("_dbapi", devsup_methods); mod = Py_InitModule("_dbapi", devsup_methods);
#endif
pysuptable = PySet_New(NULL); pysuptable = PySet_New(NULL);
if(!pysuptable) if(!pysuptable)
return; MODINIT_RET(NULL);
PyModule_AddObject(mod, "_supports", pysuptable); PyModule_AddObject(mod, "_supports", pysuptable);
hookdict = PyDict_New(); hookdict = PyDict_New();
if(!hookdict) if(!hookdict)
return; MODINIT_RET(NULL);
PyModule_AddObject(mod, "_hooks", hookdict); PyModule_AddObject(mod, "_hooks", hookdict);
for(st = statenames; st->name; st++) { for(st = statenames; st->name; st++) {
@ -231,6 +208,43 @@ static void init_dbapi(void)
pyField_setup(mod); pyField_setup(mod);
pyRecord_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> #include <iocsh.h>
@ -251,7 +265,7 @@ static void pySetupReg(void)
{ {
PyGILState_STATE state; PyGILState_STATE state;
epicsThreadOnce(&setupPyOnceId, &setupPyOnce, NULL); setupPyInit();
iocshRegister(&codeDef, &codeRun); iocshRegister(&codeDef, &codeRun);
iocshRegister(&fileDef, &fileRun); iocshRegister(&fileDef, &fileRun);
initHookRegister(&pyhook); initHookRegister(&pyhook);

View File

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

View File

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

View File

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

View File

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

View File

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