From 5f9fb860331abe6e439f900edd31e3dd4eda54a3 Mon Sep 17 00:00:00 2001
From: Lars Kanis <kanis@comcard.de>
Date: Mon, 6 Jul 2015 17:54:40 +0200
Subject: [PATCH] Release GVL for FXApp#run and FXDialogBox#execute.

Switch off polling-based (addChore) processing of threads

Add event-based interruption of GVL-released functions.
---
 ext/fox16_c/FXRbApp.cpp             | 39 +++++++++++++++++++++++++----
 ext/fox16_c/include/FXRbApp.h       |  8 ++++++
 ext/fox16_c/include/FXRbDialogBox.h |  2 +-
 ext/fox16_c/include/gvl_wrappers.h  | 32 +++++++++++++++++++++--
 lib/fox16/thread.rb                 |  1 +
 swig-interfaces/FXApp.i             |  6 -----
 swig-interfaces/macros.i            |  2 ++
 7 files changed, 76 insertions(+), 14 deletions(-)

diff --git a/ext/fox16_c/FXRbApp.cpp b/ext/fox16_c/FXRbApp.cpp
index 11d8bb5..b70c5db 100644
--- a/ext/fox16_c/FXRbApp.cpp
+++ b/ext/fox16_c/FXRbApp.cpp
@@ -36,19 +36,25 @@ extern "C" {
 #include <sys/time.h> /* For struct timeval */
 #endif
 
+#include <fcntl.h>
+
 // Message map
 FXDEFMAP(FXRbApp) FXRbAppMap[]={
+#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
+  FXMAPFUNC(SEL_IO_READ,FXRbApp::ID_CHORE_THREADS,FXRbApp::onChoreThreads),
+#else
   FXMAPFUNC(SEL_CHORE,FXRbApp::ID_CHORE_THREADS,FXRbApp::onChoreThreads),
+#endif
   };
 
 // Class implementation
 FXRbIMPLEMENT(FXRbApp,FXApp,FXRbAppMap,ARRAYNUMBER(FXRbAppMap))
 
+int FXRbApp::interrupt_fds[2] = {-1, -1};
+
 // Constructor
-FXRbApp::FXRbApp(const FXchar* appname,const FXchar* vendor) : FXApp(appname,vendor),m_bThreadsEnabled(TRUE),sleepTime(100){
-  if(m_bThreadsEnabled){
-    addChore(this,ID_CHORE_THREADS);
-    }
+FXRbApp::FXRbApp(const FXchar* appname,const FXchar* vendor) : FXApp(appname,vendor),m_bThreadsEnabled(FALSE),sleepTime(100){
+  setThreadsEnabled(TRUE);
   }
 
 
@@ -67,7 +73,12 @@ void FXRbApp::setThreadsEnabled(FXbool enabled){
   if(enabled){
     if(!m_bThreadsEnabled){
       m_bThreadsEnabled=TRUE;
+#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
+      pipe2(interrupt_fds, O_NONBLOCK);
+      addInput(interrupt_fds[0],INPUT_READ,this,ID_CHORE_THREADS);
+#else
       addChore(this,ID_CHORE_THREADS);
+#endif
       }
     }
   else{
@@ -88,9 +99,21 @@ FXuint FXRbApp::getSleepTime() const {
   return sleepTime;
   }
 
+long FXRbApp::onChoreThreads(FXObject *obj,FXSelector sel,void *p){
+  return FXRbApp_onChoreThreads(this, obj, sel, p);
+  }
+
+long FXRbApp_onChoreThreads_gvlcb(FXRbApp *self,FXObject *obj,FXSelector sel,void *p){
+  return self->onChoreThreads_gvlcb(obj, sel, p);
+  }
 
 // Process threads
-long FXRbApp::onChoreThreads(FXObject*,FXSelector,void*){
+long FXRbApp::onChoreThreads_gvlcb(FXObject*,FXSelector,void*){
+#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
+  char byte;
+  // clear the pipe
+  read(interrupt_fds[0], &byte, 1);
+#else
   // Pause for 'sleepTime' millseconds
   struct timeval wait;
   wait.tv_sec=0;
@@ -108,11 +131,17 @@ long FXRbApp::onChoreThreads(FXObject*,FXSelector,void*){
 
   // Re-register this chore for next time
   addChore(this,ID_CHORE_THREADS);
+#endif
 
   // Back to work...
   return 1;
   }
 
+#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
+void fxrb_wakeup_fox(void *){
+  int l = write(FXRbApp::interrupt_fds[1], "X", 1);
+  }
+#endif
 
 // Destructor
 FXRbApp::~FXRbApp(){
diff --git a/ext/fox16_c/include/FXRbApp.h b/ext/fox16_c/include/FXRbApp.h
index 17375a2..68cea6f 100644
--- a/ext/fox16_c/include/FXRbApp.h
+++ b/ext/fox16_c/include/FXRbApp.h
@@ -38,6 +38,9 @@ inline void cls ## _detach(cls *self){ \
 inline void cls ## _create(cls *self){ \
   self->cls::create(); \
   } \
+inline FXint cls ## _run_gvl(cls *self){ \
+  return self->cls::run(); \
+  } \
 static void cls ## _init(cls* self,VALUE ary,bool connect){ \
   int i; \
   char **argv; \
@@ -114,6 +117,8 @@ class FXRbApp : public FXApp {
 protected:
   FXbool m_bThreadsEnabled;
   FXuint sleepTime;
+public:
+  static int interrupt_fds[2];
 protected:
   FXRbApp(){}
 public:
@@ -126,6 +131,7 @@ public:
     };
 public:
   long onChoreThreads(FXObject*,FXSelector,void*);
+  long onChoreThreads_gvlcb(FXObject*,FXSelector,void*);
 public:
   // Constructor
   FXRbApp(const FXchar* name,const FXchar* vendor);
@@ -152,4 +158,6 @@ public:
   virtual ~FXRbApp();
   };
 
+long FXRbApp_onChoreThreads_gvlcb(FXRbApp*,FXObject*,FXSelector,void*);
+
 #endif
diff --git a/ext/fox16_c/include/FXRbDialogBox.h b/ext/fox16_c/include/FXRbDialogBox.h
index 883b926..4a748a4 100644
--- a/ext/fox16_c/include/FXRbDialogBox.h
+++ b/ext/fox16_c/include/FXRbDialogBox.h
@@ -28,7 +28,7 @@
 #define FXRBDIALOGBOX_H
 
 #define DECLARE_FXDIALOGBOX_STUBS(klass) \
-inline FXuint klass ## _execute(klass* self,FXuint placement){ \
+inline FXuint klass ## _execute_gvl(klass* self,FXuint placement){ \
   return self->klass::execute(placement); \
   }
 
diff --git a/ext/fox16_c/include/gvl_wrappers.h b/ext/fox16_c/include/gvl_wrappers.h
index df47817..9013224 100644
--- a/ext/fox16_c/include/gvl_wrappers.h
+++ b/ext/fox16_c/include/gvl_wrappers.h
@@ -26,6 +26,8 @@ extern "C" {
   #endif
 }
 
+void fxrb_wakeup_fox(void *);
+
 #define DEFINE_PARAM_LIST1(type, ref, name) \
   , name
 
@@ -71,7 +73,7 @@ extern __thread int g_fxrb_thread_has_gvl;
       struct gvl_wrapper_##klass##_##name##_params params = { \
         {firstparamname FOR_EACH_PARAM_OF_##baseclass##_##name(DEFINE_PARAM_LIST1)}, when_non_void((rettype)0) \
       }; \
-      rb_thread_call_without_gvl(gvl_##klass##_##name##_skeleton, &params, RUBY_UBF_IO, 0); \
+      rb_thread_call_without_gvl(gvl_##klass##_##name##_skeleton, &params, fxrb_wakeup_fox, 0); \
       when_non_void( return params.retval; ) \
     }
 #else
@@ -147,6 +149,11 @@ extern __thread int g_fxrb_thread_has_gvl;
 #define FOR_EACH_PARAM_OF_FXImage_savePixels(param) \
   param(FXStream, &, store)
 
+#define FOR_EACH_PARAM_OF_FXDialogBox_execute(param) \
+  param(FXuint, , placement)
+
+#define FOR_EACH_PARAM_OF_FXApp_run(param)
+
 /* function( class, name, baseclass, void_or_nonvoid, returntype, firstparamtype, firstparamname ) */
 #define FOR_EACH_BLOCKING_FUNCTION(function) \
   function(FXImage, loadPixels, FXImage, GVL_TYPE_NONVOID, bool, FXImage *, self) \
@@ -200,7 +207,22 @@ extern __thread int g_fxrb_thread_has_gvl;
   function(FXXBMIcon, loadPixels, FXImage, GVL_TYPE_NONVOID, bool, FXXBMIcon *, self) \
   function(FXXBMIcon, savePixels, FXImage, GVL_TYPE_NONVOID, bool, const FXXBMIcon *, self) \
   function(FXXPMIcon, loadPixels, FXImage, GVL_TYPE_NONVOID, bool, FXXPMIcon *, self) \
-  function(FXXPMIcon, savePixels, FXImage, GVL_TYPE_NONVOID, bool, const FXXPMIcon *, self)
+  function(FXXPMIcon, savePixels, FXImage, GVL_TYPE_NONVOID, bool, const FXXPMIcon *, self) \
+  function(FXChoiceBox, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXChoiceBox *, self) \
+  function(FXColorDialog, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXColorDialog *, self) \
+  function(FXDialogBox, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXDialogBox *, self) \
+  function(FXDirDialog, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXDirDialog *, self) \
+  function(FXFileDialog, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXFileDialog *, self) \
+  function(FXFontDialog, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXFontDialog *, self) \
+  function(FXInputDialog, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXInputDialog *, self) \
+  function(FXMessageBox, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXMessageBox *, self) \
+  function(FXPrintDialog, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXPrintDialog *, self) \
+  function(FXProgressDialog, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXProgressDialog *, self) \
+  function(FXReplaceDialog, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXReplaceDialog *, self) \
+  function(FXSearchDialog, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXSearchDialog *, self) \
+  function(FXWizard, execute, FXDialogBox, GVL_TYPE_NONVOID, FXuint, FXWizard *, self) \
+  function(FXApp, run, FXApp, GVL_TYPE_NONVOID, FXint, FXApp *, self) \
+
 
 
 FOR_EACH_BLOCKING_FUNCTION( DEFINE_GVL_STUB_DECL )
@@ -470,6 +492,11 @@ FOR_EACH_BLOCKING_FUNCTION( DEFINE_GVL_STUB_DECL )
   param(TYPE1, , arg1) \
   param(TYPE2, , arg2)
 
+#define FOR_EACH_PARAM_OF_FXRbApp_onChoreThreads_4(param) \
+  param(ID, , func) \
+  param(TYPE1, , arg1) \
+  param(TYPE2, , arg2)
+
 
 /* function( name, void_or_nonvoid, returntype, firstparamtype, firstparamname, paramcount ) */
 #define FOR_EACH_CALLBACK_FUNCTION(function) \
@@ -524,6 +551,7 @@ FOR_EACH_BLOCKING_FUNCTION( DEFINE_GVL_STUB_DECL )
   function(FXRbCallDCDrawMethod, GVL_TYPE_VOID, void, RECV, recv, 6) \
   function(FXRbCallTreeItemMethod, GVL_TYPE_NONVOID, FXTreeItem*, RECV, recv, 4) \
   function(FXRbCallFoldingItemMethod, GVL_TYPE_NONVOID, FXFoldingItem*, RECV, recv, 4) \
+  function(FXRbApp_onChoreThreads, GVL_TYPE_NONVOID, long, RECV, recv, 4) \
 
 
 FOR_EACH_CALLBACK_FUNCTION( DEFINE_GVLCB_STUB_DECL )
diff --git a/lib/fox16/thread.rb b/lib/fox16/thread.rb
index 0cf58ee..902b8e8 100644
--- a/lib/fox16/thread.rb
+++ b/lib/fox16/thread.rb
@@ -24,6 +24,7 @@ module Fox
         gs = TCPServer.open('localhost', 0)
         prd = TCPSocket.open('localhost', gs.addr[1])
         pwr = gs.accept
+        gs.close
       else
         prd, pwr = IO.pipe
       end
diff --git a/swig-interfaces/FXApp.i b/swig-interfaces/FXApp.i
index f25f8b4..f3aa4b0 100644
--- a/swig-interfaces/FXApp.i
+++ b/swig-interfaces/FXApp.i
@@ -397,12 +397,6 @@ public:
   /// Perform one event dispatch; return true if event was dispatched
   bool runOneEvent(bool blocking=true);
 
-  /**
-  * Run the main application event loop until stop() is called,
-  * and return the exit code passed as argument to stop().
-  */
-  FXint run();
-
   /**
   * Run an event loop till some flag becomes non-zero, and
   * then return.
diff --git a/swig-interfaces/macros.i b/swig-interfaces/macros.i
index 8ed1e82..3349425 100644
--- a/swig-interfaces/macros.i
+++ b/swig-interfaces/macros.i
@@ -31,6 +31,8 @@
   /// Detach application's windows
   virtual void detach();
 
+  FXint run();
+
   /**
    * Initialize application.
    * Parses and removes common command line arguments, reads the registry.
-- 
GitLab