changeset 90:b90ce8ec9c44

Fixed a bug in go_event_close() and added thread/event pages to the test programs, ported from the C version.
author Brian Smith <brian@dbsoft.org>
date Thu, 26 Sep 2013 03:55:04 -0500
parents 90e3c9c7ac73
children d982501fe83d
files src/dw/dwglue.c src/dwootest/dwootest.go src/dwtest/dwtest.go
diffstat 3 files changed, 302 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/dw/dwglue.c	Thu Sep 26 01:50:58 2013 -0500
+++ b/src/dw/dwglue.c	Thu Sep 26 03:55:04 2013 -0500
@@ -1133,22 +1133,23 @@
 
 static int go_event_close(void *event)
 {
-    return dw_event_close((HMTX)event);
+    HEV thisevent = (HEV)event;
+    return dw_event_close(&thisevent);
 }
 
 static int go_event_post(void *event)
 {
-    return dw_event_post((HMTX)event);
+    return dw_event_post((HEV)event);
 }
 
 static int go_event_reset(void *event)
 {
-    return dw_event_reset((HMTX)event);
+    return dw_event_reset((HEV)event);
 }
 
 static int go_event_wait(void *event, unsigned long timeout)
 {
-    return dw_event_wait((HMTX)event, timeout);
+    return dw_event_wait((HEV)event, timeout);
 }
 
 extern int go_int_callback_basic(void *pfunc, void* window, void *data, unsigned int flags);
--- a/src/dwootest/dwootest.go	Thu Sep 26 01:50:58 2013 -0500
+++ b/src/dwootest/dwootest.go	Thu Sep 26 03:55:04 2013 -0500
@@ -46,6 +46,15 @@
 // Page 8
 var MAX_WIDGETS = 20
 
+// Page 9
+var threadmle dw.HMLE
+var startbutton dw.HBUTTON
+var mutex dw.HMTX;
+var workevent, controlevent dw.HEV
+var finished = 0
+var ready = 0
+var mlepos = 0
+
 // Miscellaneous
 var fileicon, foldericon dw.HICN
 var current_file string
@@ -1082,6 +1091,138 @@
     }
 }
 
