@@ -24,6 +24,7 @@ void process_body(int read_fd, int send_fd, bool isMultiOutput) {
2424 close (send_fd);
2525 close (read_fd);
2626 pickl.~pickling ();
27+  //  finalize python interpreter
2728 Py_Finalize ();
2829 exit (0 );
2930 };
@@ -33,12 +34,10 @@ void process_body(int read_fd, int send_fd, bool isMultiOutput) {
3334 //  receive serialized node
3435 int  err = receiveMessage (read_fd, send_fd, message);
3536 if  (err <= 0 ) handleError (" [child] read serialized node"  , cleanup_exit ());
36-  LOG (" [child] read serialized node"  );
3737
3838 //  deserialize Python node
3939 auto  node = pickl.unpickle (message.data );
4040 CHECK_ERROR_THEN (" [child] unpickle node failure: "  , cleanup_exit ();)
41-  LOG (" [child] deserialized node"  );
4241
4342 py_ff_callback_object* callback = (py_ff_callback_object*) PyObject_CallObject (
4443 (PyObject *) &py_ff_callback_type, NULL 
@@ -76,8 +75,6 @@ void process_body(int read_fd, int send_fd, bool isMultiOutput) {
7675 return  (PyObject*) NULL ;
7776 }
7877
79-  LOG (" [child] sent ff_send_out_to message"  );
80-  
8178 //  receive response
8279 err = receiveMessage (read_fd, send_fd, message);
8380 if  (err <= 0 ) {
@@ -104,41 +101,42 @@ void process_body(int read_fd, int send_fd, bool isMultiOutput) {
104101
105102 while (err > 0 ) {
106103 err = receiveMessage (read_fd, send_fd, message);
107-  if  (err < 0 ) handleError (" [child] read next"  , cleanup_exit ());
108- 
109-  if  (err > 0 ) {
110-  //  deserialize data
111-  auto  py_args_tuple = pickl.unpickle (message.data );
112-  CHECK_ERROR_THEN (" [child] deserialize data failure: "  , cleanup_exit ();)
113-  //  call function
114-  PyObject *py_func = PyObject_GetAttrString (node, message.f_name .c_str ());
115-  CHECK_ERROR_THEN (" [child] get node function: "  , cleanup_exit ();)
116- 
117-  if  (py_func) {
118-  //  finally call the function
119-  PyObject* py_result = PyTuple_Check (py_args_tuple) == 1  ? PyObject_CallObject (py_func, py_args_tuple):PyObject_CallFunctionObjArgs (py_func, py_args_tuple, nullptr );
120-  CHECK_ERROR_THEN (" [child] call function failure: "  , cleanup_exit ();)
121- 
122-  //  we may have a fastflow constant as result
123-  if  (PyObject_TypeCheck (py_result, &py_ff_constant_type) != 0 ) {
124-  //  py_ff_constant_object* _const_result = reinterpret_cast<py_ff_constant_object*>(py_result);
125-  //  the only constant available is FF_GO_ON
126-  err = sendMessage (read_fd, send_fd, { .type  = MESSAGE_TYPE_RESPONSE_GO_ON, .data  = " "  , .f_name  = " "   });
127-  if  (err <= 0 ) handleError (" [child] send constant response"  , cleanup_exit ());
128-  LOG (" [child] sent constant response"  );
129-  } else  {
130-  //  serialize response
131-  auto  result_str = pickl.pickle (py_result);
132-  CHECK_ERROR_THEN (" [child] pickle result failure: "  , cleanup_exit ();)
133- 
134-  //  send response
135-  err = sendMessage (read_fd, send_fd, { .type  = MESSAGE_TYPE_RESPONSE, .data  = result_str, .f_name  = " "   });
136-  if  (err <= 0 ) handleError (" [child] send response"  , cleanup_exit ());
137-  LOG (" [child] sent response"  );
138- 
139-  Py_DECREF (py_result);
140-  Py_DECREF (py_func);
141-  }
104+  if  (err <= 0 ) handleError (" [child] read next"  , cleanup_exit ());
105+  
106+  if  (message.type  == MESSAGE_TYPE_END_OF_LIFE) break ;
107+  
108+  //  deserialize data
109+  auto  py_args_tuple = pickl.unpickle (message.data );
110+  CHECK_ERROR_THEN (" [child] deserialize data failure: "  , cleanup_exit ();)
111+  //  call function
112+  PyObject *py_func = PyObject_GetAttrString (node, message.f_name .c_str ());
113+  CHECK_ERROR_THEN (" [child] get node function: "  , cleanup_exit ();)
114+ 
115+  if  (py_func) {
116+  //  finally call the function
117+  PyObject* py_result = PyTuple_Check (py_args_tuple) == 1  ? PyObject_CallObject (py_func, py_args_tuple):PyObject_CallFunctionObjArgs (py_func, py_args_tuple, nullptr );
118+  CHECK_ERROR_THEN (" [child] call function failure: "  , cleanup_exit ();)
119+ 
120+  //  we may have a fastflow constant as result
121+  if  (PyObject_TypeCheck (py_result, &py_ff_constant_type) != 0 ) {
122+  py_ff_constant_object* _const_result = reinterpret_cast <py_ff_constant_object*>(py_result);
123+  err = sendMessage (read_fd, send_fd, { 
124+  .type  = _const_result->ff_const  == ff::FF_EOS ? MESSAGE_TYPE_EOS:MESSAGE_TYPE_GO_ON, 
125+  .data  = " "  , 
126+  .f_name  = " "   
127+  });
128+  if  (err <= 0 ) handleError (" [child] send constant response"  , cleanup_exit ());
129+  } else  {
130+  //  serialize response
131+  auto  result_str = pickl.pickle (py_result);
132+  CHECK_ERROR_THEN (" [child] pickle result failure: "  , cleanup_exit ();)
133+ 
134+  //  send response
135+  err = sendMessage (read_fd, send_fd, { .type  = MESSAGE_TYPE_RESPONSE, .data  = result_str, .f_name  = " "   });
136+  if  (err <= 0 ) handleError (" [child] send response"  , cleanup_exit ());
137+ 
138+  Py_DECREF (py_result);
139+  Py_DECREF (py_func);
142140 }
143141 }
144142 }
@@ -159,7 +157,6 @@ class base_process {
159157 }
160158
161159 int  svc_init () {
162-  TIMESTART (svc_init_start_time);
163160 //  associate a new thread state with ff_node's thread
164161 PyThreadState* cached_tstate = tstate;
165162 tstate = PyThreadState_New (cached_tstate->interp );
@@ -252,7 +249,6 @@ class base_process {
252249 }
253250
254251 //  from here the GIL is NOT acquired
255-  LOGELAPSED (" svc_init time "  , svc_init_start_time);
256252 return  returnValue;
257253 }
258254
@@ -264,7 +260,6 @@ class base_process {
264260 int  err = remote_procedure_call (send_fd, read_fd, serialized_data, " svc"  , response);
265261 if  (err <= 0 ) {
266262 handleError (" remote call of svc"  , );
267-  LOG (" an error occurred, abort."  );
268263 return  NULL ;
269264 }
270265
@@ -273,7 +268,6 @@ class base_process {
273268 //  if the call of ff_send_out_to (as of today...)
274269 if  (response.f_name .compare (" ff_send_out_to"  ) != 0 ) {
275270 handleError (" got invalid f_name"  , );
276-  LOG (" an error occurred, got invalid f_name. Abort."  );
277271 return  NULL ;
278272 }
279273
@@ -291,63 +285,51 @@ class base_process {
291285 err = sendMessage (read_fd, send_fd, { .type  = MESSAGE_TYPE_RESPONSE, .data  = result ? " t"  :" f"  , .f_name  = " "   });
292286 if  (err <= 0 ) {
293287 handleError (" error sending ff_send_out_to response"  , );
294-  LOG (" an error occurred, sending ff_send_out_to. Abort."  );
295288 return  NULL ;
296289 }
297290
298291 //  prepare for next iteration
299292 err = receiveMessage (read_fd, send_fd, response);
300293 if  (err <= 0 ) {
301294 handleError (" waiting for svc response"  , );
302-  LOG (" an error occurred, abort."  );
303295 return  NULL ;
304296 }
305297 }
306298
307299 //  got response of svc
308-  if  (response.type  == MESSAGE_TYPE_RESPONSE_GO_ON) return  ff::FF_GO_ON;
309-  if  (response.type  == MESSAGE_TYPE_RESPONSE_EOS) return  ff::FF_EOS;
310-  if  (response.data .compare (none_str) == 0 ) return  ff::FF_EOS;
300+  if  (response.type  == MESSAGE_TYPE_EOS) return  ff::FF_EOS;
301+  if  (response.type  == MESSAGE_TYPE_GO_ON || response.data .compare (none_str) == 0 ) {
302+  return  ff::FF_GO_ON;
303+  }
311304
312305 return  new  std::string (response.data );
313306 }
314307
315-  void  cleanup () {
316-  //  Cleanup of objects created
317-  Py_DECREF (node);
318-  node = nullptr ;
319-  tstate = nullptr ;
320-  PyEval_SaveThread ();
321- 
322-  if  (send_fd > 0 ) close (send_fd);
323-  send_fd = -1 ;
324-  if  (read_fd > 0 ) close (read_fd);
325-  send_fd = -1 ;
326-  }
327- 
328308 void  svc_end () {
329-  TIMESTART (svc_end_start_time);
330- 
331309 if  (has_svc_end) {
332310 Message response;
333311 auto  empty_tuple = std::string (SERIALIZED_EMPTY_TUPLE);
334312 int  err = remote_procedure_call (send_fd, read_fd, empty_tuple, " svc_end"  , response);
335313 if  (err <= 0 ) handleError (" read result of remote call of svc_end"  , );
336314 }
337315
338-  //  close the pipes, so the process can stop meanwhile we acquire the GIL and cleanup everything
316+  //  send end of life. Meanwhile we acquire the GIL and cleanup, the process will stop
317+  int  err = sendMessage (read_fd, send_fd, { .type  = MESSAGE_TYPE_END_OF_LIFE, .data  = " "  , .f_name  = " "   });
318+  
319+  //  Acquire the main GIL
320+  PyEval_RestoreThread (tstate);
321+  //  Cleanup of objects created
322+  Py_DECREF (node);
323+  node = nullptr ;
324+  tstate = nullptr ;
325+  //  Release the main GIL
326+  PyEval_SaveThread ();
327+  waitpid (pid, nullptr , 0 );
328+ 
339329 if  (send_fd > 0 ) close (send_fd);
340330 send_fd = -1 ;
341331 if  (read_fd > 0 ) close (read_fd);
342332 send_fd = -1 ;
343- 
344-  waitpid (pid, nullptr , 0 );
345- 
346-  //  Acquire the main GIL
347-  PyEval_RestoreThread (tstate);
348-  cleanup ();
349- 
350-  LOGELAPSED (" svc_end time "  , svc_end_start_time);
351333 }
352334
353335 void  register_callback (ff::ff_monode* cb_node) {
0 commit comments