chiark / gitweb /
buffer.c: Add a lock count which pins a write-buffer's backing store.
[catacomb-python] / buffer.c
index 7a3bec7f57e54da8a049663a439eefbf0f76d318..5731c53c291d9333de51dc91fbb8f69c64e520cd 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -34,6 +34,7 @@ typedef struct buf_pyobj {
   PyObject_HEAD
   buf b;
   PyObject *sub;
+  unsigned lk;
 } buf_pyobj;
 
 static PyTypeObject *rbuf_pytype, *wbuf_pytype;
@@ -41,6 +42,7 @@ static PyTypeObject *rbuf_pytype, *wbuf_pytype;
 #define WBUF_PYCHECK(o) PyObject_TypeCheck((o), wbuf_pytype)
 #define BUF_B(o) (&((buf_pyobj *)(o))->b)
 #define BUF_SUB(o) (((buf_pyobj *)(o))->sub)
+#define BUF_LK(o) (((buf_pyobj *)(o))->lk)
 
 /*----- Exceptions --------------------------------------------------------*/
 
@@ -62,7 +64,7 @@ static PyObject *rbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
   q = xmalloc(in.sz);
   memcpy(q, in.p, in.sz);
   me = (buf_pyobj *)ty->tp_alloc(ty, 0);
-  me->sub = 0;
+  me->sub = 0; me->lk = 0;
   buf_init(&me->b, q, in.sz);
 end:
   return ((PyObject *)me);
@@ -70,10 +72,9 @@ end:
 
 static void buf_pydealloc(PyObject *me)
 {
-  if (BUF_SUB(me))
-    Py_DECREF(BUF_SUB(me));
-  else
-    xfree(BBASE(BUF_B(me)));
+  assert(!BUF_LK(me));
+  if (BUF_SUB(me)) Py_DECREF(BUF_SUB(me));
+  else xfree(BBASE(BUF_B(me)));
   FREEOBJ(me);
 }
 
@@ -140,6 +141,7 @@ BUF_DOSUFFIXES(RBMETH_GETBLK_)
     b = PyObject_NEW(buf_pyobj, rbuf_pytype);                          \
     b->b = bb;                                                         \
     b->sub = me;                                                       \
+    b->lk = 0;                                                         \
     Py_INCREF(me);                                                     \
     return ((PyObject *)b);                                            \
   end:                                                                 \
@@ -331,20 +333,27 @@ static const PyTypeObject rbuf_pytype_skel = {
 
 /*----- Write buffers -----------------------------------------------------*/
 
-static void ensure(PyObject *me, size_t n)
+static int ensure(PyObject *me, size_t n)
 {
   buf *b = BUF_B(me);
+  size_t nn = BSZ(b);
+  octet *p;
+  size_t want = BLEN(b) + n;
 
-  if (BLEFT(b) < n) {
-    size_t nn = BSZ(b);
-    octet *p;
-    size_t want = BLEN(b) + n;
+  if (BLEFT(b) >= n)
+    return (0);
+  else if (BUF_LK(me))
+    BUFERR("buffer locked");
+  else {
     while (nn < want) nn <<= 1;
     p = xrealloc(BBASE(b), nn, BSZ(b));
     BCUR(b) = p + BLEN(b);
     BLIM(b) = p + nn;
     BBASE(b) = p;
+    return (0);
   }
+end:
+  return (-1);
 }
 
 static PyObject *wbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
@@ -359,7 +368,7 @@ static PyObject *wbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
     goto end;
   me = (buf_pyobj *)ty->tp_alloc(ty, 0);
   p = xmalloc(n);
-  me->sub = 0;
+  me->sub = 0; me->lk = 0;
   buf_init(&me->b, p, n);
 end:
   return ((PyObject *)me);
@@ -376,7 +385,7 @@ static PyObject *wbmeth_zero(PyObject *me, PyObject *arg)
   void *p;
   size_t n;
   if (!PyArg_ParseTuple(arg, "O&:zero", convszt, &n)) return (0);
-  ensure(me, n);
+  if (ensure(me, n)) return (0);
   p = buf_get(BUF_B(me), n); assert(p && BOK(BUF_B(me)));
   memset(p, 0, n);
   RETURN_ME;
@@ -386,7 +395,7 @@ static PyObject *wbmeth_put(PyObject *me, PyObject *arg)
 {
   struct bin in;
   if (!PyArg_ParseTuple(arg, "O&:put", convbin, &in)) return (0);
-  ensure(me, in.sz);
+  if (ensure(me, in.sz)) return (0);
   buf_put(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me)));
   RETURN_ME;
 }