+// Page 9
+func update_mle(text string, lock int) {
+    /* Protect pos from being changed by different threads */
+    if(lock != 0) {
+        mutex.Lock();
+    }
+    mlepos = threadmle.Import(text, mlepos);
+    threadmle.SetCursor(mlepos);
+    if(lock != 0) {
+        mutex.Unlock();
+    }
+}
+
+func thread_add(notebookbox9 dw.HBOX) {
+    /* create a box to pack into the notebook page */
+    tmpbox := dw.BoxNew(dw.VERT, 0);
+    notebookbox9.PackStart(tmpbox, 0, 0, dw.TRUE, dw.TRUE, 1);
+
+    startbutton := dw.ButtonNew("Start Threads", 0);
+    tmpbox.PackStart(startbutton, -1, 30, dw.FALSE, dw.FALSE, 0);
+    /* Create the base threading components */
+    threadmle = dw.MLENew(0);
+    tmpbox.PackStart(threadmle, 1, 1, dw.TRUE, dw.TRUE, 0);
+    mutex = dw.MutexNew();
+    workevent = dw.EventNew();
+    /* Connect signal handlers */
+    startbutton.ConnectClicked(func(window dw.HBUTTON) int {
+        startbutton.Disable();
+        mutex.Lock();
+        controlevent = dw.EventNew();
+        workevent.Reset();
+        finished = dw.FALSE;
+        ready = 0;
+        update_mle("Starting thread 1\r\n", dw.FALSE);
+        go run_thread(1);
+        update_mle("Starting thread 2\r\n", dw.FALSE);
+        go run_thread(2);
+        update_mle("Starting thread 3\r\n", dw.FALSE);
+        go run_thread(3);
+        update_mle("Starting thread 4\r\n", dw.FALSE);
+        go run_thread(4);
+        update_mle("Starting control thread\r\n", dw.FALSE);
+        go control_thread();
+        mutex.Unlock();
+        return dw.FALSE;
+    });
+
+}
+
+func run_thread(threadnum int) {
+    dw.InitThread();
+    update_mle(fmt.Sprintf("Thread %d started.\r\n", threadnum), dw.TRUE);
+
+    /* Increment the ready count while protected by mutex */
+    mutex.Lock();
+    ready++;
+    /* If all 4 threads have incrememted the ready count...
+     * Post the control event semaphore so things will get started.
+     */
+    if(ready == 4) {
+        controlevent.Post();
+    }
+    mutex.Unlock();
+
+    for finished == 0 {
+        result := workevent.Wait(2000);
+
+        if(result == dw.ERROR_TIMEOUT) {
+            update_mle(fmt.Sprintf("Thread %d timeout waiting for event.\r\n", threadnum), dw.TRUE);
+        } else if(result == dw.ERROR_NONE) {
+            update_mle(fmt.Sprintf("Thread %d doing some work.\r\n", threadnum), dw.TRUE);
+            /* Pretend to do some work */
+            dw.MainSleep(1000 * threadnum);
+
+            /* Increment the ready count while protected by mutex */
+            mutex.Lock();
+            ready++;
+            buf := fmt.Sprintf("Thread %d work done. ready=%d", threadnum, ready);
+            /* If all 4 threads have incrememted the ready count...
+            * Post the control event semaphore so things will get started.
+            */
+            if(ready == 4) {
+                controlevent.Post();
+                buf = fmt.Sprintf("%s%s", buf, " Control posted.");
+            }
+            mutex.Unlock();
+            update_mle(fmt.Sprintf("%s\r\n", buf), dw.TRUE);
+        } else {
+            update_mle(fmt.Sprintf("Thread %d error %d.\r\n", threadnum), dw.TRUE);
+            dw.MainSleep(10000);
+        }
+    }
+    update_mle(fmt.Sprintf("Thread %d finished.\r\n", threadnum), dw.TRUE);
+    dw.DeinitThread();
+}
+
+func control_thread() {
+    dw.InitThread();
+    
+    inprogress := 5;
+
+    for inprogress != 0 {
+        result := controlevent.Wait(2000);
+
+        if(result == dw.ERROR_TIMEOUT) {
+            update_mle("Control thread timeout waiting for event.\r\n", dw.TRUE);
+        } else if(result == dw.ERROR_NONE) {
+            /* Reset the control event */
+            controlevent.Reset();
+            ready = 0;
+            update_mle(fmt.Sprintf("Control thread starting worker threads. Inprogress=%d\r\n", inprogress), dw.TRUE);
+            /* Start the work threads */
+            workevent.Post();
+            dw.MainSleep(100);
+            /* Reset the work event */
+            workevent.Reset();
+            inprogress--;
+        } else {
+            update_mle(fmt.Sprintf("Control thread error %d.\r\n", result), dw.TRUE);
+            dw.MainSleep(10000);
+        }
+    }
+    /* Tell the other threads we are done */
+    finished = dw.TRUE;
+    workevent.Post();
+    /* Close the control event */
+    controlevent.Close();
+    update_mle("Control thread finished.\r\n", dw.TRUE);
+    startbutton.Enable();
+    dw.DeinitThread();
+}
+
 func main() {
    /* Pick an approriate font for our platform */
    if runtime.GOOS == "windows" {
@@ -1183,6 +1324,12 @@
    notebookpage8.SetText("scrollbox");
    scrollbox_add(notebookbox8);
 
+   notebookbox9 := dw.BoxNew(dw.VERT, 8);
+   notebookpage9 := notebook.PageNew(1, dw.FALSE);
+   notebookpage9.Pack(notebookbox9);
+   notebookpage9.SetText("thread/event");
+   thread_add(notebookbox9);
+
    mainwindow.ConnectDelete(func(window dw.HWND) int { return exit_handler(); });
    /*
    * The following is a special case handler for the Mac and other platforms which contain
--- a/src/dwtest/dwtest.go	Thu Sep 26 01:50:58 2013 -0500
+++ b/src/dwtest/dwtest.go	Thu Sep 26 03:55:04 2013 -0500
@@ -81,6 +81,15 @@
 
 var iteration = 0;
 
+// Page 9
+var notebookbox9 dw.HBOX
+var threadmle dw.HMLE
+var startbutton dw.HBUTTON
+var mutex dw.HMTX;
+var workevent, controlevent dw.HEV
+var finished = 0
+var ready = 0
+var mlepos = 0
 
 // Miscellaneous
 var fileicon, foldericon dw.HICN
@@ -790,6 +799,111 @@
     return FALSE;
 }
 
+// Page 9 Callbacks
+func run_thread(threadnum int) {
+    dw.InitThread();
+    update_mle(fmt.Sprintf("Thread %d started.\r\n", threadnum), TRUE);
+
+    /* Increment the ready count while protected by mutex */
+    dw.Mutex_lock(mutex);
+    ready++;
+    /* If all 4 threads have incrememted the ready count...
+     * Post the control event semaphore so things will get started.
+     */
+    if(ready == 4) {
+        dw.Event_post(controlevent);
+    }
+    dw.Mutex_unlock(mutex);
+
+    for finished == 0 {
+        result := dw.Event_wait(workevent, 2000);
+
+        if(result == dw.ERROR_TIMEOUT) {
+            update_mle(fmt.Sprintf("Thread %d timeout waiting for event.\r\n", threadnum), dw.TRUE);
+        } else if(result == dw.ERROR_NONE) {
+            update_mle(fmt.Sprintf("Thread %d doing some work.\r\n", threadnum), dw.TRUE);
+            /* Pretend to do some work */
+            dw.Main_sleep(1000 * threadnum);
+
+            /* Increment the ready count while protected by mutex */
+            dw.Mutex_lock(mutex);
+            ready++;
+            buf := fmt.Sprintf("Thread %d work done. ready=%d", threadnum, ready);
+            /* If all 4 threads have incrememted the ready count...
+            * Post the control event semaphore so things will get started.
+            */
+            if(ready == 4) {
+                dw.Event_post(controlevent);
+                buf = fmt.Sprintf("%s%s", buf, " Control posted.");
+            }
+            dw.Mutex_unlock(mutex);
+            update_mle(fmt.Sprintf("%s\r\n", buf), dw.TRUE);
+        } else {
+            update_mle(fmt.Sprintf("Thread %d error %d.\r\n", threadnum), dw.TRUE);
+            dw.Main_sleep(10000);
+        }
+    }
+    update_mle(fmt.Sprintf("Thread %d finished.\r\n", threadnum), dw.TRUE);
+    dw.DeinitThread();
+}
+
+func control_thread() {
+    dw.InitThread();
+    
+    inprogress := 5;
+
+    for inprogress != 0 {
+        result := dw.Event_wait(controlevent, 2000);
+
+        if(result == dw.ERROR_TIMEOUT) {
+            update_mle("Control thread timeout waiting for event.\r\n", dw.TRUE);
+        } else if(result == dw.ERROR_NONE) {
+            /* Reset the control event */
+            dw.Event_reset(controlevent);
+            ready = 0;
+            update_mle(fmt.Sprintf("Control thread starting worker threads. Inprogress=%d\r\n", inprogress), dw.TRUE);
+            /* Start the work threads */
+            dw.Event_post(workevent);
+            dw.Main_sleep(100);
+            /* Reset the work event */
+            dw.Event_reset(workevent);
+            inprogress--;
+        } else {
+            update_mle(fmt.Sprintf("Control thread error %d.\r\n", result), dw.TRUE);
+            dw.Main_sleep(10000);
+        }
+    }
+    /* Tell the other threads we are done */
+    finished = dw.TRUE;
+    dw.Event_post(workevent);
+    /* Close the control event */
+    dw.Event_close(controlevent);
+    update_mle("Control thread finished.\r\n", dw.TRUE);
+    dw.Window_enable(startbutton);
+    dw.DeinitThread();
+}
+
+func start_threads_button_callback(window dw.HWND, data dw.POINTER) int {
+    dw.Window_disable(startbutton);
+    dw.Mutex_lock(mutex);
+    controlevent = dw.Event_new();
+    dw.Event_reset(workevent);
+    finished = FALSE;
+    ready = 0;
+    update_mle("Starting thread 1\r\n", FALSE);
+    go run_thread(1);
+    update_mle("Starting thread 2\r\n", FALSE);
+    go run_thread(2);
+    update_mle("Starting thread 3\r\n", FALSE);
+    go run_thread(3);
+    update_mle("Starting thread 4\r\n", FALSE);
+    go run_thread(4);
+    update_mle("Starting control thread\r\n", FALSE);
+    go control_thread();
+    dw.Mutex_unlock(mutex);
+    return FALSE;
+}
+
 var exit_callback_func = exit_callback;
 var copy_clicked_callback_func = copy_clicked_callback;
 var paste_clicked_callback_func = paste_clicked_callback;
@@ -829,6 +943,7 @@
 var slider_valuechanged_callback_func = slider_valuechanged_callback;
 var print_callback_func = print_callback;
 var draw_page_func = draw_page;
+var start_threads_button_callback_func = start_threads_button_callback;
 
 var checkable_string = "checkable";
 var noncheckable_string = "non-checkable";
@@ -1312,6 +1427,35 @@
     }
 }
 
