Skip to content

Commit 8738451

Browse files
committed
Wrap render function in SWIG threads macro, to disable Python GIL
1 parent 95a43d6 commit 8738451

File tree

4 files changed

+77
-77
lines changed

4 files changed

+77
-77
lines changed

library/rpi_ws281x.i

+11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// SWIG interface file to define rpi_ws281x library python wrapper.
22
// Author: Tony DiCola ([email protected]), Jeremy Garff ([email protected])
33

4+
%nothread;
5+
46
// Define module name rpi_ws281x. This will actually be imported under
57
// the name _rpi_ws281x following the SWIG & Python conventions.
68
%module rpi_ws281x
@@ -92,3 +94,12 @@ static int convert_iarray(PyObject *input, uint8_t *ptr, int size) {
9294
return &ws->channel[channelnum];
9395
}
9496
%}
97+
98+
%thread;
99+
%inline %{
100+
ws2811_return_t ws2811_render_nogil(ws2811_t *ws2811)
101+
{
102+
return ws2811_render(ws2811);
103+
}
104+
%}
105+
%nothread;

library/rpi_ws281x.py

+21-77
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
# the SWIG interface file instead.
66

77
from sys import version_info as _swig_python_version_info
8-
98
if _swig_python_version_info < (2, 7, 0):
109
raise RuntimeError("Python 2.7 or later required")
1110

@@ -20,17 +19,12 @@
2019
except ImportError:
2120
import __builtin__
2221

23-
2422
def _swig_repr(self):
2523
try:
2624
strthis = "proxy of " + self.this.__repr__()
2725
except __builtin__.Exception:
2826
strthis = ""
29-
return "<%s.%s; %s >" % (
30-
self.__class__.__module__,
31-
self.__class__.__name__,
32-
strthis,
33-
)
27+
return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)
3428

3529

3630
def _swig_setattr_nondynamic_instance_variable(set):
@@ -43,7 +37,6 @@ def set_instance_attr(self, name, value):
4337
set(self, name, value)
4438
else:
4539
raise AttributeError("You cannot add instance attributes to %s" % self)
46-
4740
return set_instance_attr
4841

4942

@@ -53,22 +46,18 @@ def set_class_attr(cls, name, value):
5346
set(cls, name, value)
5447
else:
5548
raise AttributeError("You cannot add class attributes to %s" % cls)
56-
5749
return set_class_attr
5850

5951

