summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Fl_lock.cxx27
-rw-r--r--src/Fl_win32.cxx42
2 files changed, 55 insertions, 14 deletions
diff --git a/src/Fl_lock.cxx b/src/Fl_lock.cxx
index 918f24413..bef9d972d 100644
--- a/src/Fl_lock.cxx
+++ b/src/Fl_lock.cxx
@@ -3,7 +3,7 @@
//
// Multi-threading support code for the Fast Light Tool Kit (FLTK).
//
-// Copyright 1998-2010 by Bill Spitzak and others.
+// Copyright 1998-2015 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -70,7 +70,6 @@ static const int AWAKE_RING_SIZE = 1024;
static void lock_ring();
static void unlock_ring();
-
/** Adds an awake handler for use in awake(). */
int Fl::add_awake_handler_(Fl_Awake_Handler func, void *data)
{
@@ -80,33 +79,43 @@ int Fl::add_awake_handler_(Fl_Awake_Handler func, void *data)
awake_ring_size_ = AWAKE_RING_SIZE;
awake_ring_ = (Fl_Awake_Handler*)malloc(awake_ring_size_*sizeof(Fl_Awake_Handler));
awake_data_ = (void**)malloc(awake_ring_size_*sizeof(void*));
+ // explicitly initialize the head and tail indices
+ awake_ring_head_= awake_ring_tail_ = 0;
+ }
+ // The next head index we will want (not the current index):
+ // We use this to check if the ring-buffer is full or not
+ // (and to update awake_ring_head_ if we do use the current index.)
+ int next_head = awake_ring_head_ + 1;
+ if (next_head >= awake_ring_size_) {
+ next_head = 0;
}
- if (awake_ring_head_==awake_ring_tail_-1 || awake_ring_head_+1==awake_ring_tail_) {
- // ring is full. Return -1 as an error indicator.
+ // check that the ring buffer is not full, and that it exists
+ if ((!awake_ring_) || (next_head == awake_ring_tail_)) {
+ // ring is non-existent or full. Return -1 as an error indicator.
ret = -1;
} else {
awake_ring_[awake_ring_head_] = func;
awake_data_[awake_ring_head_] = data;
- ++awake_ring_head_;
- if (awake_ring_head_ == awake_ring_size_)
- awake_ring_head_ = 0;
+ awake_ring_head_ = next_head;
}
unlock_ring();
return ret;
}
+
/** Gets the last stored awake handler for use in awake(). */
int Fl::get_awake_handler_(Fl_Awake_Handler &func, void *&data)
{
int ret = 0;
lock_ring();
- if (!awake_ring_ || awake_ring_head_ == awake_ring_tail_) {
+ if ((!awake_ring_) || (awake_ring_head_ == awake_ring_tail_)) {
ret = -1;
} else {
func = awake_ring_[awake_ring_tail_];
data = awake_data_[awake_ring_tail_];
++awake_ring_tail_;
- if (awake_ring_tail_ == awake_ring_size_)
+ if (awake_ring_tail_ >= awake_ring_size_) {
awake_ring_tail_ = 0;
+ }
}
unlock_ring();
return ret;
diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx
index 378ef168d..0bcd2e102 100644
--- a/src/Fl_win32.cxx
+++ b/src/Fl_win32.cxx
@@ -3,7 +3,7 @@
//
// WIN32-specific code for the Fast Light Tool Kit (FLTK).
//
-// Copyright 1998-2012 by Bill Spitzak and others.
+// Copyright 1998-2015 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -350,6 +350,16 @@ extern int fl_send_system_handlers(void *e);
MSG fl_msg;
+// A local helper function to flush any pending callback requests
+// from the awake ring-buffer
+static void process_awake_handler_requests(void) {
+ Fl_Awake_Handler func;
+ void *data;
+ while (Fl::get_awake_handler_(func, data) == 0) {
+ func(data);
+ }
+}
+
// This is never called with time_to_wait < 0.0.
// It *should* return negative on error, 0 if nothing happens before
// timeout, and >0 if any callbacks were done. This version only
@@ -423,15 +433,37 @@ int fl_wait(double time_to_wait) {
if (fl_msg.message == fl_wake_msg) {
// Used for awaking wait() from another thread
thread_message_ = (void*)fl_msg.wParam;
- Fl_Awake_Handler func;
- void *data;
- while (Fl::get_awake_handler_(func, data)==0)
- func(data);
+ process_awake_handler_requests();
}
TranslateMessage(&fl_msg);
DispatchMessageW(&fl_msg);
}
+
+ // The following conditional test:
+ // (Fl::awake_ring_head_ != Fl::awake_ring_tail_)
+ // is a workaround / fix for STR #3143. This works, but a better solution
+ // would be to understand why the PostThreadMessage() messages are not
+ // seen by the main window if it is being dragged/ resized at the time.
+ // If a worker thread posts an awake callback to the ring buffer
+ // whilst the main window is unresponsive (if a drag or resize operation
+ // is in progress) we may miss the PostThreadMessage(). So here, we check if
+ // there is anything pending in the awake ring buffer and if so process
+ // it. This is not strictly thread safe (for speed it compares the head
+ // and tail indices without first locking the ring buffer) but is intended
+ // only as a fall-back recovery mechanism if the awake processing stalls.
+ // If the test erroneously returns true (may happen if we test the indices
+ // whilst they are being modified) we will call process_awake_handler_requests()
+ // unnecessarily, but this has no harmful consequences so is safe to do.
+ // Note also that if we miss the PostThreadMessage(), then thread_message_
+ // will not be updated, so this is not a perfect solution, but it does
+ // recover and process any pending awake callbacks.
+ // Normally the ring buffer head and tail indices will match and this
+ // comparison will do nothing. Addresses STR #3143
+ if (Fl::awake_ring_head_ != Fl::awake_ring_tail_) {
+ process_awake_handler_requests();
+ }
+
Fl::flush();
// This should return 0 if only timer events were handled: