This is a suggested change. It is complete except for documentation.

I did not like the awake_cb system at all. These changes implement Fl::awake(Fl_Awake_Handler, void*) which is called from a thread and tells the main loop to call the specified handler (rather a callback I guess) as soon as possible from within the main thread. It is implemented as Fifo (currently 1024 entry ring buffer), so handlers are called in the order that they are generated in.

"test/threads" was modified to change the label color as soon as a thread reaches 10000 - pretty boring, but it show the wonderful simplicity of this approach: you can write libraries that don't need to add to the main loop or register a handler at all... .

I will do some more stress testing tonight.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@5729 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Matthias Melcher 2007-03-06 17:15:03 +00:00
parent 6df72e8979
commit 11a15d83a2
4 changed files with 91 additions and 0 deletions

10
FL/Fl.H
View File

@ -46,6 +46,7 @@ typedef void (Fl_Label_Measure_F)(const Fl_Label*, int&, int&);
typedef void (Fl_Box_Draw_F)(int,int,int,int, Fl_Color); typedef void (Fl_Box_Draw_F)(int,int,int,int, Fl_Color);
typedef void (*Fl_Timeout_Handler)(void*); typedef void (*Fl_Timeout_Handler)(void*);
typedef void (*Fl_Awake_Handler)(void*);
class FL_EXPORT Fl { class FL_EXPORT Fl {
Fl() {}; // no constructor! Fl() {}; // no constructor!
@ -79,6 +80,14 @@ public: // should be private!
static void (*idle)(); static void (*idle)();
static void (*awake_cb)(void *); static void (*awake_cb)(void *);
static Fl_Awake_Handler *awake_ring_;
static void **awake_data_;
static int awake_ring_size_;
static int awake_ring_head_;
static int awake_ring_tail_;
static int add_awake_handler_(Fl_Awake_Handler, void*);
static int get_awake_handler_(Fl_Awake_Handler&, void*&);
static const char* scheme_; static const char* scheme_;
static Fl_Image* scheme_bg_; static Fl_Image* scheme_bg_;
@ -267,6 +276,7 @@ public:
static void lock(); static void lock();
static void unlock(); static void unlock();
static void awake(void* message = 0); static void awake(void* message = 0);
static int awake(Fl_Awake_Handler cb, void* message = 0);
static void set_awake_cb(void (*cb)(void *)) { awake_cb = cb; } static void set_awake_cb(void (*cb)(void *)) { awake_cb = cb; }
static void* thread_message(); static void* thread_message();

View File

@ -29,6 +29,8 @@
#include <FL/Fl.H> #include <FL/Fl.H>
#include <config.h> #include <config.h>
#include <stdlib.h>
/* /*
From Bill: From Bill:
@ -68,6 +70,62 @@
void (*Fl::awake_cb)(void *); void (*Fl::awake_cb)(void *);
Fl_Awake_Handler *Fl::awake_ring_;
void **Fl::awake_data_;
int Fl::awake_ring_size_;
int Fl::awake_ring_head_;
int Fl::awake_ring_tail_;
const int AWAKE_RING_SIZE = 1024;
int Fl::add_awake_handler_(Fl_Awake_Handler func, void *data)
{
int ret = 0;
Fl::lock();
if (!awake_ring_) {
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*));
}
if (awake_ring_head_==awake_ring_tail_-1 || awake_ring_head_+1==awake_ring_tail_) {
// ring is full. Return -1 as ann 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;
}
Fl::unlock();
return ret;
}
int Fl::get_awake_handler_(Fl_Awake_Handler &func, void *&data)
{
// this function must only be called from within the event
// loop which is locked, so don't bother creating any locks
if (!awake_ring_)
return -1;
if (awake_ring_head_ == awake_ring_tail_)
return -1;
func = awake_ring_[awake_ring_tail_];
data = awake_data_[awake_ring_tail_];
++awake_ring_tail_;
if (awake_ring_tail_ == awake_ring_size_)
awake_ring_tail_ = 0;
return 0;
}
//
// 'Fl::awake()' - Let the main thread know an update is pending
// and have it cal a specific function
//
int Fl::awake(Fl_Awake_Handler func, void *data) {
int ret = add_awake_handler_(func, data);
Fl::awake();
return ret;
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Windows threading... // Windows threading...
#ifdef WIN32 #ifdef WIN32
@ -203,6 +261,11 @@ void* Fl::thread_message() {
static void thread_awake_cb(int fd, void*) { static void thread_awake_cb(int fd, void*) {
read(fd, &thread_message_, sizeof(void*)); read(fd, &thread_message_, sizeof(void*));
if (Fl::awake_cb) (*Fl::awake_cb)(thread_message_); if (Fl::awake_cb) (*Fl::awake_cb)(thread_message_);
Fl_Awake_Handler *func;
void *data;
while (Fl::get_awake_handler_(func, data)==0) {
(*func)(data);
}
} }
// These pointers are in Fl_x.cxx: // These pointers are in Fl_x.cxx:

View File

@ -300,6 +300,11 @@ int fl_wait(double time_to_wait) {
// Used for awaking wait() from another thread // Used for awaking wait() from another thread
thread_message_ = (void*)fl_msg.wParam; thread_message_ = (void*)fl_msg.wParam;
if (Fl::awake_cb) (*Fl::awake_cb)(thread_message_); if (Fl::awake_cb) (*Fl::awake_cb)(thread_message_);
Fl_Awake_Handler func;
void *data;
while (Fl::get_awake_handler_(func, data)==0) {
func(data);
}
} }
TranslateMessage(&fl_msg); TranslateMessage(&fl_msg);

View File

@ -32,6 +32,7 @@
# include <FL/Fl_Window.H> # include <FL/Fl_Window.H>
# include <FL/Fl_Browser.H> # include <FL/Fl_Browser.H>
# include <FL/Fl_Value_Output.H> # include <FL/Fl_Value_Output.H>
# include <FL/fl_ask.h>
# include "threads.h" # include "threads.h"
# include <stdio.h> # include <stdio.h>
# include <math.h> # include <math.h>
@ -42,12 +43,20 @@ Fl_Browser *browser1, *browser2;
Fl_Value_Output *value1, *value2; Fl_Value_Output *value1, *value2;
int start2 = 3; int start2 = 3;
void magic_number_cb(void *p)
{
Fl_Value_Output *w = (Fl_Value_Output*)p;
w->labelcolor(FL_RED);
w->redraw_label();
}
void* prime_func(void* p) void* prime_func(void* p)
{ {
Fl_Browser* browser = (Fl_Browser*) p; Fl_Browser* browser = (Fl_Browser*) p;
Fl_Value_Output *value; Fl_Value_Output *value;
int n; int n;
int step; int step;
char proud = 0;
if (browser == browser2) { if (browser == browser2) {
n = start2; n = start2;
@ -86,6 +95,10 @@ void* prime_func(void* p)
// message we pass here isn't used for anything, so we could also // message we pass here isn't used for anything, so we could also
// just pass NULL. // just pass NULL.
Fl::awake(p); Fl::awake(p);
if (n>10000 && !proud) {
proud = 1;
Fl::awake(magic_number_cb, value);
}
} else { } else {
// This should not be necessary since "n" and "step" are local variables, // This should not be necessary since "n" and "step" are local variables,
// however it appears that at least MacOS X has some threading issues // however it appears that at least MacOS X has some threading issues