aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Gudmundsson <[email protected]>2015-05-05 09:31:18 +0200
committerDan Gudmundsson <[email protected]>2015-05-05 09:31:18 +0200
commit676500a8042165ae3391275fb638471a5a05b25f (patch)
treef38c152677c66e13c4bf79df0dd46e5140812441
parent727338fe38bb9aae0ea4d9069d8a1d6e1694a2dd (diff)
parent60229a03667a9bac8917a78c922bec4885d2d53f (diff)
downloadotp-676500a8042165ae3391275fb638471a5a05b25f.tar.gz
otp-676500a8042165ae3391275fb638471a5a05b25f.tar.bz2
otp-676500a8042165ae3391275fb638471a5a05b25f.zip
Merge branch 'dgud/wx/optimize-queues'
* dgud/wx/optimize-queues: wx: Fix delete object wx: Optimize command queues wx: Optimize OpenGL invocations
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl4
-rw-r--r--lib/wx/c_src/gen/wxe_funcs.cpp6
-rw-r--r--lib/wx/c_src/wxe_gl.cpp8
-rw-r--r--lib/wx/c_src/wxe_helpers.cpp167
-rw-r--r--lib/wx/c_src/wxe_helpers.h30
-rw-r--r--lib/wx/c_src/wxe_impl.cpp298
-rw-r--r--lib/wx/c_src/wxe_impl.h6
-rw-r--r--lib/wx/test/wx_event_SUITE.erl42
8 files changed, 350 insertions, 211 deletions
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index 720526b3b9..8e32aeddc8 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -197,8 +197,8 @@ gen_funcs(Defs) ->
w(" if(recurse_level > 1 && refd->type != 4) {~n"),
w(" delayed_delete->Append(Ecmd.Save());~n"),
w(" } else {~n"),
- w(" ((WxeApp *) wxTheApp)->clearPtr(This);~n"),
- w(" delete_object(This, refd); }~n"),
+ w(" delete_object(This, refd);~n"),
+ w(" ((WxeApp *) wxTheApp)->clearPtr(This);}~n"),
w(" } } break;~n"),
w(" case WXE_REGISTER_OBJECT: {~n"
" registerPid(bp, Ecmd.caller, memenv);~n"
diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp
index 91ce5d810c..3b11c0642e 100644
--- a/lib/wx/c_src/gen/wxe_funcs.cpp
+++ b/lib/wx/c_src/gen/wxe_funcs.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2015. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -51,8 +51,8 @@ void WxeApp::wxe_dispatch(wxeCommand& Ecmd)
if(recurse_level > 1 && refd->type != 4) {
delayed_delete->Append(Ecmd.Save());
} else {
- ((WxeApp *) wxTheApp)->clearPtr(This);
- delete_object(This, refd); }
+ delete_object(This, refd);
+ ((WxeApp *) wxTheApp)->clearPtr(This);}
} } break;
case WXE_REGISTER_OBJECT: {
registerPid(bp, Ecmd.caller, memenv);
diff --git a/lib/wx/c_src/wxe_gl.cpp b/lib/wx/c_src/wxe_gl.cpp
index a9feb23831..26b45d219e 100644
--- a/lib/wx/c_src/wxe_gl.cpp
+++ b/lib/wx/c_src/wxe_gl.cpp
@@ -135,8 +135,12 @@ void deleteActiveGL(wxGLCanvas *canvas)
void gl_dispatch(int op, char *bp,ErlDrvTermData caller,WXEBinRef *bins[]){
if(caller != gl_active) {
wxGLCanvas * current = glc[caller];
- if(current) { gl_active = caller; current->SetCurrent();}
- else {
+ if(current) {
+ if(current != glc[gl_active]) {
+ gl_active = caller;
+ current->SetCurrent();
+ }
+ } else {
ErlDrvTermData rt[] = // Error msg
{ERL_DRV_ATOM, driver_mk_atom((char *) "_egl_error_"),
ERL_DRV_INT, (ErlDrvTermData) op,
diff --git a/lib/wx/c_src/wxe_helpers.cpp b/lib/wx/c_src/wxe_helpers.cpp
index 15d75080d9..120919e7aa 100644
--- a/lib/wx/c_src/wxe_helpers.cpp
+++ b/lib/wx/c_src/wxe_helpers.cpp
@@ -24,23 +24,96 @@
* Erlang Commands
* ****************************************************************************/
-wxeCommand::wxeCommand(int fc,char * cbuf,int buflen, wxe_data *sd)
- : wxObject()
+wxeCommand::wxeCommand()
{
+}
+
+wxeCommand::~wxeCommand()
+{
+ Delete();
+}
+
+void wxeCommand::Delete()
+{
+ int n = 0;
+
+ if(buffer) {
+ while(bin[n]) {
+ if(bin[n]->bin)
+ driver_free_binary(bin[n]->bin);
+ driver_free(bin[n++]);
+ }
+ if(len > 64)
+ driver_free(buffer);
+ buffer = NULL;
+ op = -1;
+ }
+}
+
+/* ****************************************************************************
+ * wxeFifo
+ * ****************************************************************************/
+wxeFifo::wxeFifo(unsigned int sz)
+{
+ m_q = (wxeCommand *) driver_alloc(sizeof(wxeCommand) * sz);
+ m_orig_sz = sz;
+ m_max = sz;
+ m_n = 0;
+ m_first = 0;
+ m_old = NULL;
+ for(unsigned int i = 0; i < sz; i++) {
+ m_q[i].buffer = NULL;
+ m_q[i].op = -1;
+ }
+}
+
+wxeFifo::~wxeFifo() {
+ // dealloc all memory buffers
+ driver_free(m_q);
+}
+
+wxeCommand * wxeFifo::Get()
+{
+ unsigned int pos;
+ if(m_n > 0) {
+ pos = m_first++;
+ m_n--;
+ m_first %= m_max;
+ return &m_q[pos];
+ }
+ return NULL;
+}
+
+void wxeFifo::Add(int fc, char * cbuf,int buflen, wxe_data *sd)
+{
+ unsigned int pos;
+ wxeCommand *curr;
+
WXEBinRef *temp, *start, *prev;
int n = 0;
- ref_count = 1;
- caller = driver_caller(sd->port_handle);
- port = sd->port;
- op = fc;
- len = buflen;
- bin[0] = NULL;
- bin[1] = NULL;
- bin[2] = NULL;
+
+ if(m_n == (m_max-1)) { // resize
+ Realloc();
+ }
+
+ pos = (m_first + m_n) % m_max;
+ m_n++;
+
+ curr = &m_q[pos];
+ curr->caller = driver_caller(sd->port_handle);
+ curr->port = sd->port;
+ curr->op = fc;
+ curr->len = buflen;
+ curr->bin[0] = NULL;
+ curr->bin[1] = NULL;
+ curr->bin[2] = NULL;
if(cbuf) {
- buffer = (char *) driver_alloc(len);
- memcpy((void *) buffer, (void *) cbuf, len);;
+ if(buflen > 64)
+ curr->buffer = (char *) driver_alloc(buflen);
+ else
+ curr->buffer = curr->c_buf;
+ memcpy((void *) curr->buffer, (void *) cbuf, buflen);
temp = sd->bin;
@@ -48,8 +121,8 @@ wxeCommand::wxeCommand(int fc,char * cbuf,int buflen, wxe_data *sd)
start = temp;
while(temp) {
- if(caller == temp->from) {
- bin[n++] = temp;
+ if(curr->caller == temp->from) {
+ curr->bin[n++] = temp;
if(prev) {
prev->next = temp->next;
} else {
@@ -63,20 +136,68 @@ wxeCommand::wxeCommand(int fc,char * cbuf,int buflen, wxe_data *sd)
}
sd->bin = start;
} else { // No-op only PING currently
- buffer = NULL;
+ curr->buffer = NULL;
}
}
-wxeCommand::~wxeCommand() {
- int n = 0;
- if(buffer) {
- while(bin[n]) {
- if(bin[n]->bin)
- driver_free_binary(bin[n]->bin);
- driver_free(bin[n++]);
+void wxeFifo::Append(wxeCommand *orig)
+{
+ unsigned int pos;
+ wxeCommand *curr;
+ if(m_n == (m_max-1)) { // resize
+ Realloc();
+ }
+
+ pos = (m_first + m_n) % m_max;
+ m_n++;
+ curr = &m_q[pos];
+ curr->caller = orig->caller;
+ curr->port = orig->port;
+ curr->op = orig->op;
+ curr->len = orig->len;
+ curr->bin[0] = orig->bin[0];
+ curr->bin[1] = orig->bin[1];
+ curr->bin[2] = orig->bin[2];
+
+ if(orig->len > 64)
+ curr->buffer = orig->buffer;
+ else {
+ curr->buffer = curr->c_buf;
+ memcpy((void *) curr->buffer, (void *) orig->buffer, orig->len);
+ }
+ orig->op = -1;
+ orig->buffer = NULL;
+ orig->bin[0] = NULL;
+}
+
+void wxeFifo::Realloc()
+{
+ unsigned int i;
+ unsigned int growth = m_orig_sz / 2;
+ unsigned int new_sz = growth + m_max;
+ unsigned int max = m_max;
+ unsigned int first = m_first;
+ unsigned int n = m_n;
+ wxeCommand * old = m_q;
+ wxeCommand * queue = (wxeCommand *)driver_alloc(new_sz*sizeof(wxeCommand));
+
+ m_max=new_sz;
+ m_first = 0;
+ m_n=0;
+ m_q = queue;
+
+ for(i=0; i < n; i++) {
+ unsigned int pos = i+first;
+ if(old[pos%max].op >= 0) {
+ Append(&old[pos%max]);
}
- driver_free(buffer);
}
+ for(i = m_n; i < new_sz; i++) { // Reset the rest
+ m_q[i].buffer = NULL;
+ m_q[i].op = -1;
+ }
+ // Can not free old queue here it can be used in the wx thread
+ m_old = old;
}
/* ****************************************************************************
diff --git a/lib/wx/c_src/wxe_helpers.h b/lib/wx/c_src/wxe_helpers.h
index 659bc666c6..ec3a5debdb 100644
--- a/lib/wx/c_src/wxe_helpers.h
+++ b/lib/wx/c_src/wxe_helpers.h
@@ -39,14 +39,14 @@ class wxeMetaCommand : public wxEvent
ErlDrvPDL pdl;
};
-class wxeCommand : public wxObject
+class wxeCommand
{
public:
- wxeCommand(int fc,char * cbuf,int buflen, wxe_data *);
+ wxeCommand();
virtual ~wxeCommand(); // Use Delete()
- wxeCommand * Save() {ref_count++; return this; };
- void Delete() {if(--ref_count < 1) delete this;};
+ wxeCommand * Save() { return this; };
+ void Delete();
ErlDrvTermData caller;
ErlDrvTermData port;
@@ -54,7 +54,27 @@ class wxeCommand : public wxObject
char * buffer;
int len;
int op;
- int ref_count;
+ char c_buf[64]; // 64b covers 90% of usage
+};
+
+class wxeFifo {
+ public:
+ wxeFifo(unsigned int size);
+ virtual ~wxeFifo();
+
+ void Add(int fc, char * cbuf,int buflen, wxe_data *);
+ void Append(wxeCommand *Other);
+
+ wxeCommand * Get();
+
+ void Realloc();
+
+ unsigned int m_max;
+ unsigned int m_first;
+ unsigned int m_n;
+ unsigned int m_orig_sz;
+ wxeCommand *m_q;
+ wxeCommand *m_old;
};
class intListElement {
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index 0ee52e3af2..ef648e008c 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -55,8 +55,9 @@ extern ErlDrvCond * wxe_batch_locker_c;
extern ErlDrvTermData init_caller;
extern int wxe_status;
-wxList * wxe_batch = NULL;
-wxList * wxe_batch_cb_saved = NULL;
+wxeFifo * wxe_queue = NULL;
+wxeFifo * wxe_queue_cb_saved = NULL;
+
int wxe_batch_caller = 0; // inside batch if larger than 0
/* ************************************************************
@@ -68,30 +69,30 @@ void push_command(int op,char * buf,int len, wxe_data *sd)
{
/* fprintf(stderr, "Op %d %d [%ld] %d\r\n", op, (int) driver_caller(sd->port_handle),
wxe_batch->size(), wxe_batch_caller),fflush(stderr); */
- wxeCommand *Cmd = new wxeCommand(op, buf, len, sd);
erl_drv_mutex_lock(wxe_batch_locker_m);
- wxe_batch->Append(Cmd);
+ wxe_queue->Add(op, buf, len, sd);
if(wxe_batch_caller > 0) {
// wx-thread is waiting on batch end in cond_wait
erl_drv_cond_signal(wxe_batch_locker_c);
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
} else {
// wx-thread is waiting gui-events
if(op == WXE_BATCH_BEGIN) {
wxe_batch_caller = 1;
}
erl_drv_cond_signal(wxe_batch_locker_c);
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
wxWakeUpIdle();
}
- erl_drv_mutex_unlock(wxe_batch_locker_m);
+
}
void meta_command(int what, wxe_data *sd) {
if(what == PING_PORT) {
erl_drv_mutex_lock(wxe_batch_locker_m);
if(wxe_batch_caller > 0) {
- wxeCommand *Cmd = new wxeCommand(WXE_DEBUG_PING, NULL, 0, sd);
- wxe_batch->Append(Cmd);
+ wxe_queue->Add(WXE_DEBUG_PING, NULL, 0, sd);
erl_drv_cond_signal(wxe_batch_locker_c);
}
wxWakeUpIdle();
@@ -121,12 +122,12 @@ bool WxeApp::OnInit()
{
global_me = new wxeMemEnv();
- wxe_batch = new wxList;
- wxe_batch_cb_saved = new wxList;
+ wxe_queue = new wxeFifo(1000);
+ wxe_queue_cb_saved = new wxeFifo(200);
cb_buff = NULL;
recurse_level = 0;
- delayed_cleanup = new wxList;
- delayed_delete = new wxList;
+ delayed_delete = new wxeFifo(10);
+ delayed_cleanup = new wxList;
wxe_ps_init2();
// wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED); // Hmm printpreview doesn't work in 2.9 with this
@@ -169,6 +170,8 @@ void WxeApp::MacOpenFile(const wxString &filename) {
void WxeApp::shutdown(wxeMetaCommand& Ecmd) {
ExitMainLoop();
+ delete wxe_queue;
+ delete wxe_queue_cb_saved;
}
void WxeApp::dummy_close(wxEvent& Ev) {
@@ -201,11 +204,11 @@ void handle_event_callback(ErlDrvPort port, ErlDrvTermData process)
if(driver_monitor_process(port, process, &monitor) == 0) {
// Should we be able to handle commands when recursing? probably
erl_drv_mutex_lock(wxe_batch_locker_m);
- //fprintf(stderr, "\r\nCB EV Start %lu \r\n", process);fflush(stderr);
+ // fprintf(stderr, "\r\nCB EV Start %lu \r\n", process);fflush(stderr);
app->recurse_level++;
- app->dispatch_cb(wxe_batch, wxe_batch_cb_saved, process);
+ app->dispatch_cb(wxe_queue, wxe_queue_cb_saved, process);
app->recurse_level--;
- //fprintf(stderr, "CB EV done %lu \r\n", process);fflush(stderr);
+ // fprintf(stderr, "CB EV done %lu \r\n", process);fflush(stderr);
wxe_batch_caller = 0;
erl_drv_mutex_unlock(wxe_batch_locker_m);
driver_demonitor_process(port, &monitor);
@@ -216,22 +219,22 @@ void WxeApp::dispatch_cmds()
{
erl_drv_mutex_lock(wxe_batch_locker_m);
recurse_level++;
- int level = dispatch(wxe_batch_cb_saved, 0, WXE_STORED);
- dispatch(wxe_batch, level, WXE_NORMAL);
+ int level = dispatch(wxe_queue_cb_saved, 0, WXE_STORED);
+ dispatch(wxe_queue, level, WXE_NORMAL);
recurse_level--;
wxe_batch_caller = 0;
+ if(wxe_queue->m_old) {
+ driver_free(wxe_queue->m_old);
+ wxe_queue->m_old = NULL;
+ }
erl_drv_mutex_unlock(wxe_batch_locker_m);
// Cleanup old memenv's and deleted objects
if(recurse_level == 0) {
- if(delayed_delete->size() > 0)
- for( wxList::compatibility_iterator node = delayed_delete->GetFirst();
- node;
- node = delayed_delete->GetFirst()) {
- wxeCommand *event = (wxeCommand *)node->GetData();
- delayed_delete->Erase(node);
- wxe_dispatch(*event);
- event->Delete();
- }
+ wxeCommand *curr;
+ while((curr = delayed_delete->Get()) != NULL) {
+ wxe_dispatch(*curr);
+ curr->Delete();
+ }
if(delayed_cleanup->size() > 0)
for( wxList::compatibility_iterator node = delayed_cleanup->GetFirst();
node;
@@ -241,158 +244,145 @@ void WxeApp::dispatch_cmds()
destroyMemEnv(*event);
delete event;
}
+ if(wxe_queue_cb_saved->m_old) {
+ driver_free(wxe_queue_cb_saved->m_old);
+ wxe_queue_cb_saved->m_old = NULL;
+ }
+ if(delayed_delete->m_old) {
+ driver_free(delayed_delete->m_old);
+ delayed_delete->m_old = NULL;
+ }
}
}
// Should have erl_drv_mutex_lock(wxe_batch_locker_m);
// when entering this function and it should be released
// afterwards
-int WxeApp::dispatch(wxList * batch, int blevel, int list_type)
+int WxeApp::dispatch(wxeFifo * batch, int blevel, int list_type)
{
int ping = 0;
// erl_drv_mutex_lock(wxe_batch_locker_m); must be locked already
- while(true)
- {
- if (batch->size() > 0) {
- for( wxList::compatibility_iterator node = batch->GetFirst();
- node;
- node = batch->GetFirst())
- {
- wxeCommand *event = (wxeCommand *)node->GetData();
- batch->Erase(node);
- switch(event->op) {
- case WXE_BATCH_END:
- {--blevel; }
- break;
- case WXE_BATCH_BEGIN:
- {blevel++; }
- break;
- case WXE_DEBUG_PING:
- // When in debugger we don't want to hang waiting for a BATCH_END
- // that never comes, because a breakpoint have hit.
- ping++;
- if(ping > 2)
- blevel = 0;
- break;
- case WXE_CB_RETURN:
- // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after
- // whatever cleaning is necessary
- if(event->len > 0) {
- cb_buff = (char *) driver_alloc(event->len);
- memcpy(cb_buff, event->buffer, event->len);
- }
- return blevel;
- default:
- erl_drv_mutex_unlock(wxe_batch_locker_m);
- if(event->op < OPENGL_START) {
- // fprintf(stderr, " c %d (%d) \r\n", event->op, blevel);
- wxe_dispatch(*event);
- } else {
- gl_dispatch(event->op,event->buffer,event->caller,event->bin);
- }
- erl_drv_mutex_lock(wxe_batch_locker_m);
- break;
- }
- event->Delete();
- }
- } else {
- if((list_type == WXE_STORED) || (blevel <= 0 && list_type == WXE_NORMAL)) {
- // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after
- // whatever cleaning is necessary
- return blevel;
+ wxeCommand *event;
+ while(true) {
+ while((event = batch->Get()) != NULL) {
+ switch(event->op) {
+ case -1:
+ break;
+ case WXE_BATCH_END:
+ {--blevel; }
+ break;
+ case WXE_BATCH_BEGIN:
+ {blevel++; }
+ break;
+ case WXE_DEBUG_PING:
+ // When in debugger we don't want to hang waiting for a BATCH_END
+ // that never comes, because a breakpoint have hit.
+ ping++;
+ if(ping > 2)
+ blevel = 0;
+ break;
+ case WXE_CB_RETURN:
+ // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after
+ // whatever cleaning is necessary
+ if(event->len > 0) {
+ cb_buff = (char *) driver_alloc(event->len);
+ memcpy(cb_buff, event->buffer, event->len);
}
- // sleep until something happens
- //fprintf(stderr, "%s:%d sleep %d %d %d %d \r\n", __FILE__, __LINE__, batch->size(), callback_returned, blevel, is_callback);fflush(stderr);
- wxe_batch_caller++;
- while(batch->size() == 0) {
- erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
+ event->Delete();
+ return blevel;
+ default:
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
+ if(event->op < OPENGL_START) {
+ // fprintf(stderr, " c %d (%d) \r\n", event->op, blevel);
+ wxe_dispatch(*event);
+ } else {
+ gl_dispatch(event->op,event->buffer,event->caller,event->bin);
}
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ break;
}
+ event->Delete();
+ }
+ if((list_type == WXE_STORED) || (blevel <= 0 && list_type == WXE_NORMAL)) {
+ // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after
+ // whatever cleaning is necessary
+ return blevel;
}
+ // sleep until something happens
+ //fprintf(stderr, "%s:%d sleep %d %d\r\n", __FILE__, __LINE__, batch->size(), blevel);fflush(stderr);
+ wxe_batch_caller++;
+ while(batch->m_n == 0) {
+ erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
+ }
+ }
}
-void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) {
- int callback_returned = 0;
+void WxeApp::dispatch_cb(wxeFifo * batch, wxeFifo * temp, ErlDrvTermData process) {
+ wxeCommand *event;
while(true) {
- if (batch->size() > 0) {
- for( wxList::compatibility_iterator node = batch->GetFirst();
- node;
- node = batch->GetFirst())
- {
- wxeCommand *event = (wxeCommand *)node->GetData();
- wxeMemEnv *memenv = getMemEnv(event->port);
- batch->Erase(node);
- // fprintf(stderr, " Ev %d %lu\r\n", event->op, event->caller);
- if(event->caller == process || // Callbacks from CB process only
- event->op == WXE_CB_START || // Event callback start change process
- event->op == WXE_CB_DIED || // Event callback process died
- // Allow connect_cb during CB i.e. msg from wxe_server.
- (memenv && event->caller == memenv->owner))
- {
- switch(event->op) {
- case WXE_BATCH_END:
- case WXE_BATCH_BEGIN:
- case WXE_DEBUG_PING:
- break;
- case WXE_CB_RETURN:
- if(event->len > 0) {
- cb_buff = (char *) driver_alloc(event->len);
- memcpy(cb_buff, event->buffer, event->len);
- } // continue
- case WXE_CB_DIED:
- callback_returned = 1;
- return;
- case WXE_CB_START:
- // CB start from now accept message from CB process only
- process = event->caller;
- break;
- default:
- erl_drv_mutex_unlock(wxe_batch_locker_m);
- size_t start=temp->GetCount();
- if(event->op < OPENGL_START) {
- // fprintf(stderr, " cb %d \r\n", event->op);
- wxe_dispatch(*event);
- } else {
- gl_dispatch(event->op,event->buffer,event->caller,event->bin);
- }
- erl_drv_mutex_lock(wxe_batch_locker_m);
- if(temp->GetCount() > start) {
- // We have recursed dispatch_cb and messages for this
- // callback may be saved on temp list move them
- // to orig list
- for(wxList::compatibility_iterator node = temp->Item(start);
- node;
- node = node->GetNext()) {
- wxeCommand *ev = (wxeCommand *)node->GetData();
- if(ev->caller == process) {
- batch->Append(ev);
- temp->Erase(node);
- }
- }
- }
- if(callback_returned)
- return;
- break;
+ while((event = batch->Get()) != NULL) {
+ wxeMemEnv *memenv = getMemEnv(event->port);
+ // fprintf(stderr, " Ev %d %lu\r\n", event->op, event->caller);
+ if(event->caller == process || // Callbacks from CB process only
+ event->op == WXE_CB_START || // Event callback start change process
+ event->op == WXE_CB_DIED || // Event callback process died
+ // Allow connect_cb during CB i.e. msg from wxe_server.
+ (memenv && event->caller == memenv->owner)) {
+ switch(event->op) {
+ case -1:
+ case WXE_BATCH_END:
+ case WXE_BATCH_BEGIN:
+ case WXE_DEBUG_PING:
+ break;
+ case WXE_CB_RETURN:
+ if(event->len > 0) {
+ cb_buff = (char *) driver_alloc(event->len);
+ memcpy(cb_buff, event->buffer, event->len);
+ } // continue
+ case WXE_CB_DIED:
+ event->Delete();
+ return;
+ case WXE_CB_START:
+ // CB start from now accept message from CB process only
+ process = event->caller;
+ break;
+ default:
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
+ size_t start=temp->m_n;
+ if(event->op < OPENGL_START) {
+ // fprintf(stderr, " cb %d \r\n", event->op);
+ wxe_dispatch(*event);
+ } else {
+ gl_dispatch(event->op,event->buffer,event->caller,event->bin);
+ }
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ if(temp->m_n > start) {
+ // We have recursed dispatch_cb and messages for this
+ // callback may be saved on temp list move them
+ // to orig list
+ for(unsigned int i=start; i < temp->m_n; i++) {
+ wxeCommand *ev = &temp->m_q[(temp->m_first+i) % temp->m_max];
+ if(ev->caller == process) {
+ batch->Append(ev);
}
- event->Delete();
- } else {
- // fprintf(stderr, " save %d \r\n", event->op);
- temp->Append(event);
+ }
}
+ break;
}
- } else {
- if(callback_returned) {
- return;
- }
- // sleep until something happens
- //fprintf(stderr, "%s:%d sleep %d %d %d %d \r\n", __FILE__, __LINE__, batch->size(), callback_returned, blevel, is_callback);fflush(stderr);
- while(batch->size() == 0) {
- erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
+ event->Delete();
+ } else {
+ // fprintf(stderr, " save %d %lu\r\n", event->op, event->caller);
+ temp->Append(event);
}
}
+ // sleep until something happens
+ // fprintf(stderr, "%s:%d sleep %d %d\r\n", __FILE__, __LINE__,
+ // batch->m_n, temp->m_n);fflush(stderr);
+ while(batch->m_n == 0) {
+ erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
+ }
}
}
-
/* Memory handling */
void WxeApp::newMemEnv(wxeMetaCommand& Ecmd) {
diff --git a/lib/wx/c_src/wxe_impl.h b/lib/wx/c_src/wxe_impl.h
index 57bf2e2dba..a0a1c84718 100644
--- a/lib/wx/c_src/wxe_impl.h
+++ b/lib/wx/c_src/wxe_impl.h
@@ -60,8 +60,8 @@ public:
#endif
void shutdown(wxeMetaCommand& event);
- int dispatch(wxList *, int, int);
- void dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process);
+ int dispatch(wxeFifo *, int, int);
+ void dispatch_cb(wxeFifo * batch, wxeFifo * temp, ErlDrvTermData process);
void wxe_dispatch(wxeCommand& event);
@@ -93,7 +93,7 @@ public:
int recurse_level;
wxList * delayed_cleanup;
- wxList * delayed_delete;
+ wxeFifo * delayed_delete;
// Temp container for callbacks
char *cb_buff;
int cb_len;
diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl
index 3252547c9b..6bcd88e4fb 100644
--- a/lib/wx/test/wx_event_SUITE.erl
+++ b/lib/wx/test/wx_event_SUITE.erl
@@ -379,25 +379,29 @@ recursive(Config) ->
Frame = wxFrame:new(Wx, ?wxID_ANY, "Connect in callback"),
Panel = wxPanel:new(Frame, []),
Sz = wxBoxSizer:new(?wxVERTICAL),
- ListBox = wxListBox:new(Panel, ?wxID_ANY, [{choices, ["foo", "bar", "baz"]}]),
- wxSizer:add(Sz, ListBox, [{proportion, 1},{flag, ?wxEXPAND}]),
- wxWindow:setSizer(Panel, Sz),
- wxListBox:connect(ListBox, command_listbox_selected,
- [{callback,
- fun(#wx{event=#wxCommand{commandInt=Id}}, _) ->
- io:format("Selected ~p~n",[Id])
- end}]),
- wxListBox:setSelection(ListBox, 0),
- wxListBox:connect(ListBox, size,
- [{callback,
- fun(#wx{event=#wxSize{}}, _) ->
- io:format("Size init ~n",[]),
- case wxListBox:getCount(ListBox) > 0 of
- true -> wxListBox:delete(ListBox, 0);
- false -> ok
- end,
- io:format("Size done ~n",[])
- end}]),
+ Ctrl1 = wxTextCtrl:new(Panel, ?wxID_ANY, [{size, {300, -1}}]),
+ Ctrl2 = wxTextCtrl:new(Panel, ?wxID_ANY, [{size, {300, -1}}]),
+ wxSizer:add(Sz, Ctrl1, [{proportion, 1},{flag, ?wxEXPAND}]),
+ wxSizer:add(Sz, Ctrl2, [{proportion, 1},{flag, ?wxEXPAND}]),
+ wxWindow:setSizerAndFit(Panel, Sz),
+
+ CB1 = fun(#wx{event=#wxCommand{cmdString=String}}, _) ->
+ io:format(" CB1: ~s~n",[String]),
+ wxTextCtrl:setValue(Ctrl2, io_lib:format("from CB1 ~s", [String]))
+ end,
+ CB2 = fun(#wx{event=#wxCommand{cmdString=String}}, _) ->
+ io:format(" CB2: ~s~n",[String]),
+ ok
+ end,
+ wxTextCtrl:connect(Ctrl1, command_text_updated, [{callback,CB1}]),
+ wxTextCtrl:connect(Ctrl2, command_text_updated, [{callback,CB2}]),
+ wxFrame:connect(Frame, size,
+ [{callback,
+ fun(#wx{event=#wxSize{size=Size}}, _) ->
+ io:format("Size init: ~s ~n",[wxTextCtrl:getValue(Ctrl2)]),
+ wxTextCtrl:setValue(Ctrl1, io_lib:format("Size ~p", [Size])),
+ io:format("Size done: ~s ~n",[wxTextCtrl:getValue(Ctrl2)])
+ end}]),
wxFrame:show(Frame),
wx_test_lib:flush(),