File 0091-Avoid-livelock-in-driver-when-batching-commands.patch of Package erlang

From b901918e7616dd346bfeb3e3c22be608a27f8da4 Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson <dgud@erlang.org>
Date: Tue, 21 Mar 2017 11:59:14 +0100
Subject: [PATCH] Avoid livelock in driver when batching commands

With a bad timing in wx:batch() the driver could get stuck
handling commands without ever checking for gui events.

Avoid that by exiting loop after the driver have done cond_wait a
couple of times.
---
 lib/wx/c_src/wxe_impl.cpp     | 28 +++++++++++++++++-----------
 lib/wx/c_src/wxe_impl.h       |  2 +-
 lib/wx/examples/demo/demo.erl |  3 +++
 lib/wx/src/wxe_master.erl     | 10 ++++++++--
 4 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index 0d2da5d4a..05d56667a 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -128,7 +128,7 @@ bool WxeApp::OnInit()
   delayed_cleanup  = new wxList;
 
   wxe_ps_init2();
-  // wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED); // Hmm printpreview doesn't work in 2.9 with this
+  wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED);
 
   Connect(wxID_ANY, wxEVT_IDLE,	(wxObjectEventFunction) (wxEventFunction) &WxeApp::idle);
   Connect(CREATE_PORT, wxeEVT_META_COMMAND,(wxObjectEventFunction) (wxEventFunction) &WxeApp::newMemEnv);
@@ -200,7 +200,8 @@ void WxeApp::OnAssertFailure(const wxChar *file, int line, const wxChar *cfunc,
 // Called by wx thread
 void WxeApp::idle(wxIdleEvent& event) {
   event.Skip(true);
-  dispatch_cmds();
+  if(dispatch_cmds())
+    event.RequestMore();
 }
 
 /* ************************************************************
@@ -233,14 +234,15 @@ void handle_event_callback(ErlDrvPort port, ErlDrvTermData process)
   }
 }
 
-void WxeApp::dispatch_cmds()
+int WxeApp::dispatch_cmds()
 {
+  int more = 0;
   if(wxe_status != WXE_INITIATED)
-    return;
+    return more;
   recurse_level++;
   // fprintf(stderr, "\r\ndispatch_normal %d\r\n", recurse_level);fflush(stderr);
   wxe_queue->cb_start = 0;
-  dispatch(wxe_queue);
+  more = dispatch(wxe_queue);
   // fprintf(stderr, "\r\ndispatch_done %d\r\n", recurse_level);fflush(stderr);
   recurse_level--;
 
@@ -262,12 +264,14 @@ void WxeApp::dispatch_cmds()
 	delete event;
       }
   }
+  return more;
 }
 
 int WxeApp::dispatch(wxeFifo * batch)
 {
   int ping = 0;
   int blevel = 0;
+  int wait = 0; // Let event handling generate events sometime
   wxeCommand *event;
   erl_drv_mutex_lock(wxe_batch_locker_m);
   while(true) {
@@ -275,10 +279,10 @@ int WxeApp::dispatch(wxeFifo * batch)
       erl_drv_mutex_unlock(wxe_batch_locker_m);
       switch(event->op) {
       case WXE_BATCH_END:
-	{--blevel; }
+	if(blevel>0) blevel--;
 	break;
       case WXE_BATCH_BEGIN:
-	{blevel++; }
+	blevel++;
 	break;
       case WXE_DEBUG_PING:
 	// When in debugger we don't want to hang waiting for a BATCH_END
@@ -293,7 +297,7 @@ int WxeApp::dispatch(wxeFifo * batch)
 	  memcpy(cb_buff, event->buffer, event->len);
 	}
 	event->Delete();
-	return blevel;
+	return 1;
       default:
 	if(event->op < OPENGL_START) {
 	  // fprintf(stderr, "  c %d (%d) \r\n", event->op, blevel);
@@ -307,13 +311,15 @@ int WxeApp::dispatch(wxeFifo * batch)
       erl_drv_mutex_lock(wxe_batch_locker_m);
       batch->Cleanup();
     }
-    if(blevel <= 0) {
+    if(blevel <= 0 || wait > 3) {
       erl_drv_mutex_unlock(wxe_batch_locker_m);
-      return blevel;
+      if(blevel > 0) return 1; // We are still in a batch but we can let wx check for events
+      else return 0;
     }
     // sleep until something happens
-    //fprintf(stderr, "%s:%d sleep %d %d\r\n", __FILE__, __LINE__, batch->m_n, blevel);fflush(stderr);
+    // fprintf(stderr, "%s:%d sleep %d %d %d\r\n", __FILE__, __LINE__, batch->m_n, blevel, wait);fflush(stderr);
     wxe_needs_signal = 1;
+    wait += 1;
     while(batch->m_n == 0) {
       erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
     }
diff --git a/lib/wx/c_src/wxe_impl.h b/lib/wx/c_src/wxe_impl.h
index 57dac997a..68f5deb33 100644
--- a/lib/wx/c_src/wxe_impl.h
+++ b/lib/wx/c_src/wxe_impl.h
@@ -73,7 +73,7 @@ public:
   void wxe_dispatch(wxeCommand& event);
 
   void idle(wxIdleEvent& event);
-  void dispatch_cmds();
+  int dispatch_cmds();
 
   void dummy_close(wxEvent& Ev);
   bool sendevent(wxEvent *event);
diff --git a/lib/wx/examples/demo/demo.erl b/lib/wx/examples/demo/demo.erl
index 8b7412017..0258202a6 100644
--- a/lib/wx/examples/demo/demo.erl
+++ b/lib/wx/examples/demo/demo.erl
@@ -243,6 +243,9 @@ handle_event(#wx{id = Id,
 	    %% If you are going to printout mainly text it is easier if
 	    %% you generate HTML code and use a wxHtmlEasyPrint
 	    %% instead of using DCs
+
+            %% Printpreview doesn't work in >2.9 without this
+            wxIdleEvent:setMode(?wxIDLE_PROCESS_ALL),
 	    Module = "ex_" ++ wxListBox:getStringSelection(State#state.selector) ++ ".erl",
 	    HEP = wxHtmlEasyPrinting:new([{name, "Print"},
 					  {parentWindow, State#state.win}]),
diff --git a/lib/wx/src/wxe_master.erl b/lib/wx/src/wxe_master.erl
index e17a3327a..913bf4d41 100644
--- a/lib/wx/src/wxe_master.erl
+++ b/lib/wx/src/wxe_master.erl
@@ -82,8 +82,14 @@ init_port(SilentStart) ->
 %% Initalizes the opengl library
 %%--------------------------------------------------------------------
 init_opengl() ->
-    GLLib = wxe_util:wxgl_dl(),
-    wxe_util:call(?WXE_INIT_OPENGL, <<(list_to_binary(GLLib))/binary, 0:8>>).
+    case get(wx_init_opengl) of
+        true -> {ok, "already  initialized"};
+        _ ->
+            GLLib = wxe_util:wxgl_dl(),
+            Res = wxe_util:call(?WXE_INIT_OPENGL, <<(list_to_binary(GLLib))/binary, 0:8>>),
+            element(1, Res) =:= ok andalso put(wx_init_opengl, true),
+            Res
+    end.
 
 %%--------------------------------------------------------------------
 %% Fetch early messages, hack to get start up args on mac
-- 
2.12.2

openSUSE Build Service is sponsored by