Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

add increment/decrement functions

Add functions to atomically increment/decrement an integer without lock.
While I'm here add functions to compare and swap a value and read
atomically an integer.
  • Loading branch information...
commit 0d22b8fbc59df8004af820f0b1c8ce58d54ea139 1 parent fe2d68d
@benoitc authored
Showing with 184 additions and 2 deletions.
  1. +1 −1  .gitignore
  2. +135 −0 flower/core/sync.c
  3. +6 −1 setup.py
  4. +42 −0 test/test_sync.py
View
2  .gitignore
@@ -11,7 +11,7 @@ setuptools-*
.Python
distribute-0.6.8-py2.6.egg
distribute-0.6.8.tar.gz
-flower.egg-info
+*.egg-info
nohup.out
.coverage
doc/.sass-cache
View
135 flower/core/sync.c
@@ -0,0 +1,135 @@
+/* -*- coding: utf-8 -
+ *
+ * This file is part of flower. See the NOTICE for more information. */
+
+#include <pthread.h>
+#if defined( __ia64__ ) && defined( __INTEL_COMPILER )
+# include <ia64intrin.h>
+#endif
+#include <stdio.h>
+
+#include "Python.h"
+#include "intobject.h"
+
+struct module_state {
+ PyObject *error;
+};
+
+#if PY_MAJOR_VERSION >= 3
+#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
+#else
+#define GETSTATE(m) (&_state)
+static struct module_state _state;
+#endif
+
+static
+PyObject* compare_and_swap(PyObject *self, PyObject *args)
+{
+ int oldval, newval, r;
+ if (!PyArg_ParseTuple(args, "ii", &oldval, &newval))
+ return NULL;
+ r = __sync_bool_compare_and_swap(&oldval, oldval, newval);
+
+ return Py_BuildValue("i", oldval);
+}
+
+static
+PyObject* increment(PyObject *self, PyObject *args)
+{
+ int val;
+ if (!PyArg_ParseTuple(args, "i", &val))
+ return NULL;
+
+ return Py_BuildValue("i", __sync_add_and_fetch(&val, 1));
+}
+
+static
+PyObject* decrement(PyObject *self, PyObject *args)
+{
+ int val;
+ if (!PyArg_ParseTuple(args, "i", &val))
+ return NULL;
+
+ return Py_BuildValue("i", __sync_sub_and_fetch(&val, 1));
+}
+
+static
+PyObject* atomic_read(PyObject *self, PyObject *args)
+{
+ int val;
+ if (!PyArg_ParseTuple(args, "i", &val))
+ return NULL;
+
+ return Py_BuildValue("i", __sync_add_and_fetch(&val, 0));
+}
+
+
+static PyMethodDef
+sync_methods[] = {
+ {"compare_and_swap", compare_and_swap, METH_VARARGS,
+ "Atomically compare and swap 2 integers"},
+ {"increment", increment, METH_VARARGS, "Atomically increment an integer"},
+ {"decrement", decrement, METH_VARARGS, "Atomically decrement an integer"},
+ {"atomic_read", atomic_read, METH_VARARGS, "Atomically read an integer"},
+ {NULL, NULL, 0, NULL}
+};
+
+#if PY_MAJOR_VERSION >= 3
+
+static int sync_traverse(PyObject *m, visitproc visit, void *arg) {
+ Py_VISIT(GETSTATE(m)->error);
+ return 0;
+}
+
+static int sync_clear(PyObject *m) {
+ Py_CLEAR(GETSTATE(m)->error);
+ return 0;
+}
+
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "sync",
+ NULL,
+ sizeof(struct module_state),
+ sync_methods,
+ NULL,
+ sync_traverse,
+ sync_clear,
+ NULL
+};
+
+#define INITERROR return NULL
+
+PyObject *
+PyInit_sync(void)
+
+#else
+#define INITERROR return
+
+void
+initsync(void)
+#endif
+{
+#if PY_MAJOR_VERSION >= 3
+ PyObject *module = PyModule_Create(&moduledef);
+#else
+ PyObject *module = Py_InitModule("sync", sync_methods);
+#endif
+
+ if (module == NULL)
+ INITERROR;
+ struct module_state *st = GETSTATE(module);
+
+ st->error = PyErr_NewException("sync.Error", NULL, NULL);
+ if (st->error == NULL) {
+ Py_DECREF(module);
+ INITERROR;
+ }
+
+#if PY_MAJOR_VERSION >= 3
+ return module;
+#endif
+}
+
+
View
7 setup.py
@@ -1,5 +1,6 @@
import os
-from setuptools import setup, find_packages
+from setuptools import setup, find_packages, Extension
+
import sys
py_version = sys.version_info[:2]
@@ -45,5 +46,9 @@
author = 'Benoit Chesneau',
author_email = 'benoitc@e-engura.org',
packages=find_packages(),
+ ext_modules = [
+ Extension("flower.core.sync", ["flower/core/sync.c"])
+ ],
+
install_requires = ['pyuv', 'greenlet', 'six'],
data_files = DATA_FILES)
View
42 test/test_sync.py
@@ -0,0 +1,42 @@
+
+from flower.core.sync import *
+
+def test_increment():
+ i = 0
+ i = increment(i)
+ assert i == 1
+
+ i = increment(i)
+ assert i == 2
+
+
+def test_decrement():
+ i = 0
+ i = decrement(i)
+ assert i == -1
+
+ i = decrement(i)
+ assert i == -2
+
+def test_combine():
+ i = 1
+ i = decrement(i)
+ assert i == 0
+ i = increment(i)
+ assert i == 1
+
+
+def test_read():
+ i = 10
+ v = atomic_read(i)
+ assert i == v
+
+def test_compare_and_swap():
+ a, b = 1, 2
+ a = compare_and_swap(a, b)
+
+ assert a == b
+
+ a, b = 1, 1
+ r = compare_and_swap(a, b)
+ assert a == 1
Please sign in to comment.
Something went wrong with that request. Please try again.