Skip to content

Commit

Permalink
Wrap render function in SWIG threads macro, to disable Python GIL
Browse files Browse the repository at this point in the history
  • Loading branch information
stephen322 committed Oct 4, 2023
1 parent 95a43d6 commit 8738451
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 77 deletions.
11 changes: 11 additions & 0 deletions library/rpi_ws281x.i
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SWIG interface file to define rpi_ws281x library python wrapper.
// Author: Tony DiCola (tony@tonydicola.com), Jeremy Garff (jer@jers.net)

%nothread;

// Define module name rpi_ws281x. This will actually be imported under
// the name _rpi_ws281x following the SWIG & Python conventions.
%module rpi_ws281x
Expand Down Expand Up @@ -92,3 +94,12 @@ static int convert_iarray(PyObject *input, uint8_t *ptr, int size) {
return &ws->channel[channelnum];
}
%}

%thread;
%inline %{
ws2811_return_t ws2811_render_nogil(ws2811_t *ws2811)
{
return ws2811_render(ws2811);
}
%}
%nothread;
98 changes: 21 additions & 77 deletions library/rpi_ws281x.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# the SWIG interface file instead.

from sys import version_info as _swig_python_version_info

if _swig_python_version_info < (2, 7, 0):
raise RuntimeError("Python 2.7 or later required")

Expand All @@ -20,17 +19,12 @@
except ImportError:
import __builtin__


def _swig_repr(self):
try:
strthis = "proxy of " + self.this.__repr__()
except __builtin__.Exception:
strthis = ""
return "<%s.%s; %s >" % (
self.__class__.__module__,
self.__class__.__name__,
strthis,
)
return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)


def _swig_setattr_nondynamic_instance_variable(set):
Expand All @@ -43,7 +37,6 @@ def set_instance_attr(self, name, value):
set(self, name, value)
else:
raise AttributeError("You cannot add instance attributes to %s" % self)

return set_instance_attr


Expand All @@ -53,22 +46,18 @@ def set_class_attr(cls, name, value):
set(cls, name, value)
else:
raise AttributeError("You cannot add class attributes to %s" % cls)

return set_class_attr