6052
def _swig_add_metaclass(metaclass):
6153
"""Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""
62-
6354
def wrapper(cls):
6455
return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())
65-
6656
return wrapper
6757

6858

6959
class _SwigNonDynamicMeta(type):
7060
"""Meta class to enforce nondynamic attributes (no new attributes) for a class"""
71-
7261
__setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)
7362

7463

@@ -89,83 +78,42 @@ class _SwigNonDynamicMeta(type):
8978
WS2812_STRIP = _rpi_ws281x.WS2812_STRIP
9079
SK6812_STRIP = _rpi_ws281x.SK6812_STRIP
9180
SK6812W_STRIP = _rpi_ws281x.SK6812W_STRIP
92-
93-
9481
class ws2811_channel_t(object):
95-
thisown = property(
96-
lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag"
97-
)
82+
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
9883
__repr__ = _swig_repr
99-
gpionum = property(
100-
_rpi_ws281x.ws2811_channel_t_gpionum_get,
101-
_rpi_ws281x.ws2811_channel_t_gpionum_set,
102-
)
103-
invert = property(
104-
_rpi_ws281x.ws2811_channel_t_invert_get, _rpi_ws281x.ws2811_channel_t_invert_set
105-
)
106-
count = property(
107-
_rpi_ws281x.ws2811_channel_t_count_get, _rpi_ws281x.ws2811_channel_t_count_set
108-
)
109-
strip_type = property(
110-
_rpi_ws281x.ws2811_channel_t_strip_type_get,
111-
_rpi_ws281x.ws2811_channel_t_strip_type_set,
112-
)
113-
leds = property(
114-
_rpi_ws281x.ws2811_channel_t_leds_get, _rpi_ws281x.ws2811_channel_t_leds_set
115-
)
116-
brightness = property(
117-
_rpi_ws281x.ws2811_channel_t_brightness_get,
118-
_rpi_ws281x.ws2811_channel_t_brightness_set,
119-
)
120-
wshift = property(
121-
_rpi_ws281x.ws2811_channel_t_wshift_get, _rpi_ws281x.ws2811_channel_t_wshift_set
122-
)
123-
rshift = property(
124-
_rpi_ws281x.ws2811_channel_t_rshift_get, _rpi_ws281x.ws2811_channel_t_rshift_set
125-
)
126-
gshift = property(
127-
_rpi_ws281x.ws2811_channel_t_gshift_get, _rpi_ws281x.ws2811_channel_t_gshift_set
128-
)
129-
bshift = property(
130-
_rpi_ws281x.ws2811_channel_t_bshift_get, _rpi_ws281x.ws2811_channel_t_bshift_set
131-
)
132-
gamma = property(
133-
_rpi_ws281x.ws2811_channel_t_gamma_get, _rpi_ws281x.ws2811_channel_t_gamma_set
134-
)
84+
gpionum = property(_rpi_ws281x.ws2811_channel_t_gpionum_get, _rpi_ws281x.ws2811_channel_t_gpionum_set)
85+
invert = property(_rpi_ws281x.ws2811_channel_t_invert_get, _rpi_ws281x.ws2811_channel_t_invert_set)
86+
count = property(_rpi_ws281x.ws2811_channel_t_count_get, _rpi_ws281x.ws2811_channel_t_count_set)
87+
strip_type = property(_rpi_ws281x.ws2811_channel_t_strip_type_get, _rpi_ws281x.ws2811_channel_t_strip_type_set)
88+
leds = property(_rpi_ws281x.ws2811_channel_t_leds_get, _rpi_ws281x.ws2811_channel_t_leds_set)
89+
brightness = property(_rpi_ws281x.ws2811_channel_t_brightness_get, _rpi_ws281x.ws2811_channel_t_brightness_set)
90+
wshift = property(_rpi_ws281x.ws2811_channel_t_wshift_get, _rpi_ws281x.ws2811_channel_t_wshift_set)
91+
rshift = property(_rpi_ws281x.ws2811_channel_t_rshift_get, _rpi_ws281x.ws2811_channel_t_rshift_set)
92+
gshift = property(_rpi_ws281x.ws2811_channel_t_gshift_get, _rpi_ws281x.ws2811_channel_t_gshift_set)
93+
bshift = property(_rpi_ws281x.ws2811_channel_t_bshift_get, _rpi_ws281x.ws2811_channel_t_bshift_set)
94+
gamma = property(_rpi_ws281x.ws2811_channel_t_gamma_get, _rpi_ws281x.ws2811_channel_t_gamma_set)
13595

13696
def __init__(self):
13797
_rpi_ws281x.ws2811_channel_t_swiginit(self, _rpi_ws281x.new_ws2811_channel_t())
138-
13998
__swig_destroy__ = _rpi_ws281x.delete_ws2811_channel_t
14099

141-
142100
# Register ws2811_channel_t in _rpi_ws281x:
143101
_rpi_ws281x.ws2811_channel_t_swigregister(ws2811_channel_t)
144102

145-
146103
class ws2811_t(object):
147-
thisown = property(
148-
lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag"
149-
)
104+
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
150105
__repr__ = _swig_repr
151-
render_wait_time = property(
152-
_rpi_ws281x.ws2811_t_render_wait_time_get,
153-
_rpi_ws281x.ws2811_t_render_wait_time_set,
154-
)
106+
render_wait_time = property(_rpi_ws281x.ws2811_t_render_wait_time_get, _rpi_ws281x.ws2811_t_render_wait_time_set)
155107
device = property(_rpi_ws281x.ws2811_t_device_get, _rpi_ws281x.ws2811_t_device_set)
156108
rpi_hw = property(_rpi_ws281x.ws2811_t_rpi_hw_get, _rpi_ws281x.ws2811_t_rpi_hw_set)
157109
freq = property(_rpi_ws281x.ws2811_t_freq_get, _rpi_ws281x.ws2811_t_freq_set)
158110
dmanum = property(_rpi_ws281x.ws2811_t_dmanum_get, _rpi_ws281x.ws2811_t_dmanum_set)
159-
channel = property(
160-
_rpi_ws281x.ws2811_t_channel_get, _rpi_ws281x.ws2811_t_channel_set
161-
)
111+
channel = property(_rpi_ws281x.ws2811_t_channel_get, _rpi_ws281x.ws2811_t_channel_set)
162112

163113
def __init__(self):
164114
_rpi_ws281x.ws2811_t_swiginit(self, _rpi_ws281x.new_ws2811_t())
165-
166115
__swig_destroy__ = _rpi_ws281x.delete_ws2811_t
167116

168-
169117
# Register ws2811_t in _rpi_ws281x:
170118
_rpi_ws281x.ws2811_t_swigregister(ws2811_t)
171119

@@ -186,38 +134,34 @@ def __init__(self):
186134
WS2811_ERROR_SPI_TRANSFER = _rpi_ws281x.WS2811_ERROR_SPI_TRANSFER
187135
WS2811_RETURN_STATE_COUNT = _rpi_ws281x.WS2811_RETURN_STATE_COUNT
188136

189-
190137
def ws2811_init(ws2811):
191138
return _rpi_ws281x.ws2811_init(ws2811)
192139

193-
194140
def ws2811_fini(ws2811):
195141
return _rpi_ws281x.ws2811_fini(ws2811)
196142

197-
198143
def ws2811_render(ws2811):
199144
return _rpi_ws281x.ws2811_render(ws2811)
200145

201-
202146
def ws2811_wait(ws2811):
203147
return _rpi_ws281x.ws2811_wait(ws2811)
204148

205-
206149
def ws2811_get_return_t_str(state):
207150
return _rpi_ws281x.ws2811_get_return_t_str(state)
208151

209-
210152
def ws2811_set_custom_gamma_factor(ws2811, gamma_factor):
211153
return _rpi_ws281x.ws2811_set_custom_gamma_factor(ws2811, gamma_factor)
212154

213-
214155
def ws2811_led_get(channel, lednum):
215156
return _rpi_ws281x.ws2811_led_get(channel, lednum)
216157

217-
218158
def ws2811_led_set(channel, lednum, color):
219159
return _rpi_ws281x.ws2811_led_set(channel, lednum, color)
220160

221-
222161
def ws2811_channel_get(ws, channelnum):
223162
return _rpi_ws281x.ws2811_channel_get(ws, channelnum)
163+
164+
def ws2811_render_nogil(ws2811):
165+
return _rpi_ws281x.ws2811_render_nogil(ws2811)
166+
167+

library/rpi_ws281x/rpi_ws281x.py

+7
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ def show(self):
149149
str_resp = ws.ws2811_get_return_t_str(resp)
150150
raise RuntimeError('ws2811_render failed with code {0} ({1})'.format(resp, str_resp))
151151

152+
def show_nogil(self):
153+
"""Update the display with the data from the LED buffer, with no Global-Interpreter-Lock."""
154+
resp = ws.ws2811_render_nogil(self._leds)
155+
if resp != 0:
156+
str_resp = ws.ws2811_get_return_t_str(resp)
157+
raise RuntimeError('ws2811_render failed with code {0} ({1})'.format(resp, str_resp))
158+
152159
def setPixelColor(self, n, color):
153160
"""Set LED at position n to the provided 24-bit color value (in RGB order).
154161
"""

library/rpi_ws281x_wrap.c

+38
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define SWIGPYTHON
1414
#endif
1515

16+
#define SWIG_PYTHON_THREADS
1617
#define SWIG_PYTHON_DIRECTOR_NO_VTABLE
1718

1819
/* -----------------------------------------------------------------------------
@@ -3132,6 +3133,12 @@ SWIG_FromCharPtr(const char *cptr)
31323133
return &ws->channel[channelnum];
31333134
}
31343135

3136+
3137+
ws2811_return_t ws2811_render_nogil(ws2811_t *ws2811)
3138+
{
3139+
return ws2811_render(ws2811);
3140+
}
3141+
31353142
#ifdef __cplusplus
31363143
extern "C" {
31373144
#endif
@@ -4370,6 +4377,33 @@ SWIGINTERN PyObject *_wrap_ws2811_channel_get(PyObject *SWIGUNUSEDPARM(self), Py
43704377
}
43714378

43724379

4380+
SWIGINTERN PyObject *_wrap_ws2811_render_nogil(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
4381+
PyObject *resultobj = 0;
4382+
ws2811_t *arg1 = (ws2811_t *) 0 ;
4383+
void *argp1 = 0 ;
4384+
int res1 = 0 ;
4385+
PyObject *swig_obj[1] ;
4386+
ws2811_return_t result;
4387+
4388+
if (!args) SWIG_fail;
4389+
swig_obj[0] = args;
4390+
res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ws2811_t, 0 | 0 );
4391+
if (!SWIG_IsOK(res1)) {
4392+
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ws2811_render_nogil" "', argument " "1"" of type '" "ws2811_t *""'");
4393+
}
4394+
arg1 = (ws2811_t *)(argp1);
4395+
{
4396+
SWIG_PYTHON_THREAD_BEGIN_ALLOW;
4397+
result = (ws2811_return_t)ws2811_render_nogil(arg1);
4398+
SWIG_PYTHON_THREAD_END_ALLOW;
4399+
}
4400+
resultobj = SWIG_From_int((int)(result));
4401+
return resultobj;
4402+
fail:
4403+
return NULL;
4404+
}
4405+
4406+
43734407
static PyMethodDef SwigMethods[] = {
43744408
{ "SWIG_PyInstanceMethod_New", SWIG_PyInstanceMethod_New, METH_O, NULL},
43754409
{ "ws2811_channel_t_gpionum_set", _wrap_ws2811_channel_t_gpionum_set, METH_VARARGS, NULL},
@@ -4423,6 +4457,7 @@ static PyMethodDef SwigMethods[] = {
44234457
{ "ws2811_led_get", _wrap_ws2811_led_get, METH_VARARGS, NULL},
44244458
{ "ws2811_led_set", _wrap_ws2811_led_set, METH_VARARGS, NULL},
44254459
{ "ws2811_channel_get", _wrap_ws2811_channel_get, METH_VARARGS, NULL},
4460+
{ "ws2811_render_nogil", _wrap_ws2811_render_nogil, METH_O, NULL},
44264461
{ NULL, NULL, 0, NULL }
44274462
};
44284463

@@ -5263,6 +5298,9 @@ SWIG_init(void) {
52635298
SWIG_Python_SetConstant(d, "WS2811_ERROR_SPI_SETUP",SWIG_From_int((int)(WS2811_ERROR_SPI_SETUP)));
52645299
SWIG_Python_SetConstant(d, "WS2811_ERROR_SPI_TRANSFER",SWIG_From_int((int)(WS2811_ERROR_SPI_TRANSFER)));
52655300
SWIG_Python_SetConstant(d, "WS2811_RETURN_STATE_COUNT",SWIG_From_int((int)(WS2811_RETURN_STATE_COUNT)));
5301+
5302+
/* Initialize threading */
5303+
SWIG_PYTHON_INITIALIZE_THREADS;
52665304
#if PY_VERSION_HEX >= 0x03000000
52675305
return m;
52685306
#else

0 commit comments

Comments
 (0)