Added flag "-debug" to charmc for usage with charmdebug.
[charm.git] / src / libs / ck-libs / pythonCCS / PythonCCS.C
1 #include "PythonCCS.h"
2
3 //CsvDeclare(CmiNodeLock, pyLock);
4 //CsvDeclare(PythonTable *, pyWorkers);
5 //CsvDeclare(CmiUInt4, pyNumber);
6 CtvDeclare(PyObject *, pythonReturnValue);
7
8 CProxy_PythonCCS pythonCcsProxy;
9
10 // One-time per-processor setup routine
11 // main interface for python to access common charm methods
12 static PyObject *CkPy_printstr(PyObject *self, PyObject *args) {
13   char *stringToPrint;
14   if (!PyArg_ParseTuple(args, "s:printstr", &stringToPrint)) return NULL;
15   CkPrintf("%s\n",stringToPrint);
16   Py_INCREF(Py_None);return Py_None; //Return-nothing idiom
17 }
18
19 static inline void Ck_printclient(PythonObject *object, CmiUInt4 ref, char* str) {
20   //  CmiLock(CsvAccess(pyLock));
21   PythonStruct &worker = object->pyWorkers[ref];
22   //PythonObject *pyWorker = ((*CsvAccess(pyWorkers))[pyReference]).object;
23   //if (((*CsvAccess(pyWorkers))[ref]).clientReady > 0) {
24   if (worker.clientReady > 0) {
25     // return the string to the client
26     // since there is a client waiting, it means there must not be
27     // pending strings to be returned ("printed" is empty)
28     //CkPrintf("printing data to the client\n");
29     CcsSendDelayedReply(worker.client, strlen(str), str);
30     worker.printed.erase();
31     worker.clientReady = 0;
32   } else {
33     // add the string to those in list to be returned if it is keepPrint
34     if (worker.isKeepPrint) {
35       worker.printed += std::string(str);
36     }
37     // else just drop the line
38   }
39   //CmiUnlock(CsvAccess(pyLock));
40 }
41
42 static PyObject *CkPy_print(PyObject *self, PyObject *args) {
43   char *stringToPrint;
44   if (!PyArg_ParseTuple(args, "s:printclient", &stringToPrint)) return NULL;
45   PyObject *dict = PyModule_GetDict(PyImport_AddModule("__main__"));
46   CmiUInt4 pyReference = PyInt_AsLong(PyDict_GetItemString(dict,"__charmNumber__"));
47   PythonObject *object = (PythonObject*)PyLong_AsVoidPtr(PyDict_GetItemString(dict,"__charmObject__"));
48   Ck_printclient(object, pyReference, stringToPrint);
49   Py_INCREF(Py_None);return Py_None; //Return-nothing idiom
50 }
51
52 static PyObject *CkPy_mype(PyObject *self, PyObject *args) {
53   if (!PyArg_ParseTuple(args, ":mype")) return NULL;
54   return Py_BuildValue("i", CkMyPe());
55 }
56
57 static PyObject *CkPy_numpes(PyObject *self, PyObject *args) {
58   if (!PyArg_ParseTuple(args, ":numpes")) return NULL;
59   return Py_BuildValue("i", CkNumPes());
60 }
61
62 static PyObject *CkPy_myindex(PyObject *self, PyObject *args) {
63   if (!PyArg_ParseTuple(args, ":myindex")) return NULL;
64   PyObject *dict = PyModule_GetDict(PyImport_AddModule("__main__"));
65   CmiUInt4 pyReference = PyInt_AsLong(PyDict_GetItemString(dict,"__charmNumber__"));
66   PythonObject *object = (PythonObject*)PyLong_AsVoidPtr(PyDict_GetItemString(dict,"__charmObject__"));
67   //CmiLock(CsvAccess(pyLock));
68   ArrayElement1D *pyArray1 = dynamic_cast<ArrayElement1D*>(object);
69   ArrayElement2D *pyArray2 = dynamic_cast<ArrayElement2D*>(object);
70   ArrayElement3D *pyArray3 = dynamic_cast<ArrayElement3D*>(object);
71   ArrayElement4D *pyArray4 = dynamic_cast<ArrayElement4D*>(object);
72   ArrayElement5D *pyArray5 = dynamic_cast<ArrayElement5D*>(object);
73   ArrayElement6D *pyArray6 = dynamic_cast<ArrayElement6D*>(object);
74   //CmiUnlock(CsvAccess(pyLock));
75   if (pyArray1) return Py_BuildValue("(i)", pyArray1->thisIndex);
76   else if (pyArray2) return Py_BuildValue("(ii)", pyArray2->thisIndex.x, pyArray2->thisIndex.y);
77   else if (pyArray3) return Py_BuildValue("(iii)", pyArray3->thisIndex.x, pyArray3->thisIndex.y, pyArray3->thisIndex.z);
78   else if (pyArray4) return Py_BuildValue("(iiii)", pyArray4->thisIndex.w, pyArray4->thisIndex.x, pyArray4->thisIndex.y, pyArray4->thisIndex.z);
79   else if (pyArray5) return Py_BuildValue("(iiiii)", pyArray5->thisIndex.v, pyArray5->thisIndex.w, pyArray5->thisIndex.x, pyArray5->thisIndex.y, pyArray5->thisIndex.z);
80   else if (pyArray6) return Py_BuildValue("(iiiiii)", pyArray6->thisIndex.x1, pyArray6->thisIndex.y1, pyArray6->thisIndex.z1, pyArray6->thisIndex.x2, pyArray6->thisIndex.y2, pyArray6->thisIndex.z2);
81   else { Py_INCREF(Py_None);return Py_None;}
82   //return Py_BuildValue("i", (*CsvAccess(pyWorkers))[0]->thisIndex);
83 }
84
85 // method to read a variable and convert it to a python object
86 static PyObject *CkPy_read(PyObject *self, PyObject *args) {
87   if (!PyArg_ParseTuple(args, "O:read")) return NULL;
88   PyObject *dict = PyModule_GetDict(PyImport_AddModule("__main__"));
89   CmiUInt4 pyReference = PyInt_AsLong(PyDict_GetItemString(dict,"__charmNumber__"));
90   PythonObject *object = (PythonObject*)PyLong_AsVoidPtr(PyDict_GetItemString(dict,"__charmObject__"));
91   //CmiLock(CsvAccess(pyLock));
92   //CmiUnlock(CsvAccess(pyLock));
93   return object->read(args);
94 }
95
96 // method to convert a python object into a variable and write it
97 static PyObject *CkPy_write(PyObject *self, PyObject *args) {
98   PyObject *where, *what;
99   if (!PyArg_ParseTuple(args, "OO:write",&where,&what)) return NULL;
100
101   /* Problem solving:
102
103      when the calling parameters (where and what) are formed by only one value,
104      the parsing done here above will return two objects which are not tuples
105      (and no parenthesis on the caller will change this). For this reason, we
106      have to recreate two new tuples with the given argements to pass to the
107      write function of the object.
108   */
109   PyObject *whereT, *whatT;
110   if (PyTuple_Check(where)) whereT = where;
111   else {
112     whereT = PyTuple_New(1);
113     PyTuple_SET_ITEM(whereT, 0, where);
114   }
115   if (PyTuple_Check(what)) whatT = what;
116   else {
117     whatT = PyTuple_New(1);
118     PyTuple_SET_ITEM(whatT, 0, what);
119   }
120   PyObject *dict = PyModule_GetDict(PyImport_AddModule("__main__"));
121   CmiUInt4 pyReference = PyInt_AsLong(PyDict_GetItemString(dict,"__charmNumber__"));
122   PythonObject *object = (PythonObject*)PyLong_AsVoidPtr(PyDict_GetItemString(dict,"__charmObject__"));
123   object->write(whereT, whatT);
124   Py_DECREF(whereT);
125   Py_DECREF(whatT);
126   Py_INCREF(Py_None);return Py_None;
127 }
128
129 PyMethodDef PythonObject::CkPy_MethodsCustom[] = {
130   {NULL,      NULL}        /* Sentinel */
131 };
132
133 char* PythonObject::CkPy_MethodsCustomDoc = "";
134
135 PyMethodDef CkPy_MethodsDefault[] = {
136   {"printstr", CkPy_printstr, METH_VARARGS},
137   {"printclient", CkPy_print, METH_VARARGS},
138   {"mype", CkPy_mype, METH_VARARGS},
139   {"numpes", CkPy_numpes, METH_VARARGS},
140   {"myindex", CkPy_myindex, METH_VARARGS},
141   {"read", CkPy_read, METH_VARARGS},
142   {"write", CkPy_write, METH_VARARGS},
143   {NULL,      NULL}        /* Sentinel */
144 };
145
146 void PythonObject::replyIntValue(CcsDelayedReply *reply, CmiUInt4 *value) {
147   CkPrintf("[%d] PythonObject::replyIntValue\n",CkMyPe());
148   PythonReplyInt forward;
149   forward.reply = *reply;
150   forward.value = *value;
151   CkCallback cb(CkIndex_PythonCCS::forwardInt(0), pythonCcsProxy);
152   ArrayElement *array = dynamic_cast<ArrayElement *>(this);
153   Group *group = dynamic_cast<Group *>(this);
154   if (array != NULL) array->contribute(sizeof(PythonReplyInt), &forward, CkReduction::bitvec_and, cb);
155   else if (group != NULL) group->contribute(sizeof(PythonReplyInt), &forward, CkReduction::bitvec_and, cb);
156   else CcsSendDelayedReply(*reply, sizeof(CmiUInt4), (void *)value);
157 }
158
159 void PythonObject::pyRequest (CkCcsRequestMsg *msg) {
160   PythonAbstract *pyAbstract = (PythonAbstract *)msg->data;
161   pyAbstract->unpack();
162
163   if (pyAbstract->isExecute()) {
164     execute(msg, &msg->reply);
165     // the message is not deleted here, it will deleted by the function itself
166     // deleting it here creates problems with the high level scripting where
167     // a new thread is created. the alternative will be to memcopy the message
168   } else if (pyAbstract->isPrint()) {
169     print((PythonPrint *)msg->data, &msg->reply);
170     delete msg;
171   } else if (pyAbstract->isFinished()) {
172     finished((PythonFinished *)msg->data, &msg->reply);
173     delete msg;
174   } else {
175     CkPrintf("Wrong request arrived!\n");
176     delete msg;
177   }
178 }
179
180
181 void PythonObject::print (PythonPrint *pyMsg, CcsDelayedReply *reply) {
182   // ATTN: be sure that in all possible paths pyLock is released!
183   //CmiLock(CsvAccess(pyLock));
184   CmiUInt4 returnValue;
185   pyMsg->unpack();
186
187   PythonTable::iterator iter = pyWorkers.find(pyMsg->interpreter);
188   if (iter == pyWorkers.end()) {
189     // Malformed request!
190     //CkPrintf("PythonCCS: print request on invalid interpreter\n");
191     //CmiUnlock(CsvAccess(pyLock));
192     returnValue = htonl(0);
193     replyIntValue(reply, &returnValue);
194   } else {
195     // it is a correct print request, parse it
196
197     if (pyMsg->isKill()) {
198       // kill the pending client print request
199       if (iter->second.clientReady == 1) {
200         returnValue = htonl(0);
201         replyIntValue(&iter->second.client, &returnValue);
202       }
203       //CmiUnlock(CsvAccess(pyLock));
204       // do no return anything to the calling socket
205       CcsNoDelayedReply(*reply);
206       return;
207     }
208
209     // is something already printed?
210     if (iter->second.printed.length() > 0) {
211       // send back to the client the string
212       const char *str = iter->second.printed.c_str();
213       int length = strlen(str);
214       //CkPrintf("sending data to the client\n");
215       PythonReplyString *forward = new (length) PythonReplyString();
216       forward->reply = *reply;
217       memcpy(forward->data, str, length);
218       CkCallback cb(CkIndex_PythonCCS::forwardString(0), pythonCcsProxy);
219       ArrayElement *array = dynamic_cast<ArrayElement *>(this);
220       Group *group = dynamic_cast<Group *>(this);
221       if (array != NULL) array->contribute(sizeof(CcsDelayedReply)+length, forward, PythonCCS::reduceString, cb);
222       else if (group != NULL) group->contribute(sizeof(CcsDelayedReply)+length, forward, PythonCCS::reduceString, cb);
223       else CcsSendDelayedReply(*reply, length, str);
224       iter->second.printed.erase();
225       if (iter->second.clientReady == -1) {
226         // after the client flush the printed buffer, delete the entry
227         pyWorkers.erase(pyMsg->interpreter);
228       }
229     } else {
230       // nothing printed, store the client request if it will be waiting
231       if (pyMsg->isWait()) {
232         // check if someone else has requested prints, if yes, kill the other
233         if (iter->second.clientReady == 1) {
234           returnValue = htonl(0);
235           replyIntValue(&iter->second.client, &returnValue);
236         }
237         iter->second.client = *reply;
238         iter->second.clientReady = 1;
239       } else {
240         // return null
241         returnValue = htonl(0);
242         replyIntValue(reply, &returnValue);
243       }
244     }
245     //CmiUnlock(CsvAccess(pyLock));
246   }
247 }
248
249 void PythonObject::finished (PythonFinished *pyMsg, CcsDelayedReply *reply) {
250    // ATTN: be sure that in all possible paths pyLock is released!
251   //CmiLock(CsvAccess(pyLock));
252   CmiUInt4 pyReference = pyMsg->interpreter;
253   CmiUInt4 returnValue;
254   pyMsg->unpack();
255
256   PythonTable::iterator iter = pyWorkers.find(pyMsg->interpreter);
257   if (iter == pyWorkers.end() || !iter->second.inUse) {
258     //ckout <<"answering Finished yes"<<endl;
259     returnValue = htonl(pyReference);
260     replyIntValue(reply, &returnValue);
261     //CmiUnlock(CsvAccess(pyLock));
262     return;
263   }
264
265   // the client is in use
266   if (pyMsg->isWait()) {
267     // is there another client waiting for termination?
268     if (iter->second.finishReady) {
269       // kill the previous requester
270       returnValue = htonl(0);
271       replyIntValue(&iter->second.finish, &returnValue);
272     }
273     //ckout <<"queueing Finished request"<<endl;
274     iter->second.finish = *reply;
275     iter->second.finishReady = 1;
276   } else {
277     //ckout <<"answering Finished no"<<endl;
278     returnValue = htonl(0);
279     replyIntValue(reply, &returnValue);
280   }
281   //CmiUnlock(CsvAccess(pyLock));
282 }
283
284 void PythonObject::execute (CkCcsRequestMsg *msg, CcsDelayedReply *reply) {
285   // ATTN: be sure that in all possible paths pyLock is released!
286   PythonExecute *pyMsg = (PythonExecute *)msg->data;
287   //PyEval_AcquireLock();
288   //CmiLock(CsvAccess(pyLock));
289   CmiUInt4 pyReference;
290   CmiUInt4 returnValue;
291
292   // re-establish the pointers in the structure
293   pyMsg->unpack();
294
295   if (pyMsg->interpreter > 0) {
296     // the user specified an interpreter, check if it is free
297     PythonTable::iterator iter;
298     if ((iter=pyWorkers.find(pyMsg->interpreter))!=pyWorkers.end() && !iter->second.inUse && iter->second.clientReady!=-1) {
299       // the interpreter already exists and it is neither in use, nor dead
300       //CkPrintf("interpreter present and not in use\n");
301       pyReference = pyMsg->interpreter;
302       PyEval_AcquireLock();
303       PyThreadState_Swap(iter->second.pythread);
304     } else {
305       // ops, either the iterator does not exist or is already in use, return an
306       // error to the client, we don't want to create a new interpreter if the
307       // old is in use, because this can corrupt the semantics of the user code.
308       //if (iter==CsvAccess(pyWorkers)->end()) CkPrintf("asked for an interpreter not present\n");
309       //else CkPrintf("interpreter already in use\n");
310       returnValue = htonl(0);
311       replyIntValue(reply, &returnValue);
312       //CmiUnlock(CsvAccess(pyLock));
313       //PyEval_ReleaseLock();
314       return;  // stop the execution
315     }
316   } else {
317     // the user didn't specify an interpreter, create a new one
318     //CkPrintf("creating new interpreter\n");
319
320     // update the reference number, used to access the current chare
321     pyReference = ++pyNumber;
322     pyNumber &= ~(1<<31);
323     //pyWorkers[pyReference].object = this;
324     pyWorkers[pyReference].clientReady = 0;
325
326     // create the new interpreter
327     PyEval_AcquireLock();
328     PyThreadState *pts = Py_NewInterpreter();
329
330     CkAssert(pts != NULL);
331     pyWorkers[pyReference].pythread = pts;
332
333     Py_InitModule("ck", CkPy_MethodsDefault);
334     if (pyMsg->isHighLevel()) Py_InitModule("charm", getMethods());
335
336     // insert into the dictionary a variable with the reference number
337     PyObject *mod = PyImport_AddModule("__main__");
338     PyObject *dict = PyModule_GetDict(mod);
339
340     PyDict_SetItemString(dict,"__charmNumber__",PyInt_FromLong(pyReference));
341     PyDict_SetItemString(dict,"__charmObject__",PyLong_FromVoidPtr(this));
342     PyRun_String("import ck\nimport sys\n"
343                  "ck.__doc__ = \"Ck module: basic charm routines\\n"
344                  "printstr(str) -- print a string on the server\\n"
345                  "printclient(str) -- print a string on the client\\n"
346                  "mype() -- return an integer for MyPe()\\n"
347                  "numpes() -- return an integer for NumPes()\\n"
348                  "myindex() -- return a tuple containing the array index (valid only for arrays)\\n"
349                  "read(where) -- read a value on the chare (uses the \\\"read\\\" method of the chare)\\n"
350                  "write(where, what) -- write a value back on the chare (uses the \\\"write\\\" method of the chare)\\n\"",
351                  Py_file_input,dict,dict);
352     if (pyMsg->isHighLevel()) {
353       PyRun_String("import charm",Py_file_input,dict,dict);
354       PyRun_String(getMethodsDoc(),Py_file_input,dict,dict);
355     }
356
357     PyRun_String("class __charmOutput__:\n"
358                  "    def __init__(self, stdout):\n"
359                  "        self.stdout = stdout\n"
360                  "    def write(self, s):\n"
361                  "        ck.printclient(s)\n"
362                  "sys.stdout = __charmOutput__(sys.stdout)"
363                  ,Py_file_input,dict,dict);
364
365   }
366
367   pyWorkers[pyReference].inUse = true;
368   if (pyMsg->isKeepPrint()) {
369     pyWorkers[pyReference].isKeepPrint = true;
370   } else {
371     pyWorkers[pyReference].isKeepPrint = false;
372   }
373
374   if (pyMsg->isWait()) {
375     pyWorkers[pyReference].finish = *reply;
376     pyWorkers[pyReference].finishReady = 1;
377   } else {
378     pyWorkers[pyReference].finishReady = 0;
379     // send back this number to the client, which is an ack
380     ckout<<"new interpreter created "<<pyReference<<endl;
381     returnValue = htonl(pyReference);
382     replyIntValue(reply, &returnValue);
383   }
384
385   //if (((*CsvAccess(pyWorkers))[pyReference]).object != this) ckout<<"object not this"<<endl;
386   //else ckout<<"object ok"<<endl;
387
388   //CmiUnlock(CsvAccess(pyLock));
389
390   // run the program
391   if (pyMsg->isHighLevel()) {
392     CthResume(CthCreate((CthVoidFn)_callthr_executeThread, new CkThrCallArg(msg,this), 0));
393     // msg is delete inside the newly created thread
394   } else {
395     executeThread(pyMsg);
396     // delete the message, execute was delegated
397     delete msg;
398   }
399 }
400
401 // created in a new thread, call the executeThread method
402 // we know that the impl_msg contains a CkCcsRequestMsg which data is a
403 // PythonExecute, so we pass directly this latest parameter
404 void PythonObject::_callthr_executeThread(CkThrCallArg *impl_arg) {
405   CkCcsRequestMsg *impl_msg = (CkCcsRequestMsg*)impl_arg->msg;
406   PythonObject *impl_obj = (PythonObject *) impl_arg->obj;
407   delete impl_arg;
408
409   impl_obj->executeThread((PythonExecute*)impl_msg->data);
410   delete impl_msg;
411 }
412
413 void PythonObject::executeThread(PythonExecute *pyMsg) {
414   // get the information about the running python thread and my reference number
415   //ckout << "options  "<<pyMsg->isPersistent()<<endl;
416   PyThreadState *mine = PyThreadState_Get();
417   PyObject *dict = PyModule_GetDict(PyImport_AddModule("__main__"));
418   CmiUInt4 pyReference = PyInt_AsLong(PyDict_GetItemString(dict,"__charmNumber__"));
419
420   // store the self thread for future suspention if high level execution
421   if (pyMsg->isHighLevel()) {
422     //CmiLock(CsvAccess(pyLock));
423     pyWorkers[pyReference].thread=CthSelf();
424     //CmiUnlock(CsvAccess(pyLock));
425   }
426
427   // decide whether it is iterative or not
428   if (!pyMsg->isIterate()) {
429     PyObject* python_output = PyRun_String(pyMsg->code.code, Py_file_input, dict, dict);
430     //PyRun_SimpleString(pyMsg->code.code);
431     //CkPrintf("python_output = %d\n",python_output);
432     if (python_output == NULL) {
433       // return the string error to the client
434       PyObject *ptype, *pvalue, *ptraceback;
435       PyErr_Fetch(&ptype, &pvalue, &ptraceback);
436       PyObject *strP = PyObject_Str(ptype);
437       char *str = PyString_AsString(strP);
438       Ck_printclient(this, pyReference, str);
439       //CkPrintf("%s\n",str);
440       Py_DECREF(strP);
441       Ck_printclient(this, pyReference, ": ");
442       strP = PyObject_Str(pvalue);
443       str = PyString_AsString(strP);
444       Ck_printclient(this, pyReference, str);
445       //CkPrintf("%s\n",str);
446       Py_DECREF(strP);
447       //PyObject_Print(ptype, stdout, 0);
448       //CkPrintf("   %d %d %d %d\n",PyType_Check(ptype),PyString_Check(ptype),PyList_Check(ptype),PyTuple_Check(ptype));
449       //PyObject_Print(pvalue, stdout, 0);
450       //CkPrintf("   %d %d %d %d\n",PyType_Check(pvalue),PyString_Check(pvalue),PyList_Check(pvalue),PyTuple_Check(pvalue));
451       //PyObject_Print(ptraceback, stdout, 0);
452       //if (ptraceback) CkPrintf("   %d %d %d %d\n",PyType_Check(ptraceback),PyString_Check(ptraceback),PyList_Check(ptraceback),PyTuple_Check(ptraceback));
453     }
454   } else {
455     CkPrintf("userCode: |%s|",pyMsg->code);
456     CkPrintf("method: |%s|",pyMsg->methodName.methodName);
457     // compile the program
458     char *userCode = pyMsg->code.code;
459     struct _node* programNode = PyParser_SimpleParseString(userCode, Py_file_input);
460     if (programNode==NULL) {
461       CkPrintf("Program Parse Error\n");
462       // distroy map element in pyWorkers and terminate interpreter
463       cleanup(pyMsg, mine, pyReference);
464       return;
465     }
466     PyCodeObject *program = PyNode_Compile(programNode, "");
467     if (program==NULL) {
468       CkPrintf("Program Compile Error\n");
469       PyNode_Free(programNode);
470       // distroy map element in pyWorkers and terminate interpreter
471       cleanup(pyMsg, mine, pyReference);
472       return;
473     }
474     PyObject *mod = PyImport_AddModule("__main__");
475     PyObject *dict = PyModule_GetDict(mod);
476     PyObject *code = PyEval_EvalCode(program, dict, dict);
477     if (code==NULL) {
478       CkPrintf("Program Eval Error\n");
479       PyNode_Free(programNode);
480       Py_DECREF(program);
481       // distroy map element in pyWorkers and terminate interpreter
482       cleanup(pyMsg, mine, pyReference);
483       return;
484     }
485
486     // load the user defined method
487     char *userMethod = pyMsg->methodName.methodName;
488     PyObject *item = PyDict_GetItemString(dict, userMethod);
489     if (item==NULL) {
490       CkPrintf("Method not found\n");
491       PyNode_Free(programNode);
492       Py_DECREF(program);
493       Py_DECREF(code);
494       // distroy map element in pyWorkers and terminate interpreter
495       cleanup(pyMsg, mine, pyReference);
496       return;
497     }
498
499     // create the container for the data
500     PyRun_String("class CharmContainer:\n\tpass\n\n", Py_file_input, dict, dict);
501     PyObject *part = PyRun_String("CharmContainer()", Py_eval_input, dict, dict);
502     PyObject *arg = PyTuple_New(1);
503     PyObject *oldArg = part;
504
505     // construct the iterator calling the user defined method in the interiting class
506     PythonIterator *userIterator = pyMsg->info.info;
507     int more = buildIterator(part, userIterator);
508     if (oldArg != part) Py_DECREF(oldArg);
509     PyTuple_SetItem(arg, 0, part);
510
511     // iterate over all the provided iterators from the user class
512     PyObject *result;
513     while (more) {
514       result = PyObject_CallObject(item, arg);
515       if (!result) {
516         CkPrintf("Python Call error\n");
517         //PyErr_Print();
518         break;
519       }
520       oldArg = part;
521       more = nextIteratorUpdate(part, result, userIterator);
522       if (oldArg != part) {
523         Py_DECREF(oldArg);
524         PyTuple_SetItem(arg, 0, part);
525       }
526       Py_DECREF(result);
527     }
528
529     Py_DECREF(part);
530     Py_DECREF(arg);
531     PyNode_Free(programNode);
532     Py_DECREF(program);
533     Py_DECREF(code);
534
535   } // end decision if it is iterate or not
536
537   cleanup(pyMsg, mine, pyReference);
538
539 }
540
541 // this function takes care of destroying the interpreter, deleting the
542 // reference into the map table, depending on the flags specified
543 void PythonObject::cleanup (PythonExecute *pyMsg, PyThreadState *pts, CmiUInt4 pyReference) {
544   CmiUInt4 returnValue;
545
546   //ckout <<"cleanup called"<<endl;
547   //CmiLock(CsvAccess(pyLock));
548   // if there is someone waiting for finish, send ackowledge
549   if (pyWorkers[pyReference].finishReady) {
550     //ckout <<"answering the client finish"<<endl;
551     returnValue = htonl(pyReference);
552     replyIntValue(&pyWorkers[pyReference].finish, &returnValue);
553     pyWorkers[pyReference].finishReady = 0;
554   }
555
556   //ckout << "options"<<pyMsg->isPersistent()<<endl;
557   pyWorkers[pyReference].inUse = false;
558   if (!pyMsg->isPersistent()) {
559     Py_EndInterpreter(pts);
560     pyWorkers[pyReference].clientReady = -1;
561   }
562   PyEval_ReleaseLock();
563
564   if (!pyMsg->isPersistent() && pyWorkers[pyReference].printed.length()==0) {
565     // destroy the entry in the map
566     //CkPrintf("destroyed interpreter\n");
567     pyWorkers.erase(pyReference);
568   }
569   //CmiUnlock(CsvAccess(pyLock));
570 }
571
572 void PythonObject::getPrint(CkCcsRequestMsg *msg) {
573
574 }
575
576 // a bunch of routines to ease the user code
577 void PythonObject::pythonSetString(PyObject *arg, char *descr, char *value) {
578   PyObject *tmp = PyString_FromString(value);
579   PyObject_SetAttrString(arg, descr, tmp);
580   Py_DECREF(tmp);
581 }
582
583 void PythonObject::pythonSetString(PyObject *arg, char *descr, char *value, int len) {
584   PyObject *tmp = PyString_FromStringAndSize(value, len);
585   PyObject_SetAttrString(arg, descr, tmp);
586   Py_DECREF(tmp);
587 }
588
589 void PythonObject::pythonGetString(PyObject *arg, char *descr, char **result) {
590   PyObject *tmp = PyObject_GetAttrString(arg, descr);
591   *result = PyString_AsString(tmp);
592   Py_DECREF(tmp);
593 }
594
595 void PythonObject::pythonSetInt(PyObject *arg, char *descr, long value) {
596   PyObject *tmp = PyInt_FromLong(value);
597   PyObject_SetAttrString(arg, descr, tmp);
598   Py_DECREF(tmp);
599 }
600
601 void PythonObject::pythonGetInt(PyObject *arg, char *descr, long *result) {
602   PyObject *tmp = PyObject_GetAttrString(arg, descr);
603   *result = PyInt_AsLong(tmp);
604   Py_DECREF(tmp);
605 }
606
607 void PythonObject::pythonSetLong(PyObject *arg, char *descr, long value) {
608   PyObject *tmp = PyLong_FromLong(value);
609   PyObject_SetAttrString(arg, descr, tmp);
610   Py_DECREF(tmp);
611 }
612
613 void PythonObject::pythonSetLong(PyObject *arg, char *descr, unsigned long value) {
614   PyObject *tmp = PyLong_FromUnsignedLong(value);
615   PyObject_SetAttrString(arg, descr, tmp);
616   Py_DECREF(tmp);
617 }
618
619 void PythonObject::pythonSetLong(PyObject *arg, char *descr, double value) {
620   PyObject *tmp = PyLong_FromDouble(value);
621   PyObject_SetAttrString(arg, descr, tmp);
622   Py_DECREF(tmp);
623 }
624
625 void PythonObject::pythonGetLong(PyObject *arg, char *descr, long *result) {
626   PyObject *tmp = PyObject_GetAttrString(arg, descr);
627   *result = PyLong_AsLong(tmp);
628   Py_DECREF(tmp);
629 }
630
631 void PythonObject::pythonGetLong(PyObject *arg, char *descr, unsigned long *result) {
632   PyObject *tmp = PyObject_GetAttrString(arg, descr);
633   *result = PyLong_AsUnsignedLong(tmp);
634   Py_DECREF(tmp);
635 }
636
637 void PythonObject::pythonGetLong(PyObject *arg, char *descr, double *result) {
638   PyObject *tmp = PyObject_GetAttrString(arg, descr);
639   *result = PyLong_AsDouble(tmp);
640   Py_DECREF(tmp);
641 }
642
643 void PythonObject::pythonSetFloat(PyObject *arg, char *descr, double value) {
644   PyObject *tmp = PyFloat_FromDouble(value);
645   PyObject_SetAttrString(arg, descr, tmp);
646   Py_DECREF(tmp);
647 }
648
649 void PythonObject::pythonGetFloat(PyObject *arg, char *descr, double *result) {
650   PyObject *tmp = PyObject_GetAttrString(arg, descr);
651   *result = PyFloat_AsDouble(tmp);
652   Py_DECREF(tmp);
653 }
654
655 void PythonObject::pythonSetComplex(PyObject *arg, char *descr, double real, double imag) {
656   PyObject *tmp = PyComplex_FromDoubles(real, imag);
657   PyObject_SetAttrString(arg, descr, tmp);
658   Py_DECREF(tmp);
659 }
660
661 void PythonObject::pythonGetComplex(PyObject *arg, char *descr, double *real, double *imag) {
662   PyObject *tmp = PyObject_GetAttrString(arg, descr);
663   *real = PyComplex_RealAsDouble(tmp);
664   *imag = PyComplex_ImagAsDouble(tmp);
665   Py_DECREF(tmp);
666 }
667
668 void PythonObject::pythonSetPointer(PyObject *arg, char *descr, void *ptr) {
669   PyObject *tmp = PyLong_FromVoidPtr(ptr);
670   PyObject_SetAttrString(arg, descr, tmp);
671   Py_DECREF(tmp);
672 }
673
674 void PythonObject::pythonGetPointer(PyObject *arg, char *descr, void **ptr) {
675   PyObject *tmp = PyObject_GetAttrString(arg, descr);
676   *ptr = PyLong_AsVoidPtr(tmp);
677   Py_DECREF(tmp);
678 }
679
680 PyObject *PythonObject::pythonGetArg(int handle) {
681   //CmiLock(CsvAccess(pyLock));
682   PyObject *result = pyWorkers[handle].arg;
683   //CmiUnlock(CsvAccess(pyLock));
684   return result;
685 }
686
687 void PythonObject::pythonReturn(int handle) {
688   // The return value is now set to zero before calling the high-level function, so here
689   // we don't need to do anything.
690   //CmiLock(CsvAccess(pyLock));
691   //CthThread handleThread = ((*CsvAccess(pyWorkers))[handle]).thread;
692   //*((*CsvAccess(pyWorkers))[handle]).result = 0;
693   //CmiUnlock(CsvAccess(pyLock));
694   //CthAwaken(handleThread);
695 }
696
697 void PythonObject::pythonReturn(int handle, PyObject* data) {
698   //CmiLock(CsvAccess(pyLock));
699   //CthThread handleThread = ((*CsvAccess(pyWorkers))[handle]).thread;
700   * pyWorkers[handle].result = data;
701   //CmiUnlock(CsvAccess(pyLock));
702   //CthAwaken(handleThread);
703 }
704
705 /*
706 void PythonObject::pythonAwake(int handle) {
707   CmiLock(CsvAccess(pyLock));
708   PyThreadState *handleThread = ((*CsvAccess(pyWorkers))[handle]).pythread;
709   CmiUnlock(CsvAccess(pyLock));
710   PyEval_AcquireLock();
711   PyThreadState_Swap(handleThread);
712 }
713
714 void PythonObject::pythonSleep(int handle) {
715   PyEval_ReleaseLock();
716 }
717 */
718
719 PythonCCS::PythonCCS(CkArgMsg *arg) {
720   pythonCcsProxy = thishandle;
721 }
722
723 CkReductionMsg *pythonCombinePrint(int nMsg, CkReductionMsg **msgs) {
724   // the final length is the sum of all the NULL-terminated strings, minus
725   // the initial CcsDelayedReply structs and the terminating NULL characters
726   // which are present only once in the final message
727   int length = - (nMsg-1) * sizeof(CcsDelayedReply);
728   for (int i=0; i<nMsg; ++i) {
729     length += msgs[i]->getSize();
730   }
731   
732   CkReductionMsg *result = CkReductionMsg::buildNew(length,NULL);
733   
734   PythonReplyString *data = (PythonReplyString*)(result->getData());
735   data->reply = ((PythonReplyString*)msgs[0]->getData())->reply;
736   char *cur=data->data;
737   for (int i=0; i<nMsg; ++i) {
738     int messageBytes=msgs[i]->getSize() - sizeof(CcsDelayedReply);
739     memcpy((void *)cur,(void *)((PythonReplyString*)msgs[i]->getData())->data,messageBytes);
740     cur+=messageBytes;
741   }
742   return result;
743 }
744
745 void PythonCCS::forwardString(CkReductionMsg *msg) {
746   PythonReplyString *forward = (PythonReplyString *)msg->getData();
747   CcsSendDelayedReply(forward->reply, msg->getSize()-sizeof(CcsDelayedReply), (void *)forward->data);
748 }
749
750 void PythonCCS::forwardInt(CkReductionMsg *msg) {
751   CkPrintf("PythonCCS::forwardInt\n");
752   PythonReplyInt *forward = (PythonReplyInt *)msg->getData();
753   CcsSendDelayedReply(forward->reply, sizeof(CmiUInt4), (void *)&forward->value);
754 }
755
756 CkReduction::reducerType PythonCCS::reduceString;
757
758 static void initializePythonDefault(void) {
759   //CsvInitialize(CmiUInt, pyNumber);
760   //CsvAccess(pyNumber) = 0;
761   //CsvInitialize(PythonTable *,pyWorkers);
762   //CsvAccess(pyWorkers) = new PythonTable();
763   //CsvInitialize(CmiNodeLock, pyLock);
764   //CsvAccess(pyLock) = CmiCreateLock();
765   CtvInitialize(PyObject *,pythonReturnValue);
766
767   PythonCCS::reduceString = CkReduction::addReducer(pythonCombinePrint);
768   
769   Py_Initialize();
770   PyEval_InitThreads();
771
772   PyEval_ReleaseLock();
773 }
774
775 #include "PythonCCS.def.h"