+// Page 9
+func update_mle(text string, lock int) {
+    /* Protect pos from being changed by different threads */
+    if(lock != 0) {
+        dw.Mutex_lock(mutex);
+    }
+    mlepos = dw.Mle_import(threadmle, text, mlepos);
+    dw.Mle_set_cursor(threadmle, mlepos);
+    if(lock != 0) {
+        dw.Mutex_unlock(mutex);
+    }
+}
+
+func thread_add() {
+    /* create a box to pack into the notebook page */
+    tmpbox := dw.Box_new(dw.VERT, 0);
+    dw.Box_pack_start(notebookbox9, tmpbox, 0, 0, dw.TRUE, dw.TRUE, 1);
+
+    startbutton = dw.Button_new("Start Threads", 0);
+    dw.Box_pack_start(tmpbox, startbutton, -1, 30, dw.FALSE, dw.FALSE, 0);
+    dw.Signal_connect(startbutton, dw.SIGNAL_CLICKED, dw.SIGNAL_FUNC(&start_threads_button_callback_func), nil);
+
+    /* Create the base threading components */
+    threadmle = dw.Mle_new(0);
+    dw.Box_pack_start(tmpbox, threadmle, 1, 1, TRUE, TRUE, 0);
+    mutex = dw.Mutex_new();
+    workevent = dw.Event_new();
+}
+
 func main() {
    /* Pick an approriate font for our platform */
    if runtime.GOOS == "windows" {
@@ -1410,6 +1554,12 @@
    dw.Notebook_page_set_text(notebook, notebookpage8, "scrollbox");
    scrollbox_add();
 
+   notebookbox9 = dw.Box_new(dw.VERT, 8);
+   notebookpage9 := dw.Notebook_page_new(notebook, 1, FALSE);
+   dw.Notebook_pack(notebook, notebookpage9, notebookbox9);
+   dw.Notebook_page_set_text(notebook, notebookpage9, "thread/event");
+   thread_add();
+    
    /* Set the default field */
    dw.Window_default(mainwindow, copypastefield);