def _swig_add_metaclass(metaclass):
"""Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""

def wrapper(cls):
return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())

return wrapper


class _SwigNonDynamicMeta(type):
"""Meta class to enforce nondynamic attributes (no new attributes) for a class"""

__setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)


Expand All @@ -89,83 +78,42 @@ class _SwigNonDynamicMeta(type):
WS2812_STRIP = _rpi_ws281x.WS2812_STRIP
SK6812_STRIP = _rpi_ws281x.SK6812_STRIP
SK6812W_STRIP = _rpi_ws281x.SK6812W_STRIP


class ws2811_channel_t(object):
thisown = property(
lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag"
)
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
gpionum = property(
_rpi_ws281x.ws2811_channel_t_gpionum_get,
_rpi_ws281x.ws2811_channel_t_gpionum_set,
)
invert = property(
_rpi_ws281x.ws2811_channel_t_invert_get, _rpi_ws281x.ws2811_channel_t_invert_set
)
count = property(
_rpi_ws281x.ws2811_channel_t_count_get, _rpi_ws281x.ws2811_channel_t_count_set
)
strip_type = property(
_rpi_ws281x.ws2811_channel_t_strip_type_get,
_rpi_ws281x.ws2811_channel_t_strip_type_set,
)
leds = property(
_rpi_ws281x.ws2811_channel_t_leds_get, _rpi_ws281x.ws2811_channel_t_leds_set
)
brightness = property(
_rpi_ws281x.ws2811_channel_t_brightness_get,
_rpi_ws281x.ws2811_channel_t_brightness_set,
)
wshift = property(
_rpi_ws281x.ws2811_channel_t_wshift_get, _rpi_ws281x.ws2811_channel_t_wshift_set
)
rshift = property(
_rpi_ws281x.ws2811_channel_t_rshift_get, _rpi_ws281x.ws2811_channel_t_rshift_set
)
gshift = property(
_rpi_ws281x.ws2811_channel_t_gshift_get, _rpi_ws281x.ws2811_channel_t_gshift_set
)
bshift = property(
_rpi_ws281x.ws2811_channel_t_bshift_get, _rpi_ws281x.ws2811_channel_t_bshift_set
)
gamma = property(
_rpi_ws281x.ws2811_channel_t_gamma_get, _rpi_ws281x.ws2811_channel_t_gamma_set
)
gpionum = property(_rpi_ws281x.ws2811_channel_t_gpionum_get, _rpi_ws281x.ws2811_channel_t_gpionum_set)
invert = property(_rpi_ws281x.ws2811_channel_t_invert_get, _rpi_ws281x.ws2811_channel_t_invert_set)
count = property(_rpi_ws281x.ws2811_channel_t_count_get, _rpi_ws281x.ws2811_channel_t_count_set)
strip_type = property(_rpi_ws281x.ws2811_channel_t_strip_type_get, _rpi_ws281x.ws2811_channel_t_strip_type_set)
leds = property(_rpi_ws281x.ws2811_channel_t_leds_get, _rpi_ws281x.ws2811_channel_t_leds_set)
brightness = property(_rpi_ws281x.ws2811_channel_t_brightness_get, _rpi_ws281x.ws2811_channel_t_brightness_set)
wshift = property(_rpi_ws281x.ws2811_channel_t_wshift_get, _rpi_ws281x.ws2811_channel_t_wshift_set)
rshift = property(_rpi_ws281x.ws2811_channel_t_rshift_get, _rpi_ws281x.ws2811_channel_t_rshift_set)
gshift = property(_rpi_ws281x.ws2811_channel_t_gshift_get, _rpi_ws281x.ws2811_channel_t_gshift_set)
bshift = property(_rpi_ws281x.ws2811_channel_t_bshift_get, _rpi_ws281x.ws2811_channel_t_bshift_set)
gamma = property(_rpi_ws281x.ws2811_channel_t_gamma_get, _rpi_ws281x.ws2811_channel_t_gamma_set)

def __init__(self):
_rpi_ws281x.ws2811_channel_t_swiginit(self, _rpi_ws281x.new_ws2811_channel_t())

__swig_destroy__ = _rpi_ws281x.delete_ws2811_channel_t


# Register ws2811_channel_t in _rpi_ws281x:
_rpi_ws281x.ws2811_channel_t_swigregister(ws2811_channel_t)


class ws2811_t(object):
thisown = property(
lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag"
)
thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
__repr__ = _swig_repr
render_wait_time = property(
_rpi_ws281x.ws2811_t_render_wait_time_get,
_rpi_ws281x.ws2811_t_render_wait_time_set,
)
render_wait_time = property(_rpi_ws281x.ws2811_t_render_wait_time_get, _rpi_ws281x.ws2811_t_render_wait_time_set)
device = property(_rpi_ws281x.ws2811_t_device_get, _rpi_ws281x.ws2811_t_device_set)
rpi_hw = property(_rpi_ws281x.ws2811_t_rpi_hw_get, _rpi_ws281x.ws2811_t_rpi_hw_set)
freq = property(_rpi_ws281x.ws2811_t_freq_get, _rpi_ws281x.ws2811_t_freq_set)
dmanum = property(_rpi_ws281x.ws2811_t_dmanum_get, _rpi_ws281x.ws2811_t_dmanum_set)
channel = property(
_rpi_ws281x.ws2811_t_channel_get, _rpi_ws281x.ws2811_t_channel_set
)
channel = property(_rpi_ws281x.ws2811_t_channel_get, _rpi_ws281x.ws2811_t_channel_set)

def __init__(self):
_rpi_ws281x.ws2811_t_swiginit(self, _rpi_ws281x.new_ws2811_t())

__swig_destroy__ = _rpi_ws281x.delete_ws2811_t


# Register ws2811_t in _rpi_ws281x:
_rpi_ws281x.ws2811_t_swigregister(ws2811_t)

Expand All @@ -186,38 +134,34 @@ def __init__(self):
WS2811_ERROR_SPI_TRANSFER = _rpi_ws281x.WS2811_ERROR_SPI_TRANSFER
WS2811_RETURN_STATE_COUNT = _rpi_ws281x.WS2811_RETURN_STATE_COUNT


def ws2811_init(ws2811):
return _rpi_ws281x.ws2811_init(ws2811)


def ws2811_fini(ws2811):
return _rpi_ws281x.ws2811_fini(ws2811)


def ws2811_render(ws2811):
return _rpi_ws281x.ws2811_render(ws2811)


def ws2811_wait(ws2811):
return _rpi_ws281x.ws2811_wait(ws2811)


def ws2811_get_return_t_str(state):
return _rpi_ws281x.ws2811_get_return_t_str(state)


def ws2811_set_custom_gamma_factor(ws2811, gamma_factor):
return _rpi_ws281x.ws2811_set_custom_gamma_factor(ws2811, gamma_factor)


def ws2811_led_get(channel, lednum):
return _rpi_ws281x.ws2811_led_get(channel, lednum)


def ws2811_led_set(channel, lednum, color):
return _rpi_ws281x.ws2811_led_set(channel, lednum, color)


def ws2811_channel_get(ws, channelnum):
return _rpi_ws281x.ws2811_channel_get(ws, channelnum)

def ws2811_render_nogil(ws2811):
return _rpi_ws281x.ws2811_render_nogil(ws2811)


7 changes: 7 additions & 0 deletions library/rpi_ws281x/rpi_ws281x.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ def show(self):
str_resp = ws.ws2811_get_return_t_str(resp)
raise RuntimeError('ws2811_render failed with code {0} ({1})'.format(resp, str_resp))

def show_nogil(self):
"""Update the display with the data from the LED buffer, with no Global-Interpreter-Lock."""
resp = ws.ws2811_render_nogil(self._leds)
if resp != 0:
str_resp = ws.ws2811_get_return_t_str(resp)
raise RuntimeError('ws2811_render failed with code {0} ({1})'.format(resp, str_resp))

def setPixelColor(self, n, color):
"""Set LED at position n to the provided 24-bit color value (in RGB order).
"""
Expand Down
38 changes: 38 additions & 0 deletions library/rpi_ws281x_wrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#define SWIGPYTHON
#endif

#define SWIG_PYTHON_THREADS
#define SWIG_PYTHON_DIRECTOR_NO_VTABLE

/* -----------------------------------------------------------------------------
Expand Down Expand Up @@ -3132,6 +3133,12 @@ SWIG_FromCharPtr(const char *cptr)
return &ws->channel[channelnum];
}


ws2811_return_t ws2811_render_nogil(ws2811_t *ws2811)
{
return ws2811_render(ws2811);
}

#ifdef __cplusplus
extern "C" {
#endif
Expand Down Expand Up @@ -4370,6 +4377,33 @@ SWIGINTERN PyObject *_wrap_ws2811_channel_get(PyObject *SWIGUNUSEDPARM(self), Py
}


SWIGINTERN PyObject *_wrap_ws2811_render_nogil(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *resultobj = 0;
ws2811_t *arg1 = (ws2811_t *) 0 ;
void *argp1 = 0 ;
int res1 = 0 ;
PyObject *swig_obj[1] ;
ws2811_return_t result;

if (!args) SWIG_fail;
swig_obj[0] = args;
res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ws2811_t, 0 | 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ws2811_render_nogil" "', argument " "1"" of type '" "ws2811_t *""'");
}
arg1 = (ws2811_t *)(argp1);
{
SWIG_PYTHON_THREAD_BEGIN_ALLOW;
result = (ws2811_return_t)ws2811_render_nogil(arg1);
SWIG_PYTHON_THREAD_END_ALLOW;
}
resultobj = SWIG_From_int((int)(result));
return resultobj;
fail:
return NULL;
}


static PyMethodDef SwigMethods[] = {
{ "SWIG_PyInstanceMethod_New", SWIG_PyInstanceMethod_New, METH_O, NULL},
{ "ws2811_channel_t_gpionum_set", _wrap_ws2811_channel_t_gpionum_set, METH_VARARGS, NULL},
Expand Down Expand Up @@ -4423,6 +4457,7 @@ static PyMethodDef SwigMethods[] = {
{ "ws2811_led_get", _wrap_ws2811_led_get, METH_VARARGS, NULL},
{ "ws2811_led_set", _wrap_ws2811_led_set, METH_VARARGS, NULL},
{ "ws2811_channel_get", _wrap_ws2811_channel_get, METH_VARARGS, NULL},
{ "ws2811_render_nogil", _wrap_ws2811_render_nogil, METH_O, NULL},
{ NULL, NULL, 0, NULL }
};

Expand Down Expand Up @@ -5263,6 +5298,9 @@ SWIG_init(void) {
SWIG_Python_SetConstant(d, "WS2811_ERROR_SPI_SETUP",SWIG_From_int((int)(WS2811_ERROR_SPI_SETUP)));
SWIG_Python_SetConstant(d, "WS2811_ERROR_SPI_TRANSFER",SWIG_From_int((int)(WS2811_ERROR_SPI_TRANSFER)));
SWIG_Python_SetConstant(d, "WS2811_RETURN_STATE_COUNT",SWIG_From_int((int)(WS2811_RETURN_STATE_COUNT)));

/* Initialize threading */
SWIG_PYTHON_INITIALIZE_THREADS;
#if PY_VERSION_HEX >= 0x03000000
return m;
#else
Expand Down

0 comments on commit 8738451

Please sign in to comment.