Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

py_linuxtuples.c

Go to the documentation of this file.
00001 /*****************************************************************
00002  *
00003  * LinuxTuples - a Linda-esque tuple system for Linux clusters
00004  * Copyright (c) 2003, Will Ware <wware@alum.mit.edu>
00005  * All rights reserved.
00006  * 
00007  *    Redistribution and use in source and binary forms, with or
00008  *    without modification, are permitted provided that the following
00009  *    conditions are met:
00010  * 
00011  *    + Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  *
00014  *    + Redistributions in binary form must reproduce the above
00015  *    copyright notice, this list of conditions and the following
00016  *    disclaimer in the documentation and/or other materials provided
00017  *    with the distribution.
00018  *
00019  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
00020  *    CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
00021  *    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00022  *    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00023  *    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
00024  *    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00025  *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00026  *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
00027  *    USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  *    AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029  *    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00030  *    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
00031  *    THE POSSIBILITY OF SUCH DAMAGE.
00032  *
00033  *****************************************************************/
00044 #include <stdio.h>
00045 #include <stdlib.h>
00046 #include <unistd.h>
00047 #include <time.h>
00048 #include <sys/time.h>
00049 
00050 #include "Python.h"
00051 #include "tuple.h"
00052 
00053 
00054 staticforward PyTypeObject CtxType;
00055 
00059 typedef struct {
00060         PyObject_HEAD;
00061         struct context ctx;
00062 } CtxObject;
00063 
00064 
00065 static char ctx_put_doc_string[];
00066 static char ctx_get_doc_string[];
00067 static char ctx_read_doc_string[];
00068 static char ctx_get_nb_doc_string[];
00069 static char ctx_read_nb_doc_string[];
00070 static char ctx_dump_doc_string[];
00071 static char ctx_log_doc_string[];
00072 static PyMethodDef linuxtuples_methods[];
00073 static PyMethodDef ctx_methods[];
00074 
00075 static PyObject *ctx_getattr(CtxObject *obj, char *name);
00076 static PyObject *new_ctx(PyObject *self, PyObject *args);
00077 static void ctx_dealloc(PyObject *self);
00078 static struct tuple *PyTuple_to_LinuxTuple(PyObject *pytup, int puttable);
00079 static PyObject *LinuxTuple_to_PyTuple(struct tuple *t);
00080 static PyObject *ctx_put_tuple(PyObject *self, PyObject *args);
00081 static PyObject * ctx_get_read(CtxObject *pyctx,
00082                                PyObject *args,
00083                                struct tuple * (*func)(struct tuple *,
00084                                                       struct context *),
00085                                int blocking);
00086 static PyObject *ctx_get_tuple(PyObject *self, PyObject *args);
00087 static PyObject *ctx_read_tuple(PyObject *self, PyObject *args);
00088 static PyObject *ctx_get_nb_tuple(PyObject *self, PyObject *args);
00089 static PyObject *ctx_read_nb_tuple(PyObject *self, PyObject *args);
00090 static PyObject *ctx_dump_tuple_space(PyObject *self, PyObject *args);
00091 static PyObject *ctx_tuple_server_log(PyObject *self, PyObject *args);
00092 
00093 static char py_random_int_doc_string[];
00094 static PyObject *py_random_int(PyObject *self, PyObject *args);
00095 
00096 void initlinuxtuples(void);
00097 
00098 
00099 static char
00100 linuxtuples_doc_string[] =
00101 "This is the Python client API for the linuxtuples tuple server. The\n"
00102 "connect() method returns a connection to the tuple server. The\n"
00103 "random() method returns a 32-bit integer taken from /dev/urandom.";
00104 
00105 
00106 static char
00107 ctx_doc_string[] =
00108 "This is a connection to a tuple server. Its methods give access to\n"
00109 "tuple space.\n"
00110 "\n"
00111 "The put(tuple) method lets you put a tuple into the tuple space.\n"
00112 "get(template) removes a tuple that matches the template (where None is\n"
00113 "used as a wildcard), blocking until a matching tuple becomes\n"
00114 "available. read(template) is like get(), but it returns a copy of the\n"
00115 "tuple, leaving the original in tuple space.\n"
00116 "\n"
00117 "get_nonblocking() and read_nonblocking() are non-blocking versions of\n"
00118 "get() and read(), which return None if a matching tuple is not\n"
00119 "available.\n"
00120 "\n"
00121 "The dump() method returns a list of the tuples in tuple space. If\n"
00122 "supplied with a list of templates as an argument, it will return a\n"
00123 "list of only those tuples that match at least one template.\n"
00124 "\n"
00125 "The log() method prints a running log of tuple server activity to\n"
00126 "stdout. It should be called in a \"while 1:\" loop.";
00127 
00128 
00132 static PyMethodDef ctx_methods[] = {
00133         {"put", ctx_put_tuple, METH_VARARGS,
00134          ctx_put_doc_string},
00135         {"get", ctx_get_tuple, METH_VARARGS,
00136          ctx_get_doc_string},
00137         {"read", ctx_read_tuple, METH_VARARGS,
00138          ctx_read_doc_string},
00139         {"get_nonblocking", ctx_get_nb_tuple, METH_VARARGS,
00140          ctx_get_nb_doc_string},
00141         {"read_nonblocking", ctx_read_nb_tuple, METH_VARARGS,
00142          ctx_read_nb_doc_string},
00143         {"dump", ctx_dump_tuple_space, METH_VARARGS,
00144          ctx_dump_doc_string},
00145         {"log", ctx_tuple_server_log, METH_VARARGS,
00146          ctx_log_doc_string},
00147         {NULL, NULL, 0, NULL}           /* sentinel */
00148 };
00149 
00153 static PyObject *
00154 ctx_getattr(CtxObject *obj, char *name)
00155 {
00156         if (strcmp(name, "__doc__") == 0) {
00157                 return PyString_FromString(ctx_doc_string);
00158         }
00159         return Py_FindMethod(ctx_methods, (PyObject *)obj, name);
00160 }
00161 
00162 
00163 #define SETENV_STRING \
00164 "\nUnable to find the environment variables (LINUXTUPLES_HOST,\n" \
00165 "LINUXTUPLES_PORT). Please set them."
00166 
00167 
00168 static char
00169 new_ctx_doc_string[] =
00170 "conn = connect()\n"
00171 "conn = connect(int)\n"
00172 "Return a connection to the tuple server.";
00173 
00177 static PyObject*
00178 new_ctx(PyObject* self, PyObject* args)
00179 {
00180         CtxObject* pyctx;
00181         
00182         if (!PyArg_ParseTuple(args,"")) 
00183                 return NULL;
00184         
00185         pyctx = PyObject_New(CtxObject, &CtxType);
00186         
00187         if (get_server_portnumber(&pyctx->ctx)) {
00188                 PyErr_SetString(PyExc_ImportError, SETENV_STRING);
00189                 return NULL;
00190         };
00191 
00192         return (PyObject*)pyctx;
00193 }
00194 
00198 static void
00199 ctx_dealloc(PyObject* self)
00200 {
00201         CtxObject *pyctx = (CtxObject*) self;
00202         close(pyctx->ctx.sock);
00203         PyObject_Del(self);
00204 }
00205 
00209 static PyTypeObject CtxType = {
00210         PyObject_HEAD_INIT(NULL)
00211         0,
00212         "Ctx",
00213         sizeof(CtxObject),
00214         0,
00215         ctx_dealloc, /*tp_dealloc*/
00216         0,          /*tp_print*/
00217         (getattrfunc) ctx_getattr, /*tp_getattr*/
00218         0,          /*tp_setattr*/
00219         0,          /*tp_compare*/
00220         0,          /*tp_repr*/
00221         0,          /*tp_as_number*/
00222         0,          /*tp_as_sequence*/
00223         0,          /*tp_as_mapping*/
00224         0,          /*tp_hash */
00225 };
00226 
00227 
00228 
00235 static struct tuple *
00236 PyTuple_to_LinuxTuple(PyObject *pytup, int puttable)
00237 {
00238         int i, len;
00239         struct tuple *t;
00240         len = PyTuple_Size(pytup);
00241         t = malloc(sizeof(struct tuple));
00242         if (t == NULL) {
00243                 return (struct tuple*) PyErr_NoMemory();
00244         }
00245         t->tag = I_AM_A_TUPLE;
00246         t->num_elts = len;
00247         t->elements = malloc(t->num_elts * sizeof(struct element));
00248         if (t->elements == NULL) {
00249                 return (struct tuple *) PyErr_NoMemory();
00250         }
00251         t->string_space = NULL;
00252         t->string_length = 0;
00253 
00254         for (i = 0; i < len; i++) {
00255                 PyObject *elem;
00256                 elem = PyTuple_GetItem(pytup, i);
00257                 if (elem == Py_None) {
00258                         if (puttable)
00259                                 goto bad_element;
00260                         t->elements[i].tag = '?';
00261                 }
00262                 else if (PyInt_Check(elem)) {
00263                         t->elements[i].tag = 'i';
00264                         t->elements[i].data.i = PyInt_AsLong(elem);
00265                 }
00266                 else if (PyFloat_Check(elem)) {
00267                         t->elements[i].tag = 'd';
00268                         t->elements[i].data.d = PyFloat_AsDouble(elem);
00269                 }
00270                 else if (PyString_Check(elem)) {
00271                         int n = PyString_Size(elem);
00272                         t->elements[i].tag = 's';
00273                         t->elements[i].data.s.ptr = PyString_AsString(elem);
00274                         t->elements[i].data.s.len = n;
00275                         t->string_length += n;
00276                 }
00277                 else {
00278                   bad_element:
00279                         PyErr_SetString(PyExc_RuntimeError,
00280                                         "Bad element in LinuxTuples tuple");
00281                         return NULL;
00282                 }
00283         }
00284         return t;
00285 }
00286 
00287 
00291 static PyObject *
00292 LinuxTuple_to_PyTuple(struct tuple * t)
00293 {
00294         PyObject *pytup;
00295         int i;
00296         /*
00297          * Unpack the Linuxtuples tuple to a Python tuple.
00298          */
00299         pytup = PyTuple_New(t->num_elts);
00300         if (pytup == NULL)
00301                 return PyErr_NoMemory();
00302         for (i = 0; i < t->num_elts; i++) {
00303                 PyObject *ob;
00304                 switch (t->elements[i].tag) {
00305                 case '?':
00306                         Py_INCREF(Py_None);
00307                         PyTuple_SetItem(pytup, i, Py_None);
00308                         break;
00309                 case 'i':
00310                         ob = PyInt_FromLong(t->elements[i].data.i);
00311                         if (ob == NULL)
00312                                 return PyErr_NoMemory();
00313                         PyTuple_SetItem(pytup, i, ob);
00314                         break;
00315                 case 'd':
00316                         ob = PyFloat_FromDouble(t->elements[i].data.d);
00317                         if (ob == NULL)
00318                                 return PyErr_NoMemory();
00319                         PyTuple_SetItem(pytup, i, ob);
00320                         break;
00321                 case 's':
00322                         ob = PyString_FromStringAndSize(
00323                                 t->elements[i].data.s.ptr,
00324                                 t->elements[i].data.s.len);
00325                         if (ob == NULL)
00326                                 return PyErr_NoMemory();
00327                         PyTuple_SetItem(pytup, i, ob);
00328                         break;
00329                 }
00330         }
00331         return pytup;
00332 }
00333 
00334 
00335 static char
00336 ctx_put_doc_string[] =
00337 "conn.put(tuple)\n"
00338 "Put a tuple into tuple space.";
00339 
00343 static PyObject *
00344 ctx_put_tuple(PyObject *self, PyObject *args)
00345 {
00346         CtxObject *pyctx = (CtxObject*) self;
00347         PyObject *pytup;
00348         struct tuple *t;
00349 
00350         if (!PyArg_ParseTuple(args, "O", &pytup))
00351                 return NULL;
00352         if (!PyTuple_Check(pytup)) {
00353                 PyErr_SetString(PyExc_TypeError,
00354                                 "argument must be a tuple");
00355                 return NULL;
00356         }
00357 
00358         t = PyTuple_to_LinuxTuple(pytup, 1);
00359         if (t == NULL) {
00360                 return NULL;
00361         }
00362 
00363         /*
00364          * Put the Linuxtuples tuple in the tuple space.
00365          */
00366 
00367         if (put_tuple(t, &pyctx->ctx)) {
00368                 PyErr_SetString(PyExc_RuntimeError, "put() failed");
00369                 return NULL;
00370         }
00371         destroy_tuple(t);
00372 
00373         Py_INCREF(Py_None);
00374         return Py_None;
00375 }
00376 
00377 
00378 
00382 static PyObject *
00383 ctx_get_read(CtxObject *pyctx,
00384              PyObject *args,
00385              struct tuple * (*func)(struct tuple *,
00386                                     struct context *),
00387              int blocking)
00388 {
00389         PyObject *pytup;
00390         struct tuple *s, *t;
00391 
00392         if (!PyArg_ParseTuple(args, "O", &pytup))
00393                 return NULL;
00394         if (!PyTuple_Check(pytup)) {
00395                 PyErr_SetString(PyExc_TypeError,
00396                                 "argument must be a tuple");
00397                 return NULL;
00398         }
00399 
00400         /*
00401          * Build a LinuxTuples tuple template.
00402          */
00403         s = PyTuple_to_LinuxTuple(pytup, 0);
00404         if (s == NULL) {
00405                 return NULL;
00406         }
00407 
00408         /*
00409          * Get a Linuxtuples tuple from the tuple space.
00410          */
00411         t = (*func)(s, &pyctx->ctx);
00412         destroy_tuple(s);
00413         if (t == (struct tuple *) -1) {
00414                 goto abject_failure;
00415         }
00416         if (!blocking && t == NULL) {
00417                 Py_INCREF(Py_None);
00418                 return Py_None;
00419         }
00420         if (t == NULL) {
00421         abject_failure:
00422                 PyErr_SetString(PyExc_RuntimeError, "get() or read() failed");
00423                 return NULL;
00424         }
00425 
00426         /*
00427          * Unpack the Linuxtuples tuple to a Python tuple.
00428          */
00429         pytup = LinuxTuple_to_PyTuple(t);
00430         destroy_tuple(t);
00431         return pytup;
00432 }
00433 
00434 
00435 static char
00436 ctx_get_doc_string[] =
00437 "tuple = conn.get(template)\n"
00438 "Get a tuple from tuple space. Items in the returned tuple\n"
00439 "must match any non-None items in the template. Nones are\n"
00440 "wildcards. This call blocks until a matching tuple is found.";
00441 
00446 static PyObject *
00447 ctx_get_tuple(PyObject *self, PyObject *args)
00448 {
00449         return ctx_get_read((CtxObject*)self, args, get_tuple, 1);
00450 }
00451 
00452 static char
00453 ctx_read_doc_string[] =
00454 "tuple = conn.read(template)\n"
00455 "Read a copy of a tuple from tuple space. Items in the\n"
00456 "returned tuple must match any non-None items in the template.\n"
00457 "Nones are wildcards. This call blocks until a matching\n"
00458 "tuple is found.";
00459 
00464 static PyObject *
00465 ctx_read_tuple(PyObject *self, PyObject *args)
00466 {
00467         return ctx_get_read((CtxObject*)self, args, read_tuple, 1);
00468 }
00469 
00470 static char
00471 ctx_get_nb_doc_string[] =
00472 "tuple = conn.get_nonblocking(template)\n"
00473 "Get a tuple from tuple space. Items in the returned tuple\n"
00474 "must match any non-None items in the template. Nones are\n"
00475 "wildcards. If no matching tuple is found, returns None.";
00476 
00481 static PyObject *
00482 ctx_get_nb_tuple(PyObject *self, PyObject *args)
00483 {
00484         return ctx_get_read((CtxObject*)self, args, get_nb_tuple, 0);
00485 }
00486 
00487 static char
00488 ctx_read_nb_doc_string[] =
00489 "tuple = conn.read_nonblocking(template)\n"
00490 "Read a copy of a tuple from tuple space. Items in the\n"
00491 "returned tuple must match any non-None items in the template.\n"
00492 "Nones are wildcards. If no matching tuple is found, returns\n"
00493 "None.";
00494 
00499 static PyObject *
00500 ctx_read_nb_tuple(PyObject *self, PyObject *args)
00501 {
00502         return ctx_get_read((CtxObject*)self, args, read_nb_tuple, 0);
00503 }
00504 
00505 static char
00506 ctx_dump_doc_string[] =
00507 "tuple_list = conn.dump( [template_list] )\n"
00508 "Return a list of the tuples in the tuple space. If no template\n"
00509 "list is given, return all the tuples. If there is a template\n"
00510 "list, return only the tuples that match at least one template.";
00511 
00516 static PyObject *
00517 ctx_dump_tuple_space(PyObject *self, PyObject *args)
00518 {
00519         PyObject *pylst = NULL, *pytup;
00520         CtxObject *pyctx;
00521         struct tuple_list *slist, *tlist, *x;
00522         int i, count, listsize;
00523 
00524         pyctx = (CtxObject*)self;
00525         if (!PyArg_ParseTuple(args, "|O", &pylst))
00526                 return NULL;
00527         if (pylst != NULL) {
00528                 if (!PyList_Check(pylst)) {
00529                         PyErr_SetString(PyExc_TypeError,
00530                                         "argument must be a list");
00531                         return NULL;
00532                 }
00533                 listsize = PyList_Size(pylst);
00534         } else {
00535                 listsize = 0;
00536         }
00537                         
00538 
00539         /* Assemble a list of templates from the arg.
00540          */
00541         slist = NULL;
00542         for (i = 0; i < listsize; i++) {
00543                 pytup = PyList_GetItem(pylst, i);
00544                 if (!PyTuple_Check(pytup)) {
00545                         PyErr_SetString(PyExc_TypeError,
00546                                         "list members must be tuples");
00547                         return NULL;
00548                 }
00549                 x = malloc(sizeof(struct tuple_list));
00550                 if (x == NULL)
00551                         return PyErr_NoMemory();
00552                 x->tup = PyTuple_to_LinuxTuple(pytup, 0);
00553                 x->next = slist;
00554                 slist = x;
00555         }
00556 
00557         x = slist;
00558         while (x != NULL) {
00559                 x = x->next;
00560         }
00561 
00562         /* Do a dump request to the server.
00563          */
00564         tlist = dump_tuple_space(slist, &pyctx->ctx);
00565         while (slist) {
00566                 x = slist;
00567                 slist = slist->next;
00568                 free(x);
00569         }
00570 
00571         count = 0;
00572         x = tlist;
00573         while (x != NULL) {
00574                 count++;
00575                 x = x->next;
00576         }
00577         pylst = PyList_New(count);
00578         if (pylst == NULL)
00579                 return PyErr_NoMemory();
00580         for (i = 0, x = tlist; x != NULL; x = x->next, i++)
00581                 PyList_SetItem(pylst, i,
00582                                LinuxTuple_to_PyTuple(x->tup));
00583 
00584         while (tlist) {
00585                 x = tlist;
00586                 tlist = tlist->next;
00587                 free(x);
00588         }
00589 
00590         return pylst;
00591 }
00592 
00593 static char
00594 ctx_log_doc_string[] =
00595 "Dump a continuous log of tuple space activity to stdout. Call this\n"
00596 "method in a \"while 1:\" loop. Looping in Python rather than C\n"
00597 "means that you can break out of the loop easily with control-C,\n"
00598 "and you can put other code in the loop.";
00599 
00604 static PyObject *
00605 ctx_tuple_server_log(PyObject *self, PyObject *args)
00606 {
00607         CtxObject *pyctx = (CtxObject*)self;
00608         if (!PyArg_ParseTuple(args, ""))
00609                 return NULL;
00610         tuple_server_log(stdout, &pyctx->ctx);
00611         Py_INCREF(Py_None);
00612         return Py_None;
00613 }
00614 
00615 static char
00616 py_random_int_doc_string[] =
00617 "Return a 32-bit random integer, taken from /dev/urandom.";
00618 
00623 static PyObject *
00624 py_random_int(PyObject *self, PyObject *args)
00625 {
00626         if (!PyArg_ParseTuple(args, ""))
00627                 return NULL;
00628         return PyInt_FromLong(random_int());
00629 }
00630 
00631 
00632 
00636 static PyMethodDef
00637 linuxtuples_methods[] = {
00638         {"connect", new_ctx, METH_VARARGS, new_ctx_doc_string},
00639         {"random", py_random_int, METH_VARARGS, py_random_int_doc_string},
00640         {NULL, NULL}  /* sentinel */
00641 };
00642 
00643 
00648 DL_EXPORT(void)
00649 initlinuxtuples()
00650 {
00651         PyObject *m, *d;
00652 
00653         CtxType.ob_type = &PyType_Type;
00654         m = Py_InitModule("linuxtuples", linuxtuples_methods);
00655         d = PyModule_GetDict(m);
00656         PyDict_SetItemString(d, "__doc__",
00657                              PyString_FromString(linuxtuples_doc_string));
00658 }

Generated on Sun Mar 30 23:46:49 2003 by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002