@@ -396,7 +405,7 @@ static PyObject *wbmeth_put(PyObject *me, PyObject *arg)
   {                                                                    \
     uint##n i;                                                         \
     if (!PyArg_ParseTuple(arg, "O&:putu" #w, convu##n, &i)) return (0);        \
-    ensure(me, SZ_##n);                                                        \
+    if (ensure(me, SZ_##n)) return (0);                                \
     buf_putu##w(BUF_B(me), i); assert(BOK(BUF_B(me)));                 \
     RETURN_ME;                                                         \
   }
@@ -410,7 +419,7 @@ DOUINTCONV(WBMETH_PUTU_)
     struct bin in;                                                     \
     if (!PyArg_ParseTuple(arg, "O&:putblk" #w, convbin, &in)) goto end;        \
     if (MASK##W && in.sz > MASK##W) VALERR("too large");               \
-    ensure(me, in.sz + SZ_##n);                                                \
+    if (ensure(me, in.sz + SZ_##n)) return (0);                        \
     buf_putmem##w(BUF_B(me), in.p, in.sz); assert(BOK(BUF_B(me)));     \
     RETURN_ME;                                                         \
   end:                                                                 \
@@ -422,7 +431,7 @@ static PyObject *wbmeth_putmp(PyObject *me, PyObject *arg)
 {
   mp *x = 0;
   if (!PyArg_ParseTuple(arg, "O&:putmp", convmp, &x)) return (0);
-  ensure(me, mp_octets(x) + 2);
+  if (ensure(me, mp_octets(x) + 2)) return (0);
   buf_putmp(BUF_B(me), x); assert(BOK(BUF_B(me)));
   RETURN_ME;
 }
@@ -431,7 +440,7 @@ static PyObject *wbmeth_putgf(PyObject *me, PyObject *arg)
 {
   mp *x = 0;
   if (!PyArg_ParseTuple(arg, "O&:putgf", convgf, &x)) return (0);
-  ensure(me, mp_octets(x) + 2);
+  if (ensure(me, mp_octets(x) + 2)) return (0);
   buf_putmp(BUF_B(me), x); assert(BOK(BUF_B(me)));
   MP_DROP(x);
   RETURN_ME;
@@ -441,7 +450,8 @@ static PyObject *wbmeth_putecpt(PyObject *me, PyObject *arg)
 {
   ec pt = EC_INIT;
   if (!PyArg_ParseTuple(arg, "O&:putecpt", convecpt, &pt)) return (0);
-  ensure(me, EC_ATINF(&pt) ? 2 : 6 + mp_octets(pt.x) + mp_octets(pt.y));
+  if (ensure(me, EC_ATINF(&pt) ? 2 : 6 + mp_octets(pt.x) + mp_octets(pt.y)))
+    return (0);
   buf_putec(BUF_B(me), &pt); assert(BOK(BUF_B(me)));
   EC_DESTROY(&pt);
   RETURN_ME;
@@ -454,7 +464,7 @@ static PyObject *wbmeth_putecptraw(PyObject *me, PyObject *arg)
   if (!PyArg_ParseTuple(arg, "O!:putecptraw", ecptcurve_pytype, &ptobj))
     return (0);
   EC_OUT(ECPT_C(ptobj), &pt, ECPT_P(ptobj));
-  ensure(me, ECPT_C(ptobj)->f->noctets * 2 + 1);
+  if (ensure(me, ECPT_C(ptobj)->f->noctets * 2 + 1)) return (0);
   ec_putraw(ECPT_C(ptobj), BUF_B(me), &pt); assert(BOK(BUF_B(me)));
   EC_DESTROY(&pt);
   RETURN_ME;
@@ -464,7 +474,7 @@ static PyObject *wbmeth_putge(PyObject *me, PyObject *arg)
 {
   PyObject *geobj;
   if (!PyArg_ParseTuple(arg, "O!:putge", ge_pytype, &geobj)) return (0);
-  ensure(me, GE_G(geobj)->noctets);
+  if (ensure(me, GE_G(geobj)->noctets)) return (0);
   G_TOBUF(GE_G(geobj), BUF_B(me), GE_X(geobj)); assert(BOK(BUF_B(me)));
   RETURN_ME;
 }
@@ -473,7 +483,7 @@ static PyObject *wbmeth_putgeraw(PyObject *me, PyObject *arg)
 {
   PyObject *geobj;
   if (!PyArg_ParseTuple(arg, "O!:putgeraw", ge_pytype, &geobj)) return (0);
-  ensure(me, GE_G(geobj)->noctets);
+  if (ensure(me, GE_G(geobj)->noctets)) return (0);
   G_TORAW(GE_G(geobj), BUF_B(me), GE_X(geobj)); assert(BOK(BUF_B(me)));
   RETURN_ME;
 }