|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: Fl_lock.cxx 7903 2010-11-28 21:06:39Z matt $" 00003 // 00004 // Multi-threading support code for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 00029 #include <FL/Fl.H> 00030 #include <config.h> 00031 00032 #include <stdlib.h> 00033 00034 /* 00035 From Bill: 00036 00037 I would prefer that FLTK contain the minimal amount of extra 00038 stuff for doing threads. There are other portable thread 00039 wrapper libraries out there and FLTK should not be providing 00040 another. This file is an attempt to make minimal additions 00041 and make them self-contained in this source file. 00042 00043 From Mike: 00044 00045 Starting with 1.1.8, we now have a callback so that you can 00046 process awake() messages as they come in. 00047 00048 00049 The API: 00050 00051 Fl::lock() - recursive lock. You must call this before the 00052 first call to Fl::wait()/run() to initialize the thread 00053 system. The lock is locked all the time except when 00054 Fl::wait() is waiting for events. 00055 00056 Fl::unlock() - release the recursive lock. 00057 00058 Fl::awake(void*) - Causes Fl::wait() to return (with the lock 00059 locked) even if there are no events ready. 00060 00061 Fl::awake(void (*cb)(void *), void*) - Call a function 00062 in the main thread from within another thread of execution. 00063 00064 Fl::thread_message() - returns an argument sent to an 00065 Fl::awake() call, or returns NULL if none. WARNING: the 00066 current implementation only has a one-entry queue and only 00067 returns the most recent value! 00068 */ 00069 00070 #ifndef FL_DOXYGEN 00071 Fl_Awake_Handler *Fl::awake_ring_; 00072 void **Fl::awake_data_; 00073 int Fl::awake_ring_size_; 00074 int Fl::awake_ring_head_; 00075 int Fl::awake_ring_tail_; 00076 #endif 00077 00078 static const int AWAKE_RING_SIZE = 1024; 00079 static void lock_ring(); 00080 static void unlock_ring(); 00081 00082 00084 int Fl::add_awake_handler_(Fl_Awake_Handler func, void *data) 00085 { 00086 int ret = 0; 00087 lock_ring(); 00088 if (!awake_ring_) { 00089 awake_ring_size_ = AWAKE_RING_SIZE; 00090 awake_ring_ = (Fl_Awake_Handler*)malloc(awake_ring_size_*sizeof(Fl_Awake_Handler)); 00091 awake_data_ = (void**)malloc(awake_ring_size_*sizeof(void*)); 00092 } 00093 if (awake_ring_head_==awake_ring_tail_-1 || awake_ring_head_+1==awake_ring_tail_) { 00094 // ring is full. Return -1 as an error indicator. 00095 ret = -1; 00096 } else { 00097 awake_ring_[awake_ring_head_] = func; 00098 awake_data_[awake_ring_head_] = data; 00099 ++awake_ring_head_; 00100 if (awake_ring_head_ == awake_ring_size_) 00101 awake_ring_head_ = 0; 00102 } 00103 unlock_ring(); 00104 return ret; 00105 } 00107 int Fl::get_awake_handler_(Fl_Awake_Handler &func, void *&data) 00108 { 00109 int ret = 0; 00110 lock_ring(); 00111 if (!awake_ring_ || awake_ring_head_ == awake_ring_tail_) { 00112 ret = -1; 00113 } else { 00114 func = awake_ring_[awake_ring_tail_]; 00115 data = awake_data_[awake_ring_tail_]; 00116 ++awake_ring_tail_; 00117 if (awake_ring_tail_ == awake_ring_size_) 00118 awake_ring_tail_ = 0; 00119 } 00120 unlock_ring(); 00121 return ret; 00122 } 00123 00124 // 00130 int Fl::awake(Fl_Awake_Handler func, void *data) { 00131 int ret = add_awake_handler_(func, data); 00132 Fl::awake(); 00133 return ret; 00134 } 00135 00137 // Windows threading... 00189 #ifdef WIN32 00190 # include <windows.h> 00191 # include <process.h> 00192 # include <FL/x.H> 00193 00194 // These pointers are in Fl_win32.cxx: 00195 extern void (*fl_lock_function)(); 00196 extern void (*fl_unlock_function)(); 00197 00198 // The main thread's ID 00199 static DWORD main_thread; 00200 00201 // Microsoft's version of a MUTEX... 00202 CRITICAL_SECTION cs; 00203 CRITICAL_SECTION *cs_ring; 00204 00205 void unlock_ring() { 00206 LeaveCriticalSection(cs_ring); 00207 } 00208 00209 void lock_ring() { 00210 if (!cs_ring) { 00211 cs_ring = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION)); 00212 InitializeCriticalSection(cs_ring); 00213 } 00214 EnterCriticalSection(cs_ring); 00215 } 00216 00217 // 00218 // 'unlock_function()' - Release the lock. 00219 // 00220 00221 static void unlock_function() { 00222 LeaveCriticalSection(&cs); 00223 } 00224 00225 // 00226 // 'lock_function()' - Get the lock. 00227 // 00228 00229 static void lock_function() { 00230 EnterCriticalSection(&cs); 00231 } 00232 00233 void Fl::lock() { 00234 if (!main_thread) InitializeCriticalSection(&cs); 00235 00236 lock_function(); 00237 00238 if (!main_thread) { 00239 fl_lock_function = lock_function; 00240 fl_unlock_function = unlock_function; 00241 main_thread = GetCurrentThreadId(); 00242 } 00243 } 00244 00245 void Fl::unlock() { 00246 unlock_function(); 00247 } 00248 00249 void Fl::awake(void* msg) { 00250 PostThreadMessage( main_thread, fl_wake_msg, (WPARAM)msg, 0); 00251 } 00252 00254 // POSIX threading... 00255 #elif HAVE_PTHREAD 00256 # include <unistd.h> 00257 # include <fcntl.h> 00258 # include <pthread.h> 00259 00260 // Pipe for thread messaging via Fl::awake()... 00261 static int thread_filedes[2]; 00262 00263 // Mutex and state information for Fl::lock() and Fl::unlock()... 00264 static pthread_mutex_t fltk_mutex; 00265 static pthread_t owner; 00266 static int counter; 00267 00268 static void lock_function_init_std() { 00269 pthread_mutex_init(&fltk_mutex, NULL); 00270 } 00271 00272 static void lock_function_std() { 00273 if (!counter || owner != pthread_self()) { 00274 pthread_mutex_lock(&fltk_mutex); 00275 owner = pthread_self(); 00276 } 00277 counter++; 00278 } 00279 00280 static void unlock_function_std() { 00281 if (!--counter) pthread_mutex_unlock(&fltk_mutex); 00282 } 00283 00284 # ifdef PTHREAD_MUTEX_RECURSIVE 00285 static bool lock_function_init_rec() { 00286 pthread_mutexattr_t attrib; 00287 pthread_mutexattr_init(&attrib); 00288 if (pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE)) { 00289 pthread_mutexattr_destroy(&attrib); 00290 return true; 00291 } 00292 00293 pthread_mutex_init(&fltk_mutex, &attrib); 00294 return false; 00295 } 00296 00297 static void lock_function_rec() { 00298 pthread_mutex_lock(&fltk_mutex); 00299 } 00300 00301 static void unlock_function_rec() { 00302 pthread_mutex_unlock(&fltk_mutex); 00303 } 00304 # endif // PTHREAD_MUTEX_RECURSIVE 00305 00306 void Fl::awake(void* msg) { 00307 if (write(thread_filedes[1], &msg, sizeof(void*))==0) { /* ignore */ } 00308 } 00309 00310 static void* thread_message_; 00311 void* Fl::thread_message() { 00312 void* r = thread_message_; 00313 thread_message_ = 0; 00314 return r; 00315 } 00316 00317 static void thread_awake_cb(int fd, void*) { 00318 if (read(fd, &thread_message_, sizeof(void*))==0) { 00319 /* This should never happen */ 00320 } 00321 Fl_Awake_Handler func; 00322 void *data; 00323 while (Fl::get_awake_handler_(func, data)==0) { 00324 (*func)(data); 00325 } 00326 } 00327 00328 // These pointers are in Fl_x.cxx: 00329 extern void (*fl_lock_function)(); 00330 extern void (*fl_unlock_function)(); 00331 00332 void Fl::lock() { 00333 if (!thread_filedes[1]) { 00334 // Initialize thread communication pipe to let threads awake FLTK 00335 // from Fl::wait() 00336 if (pipe(thread_filedes)==-1) { 00337 /* this should not happen */ 00338 } 00339 00340 // Make the write side of the pipe non-blocking to avoid deadlock 00341 // conditions (STR #1537) 00342 fcntl(thread_filedes[1], F_SETFL, 00343 fcntl(thread_filedes[1], F_GETFL) | O_NONBLOCK); 00344 00345 // Monitor the read side of the pipe so that messages sent via 00346 // Fl::awake() from a thread will "wake up" the main thread in 00347 // Fl::wait(). 00348 Fl::add_fd(thread_filedes[0], FL_READ, thread_awake_cb); 00349 00350 // Set lock/unlock functions for this system, using a system-supplied 00351 // recursive mutex if supported... 00352 # ifdef PTHREAD_MUTEX_RECURSIVE 00353 if (!lock_function_init_rec()) { 00354 fl_lock_function = lock_function_rec; 00355 fl_unlock_function = unlock_function_rec; 00356 } else { 00357 # endif // PTHREAD_MUTEX_RECURSIVE 00358 lock_function_init_std(); 00359 fl_lock_function = lock_function_std; 00360 fl_unlock_function = unlock_function_std; 00361 # ifdef PTHREAD_MUTEX_RECURSIVE 00362 } 00363 # endif // PTHREAD_MUTEX_RECURSIVE 00364 } 00365 00366 fl_lock_function(); 00367 } 00368 00369 void Fl::unlock() { 00370 fl_unlock_function(); 00371 } 00372 00373 // Mutex code for the awake ring buffer 00374 static pthread_mutex_t *ring_mutex; 00375 00376 void unlock_ring() { 00377 pthread_mutex_unlock(ring_mutex); 00378 } 00379 00380 void lock_ring() { 00381 if (!ring_mutex) { 00382 ring_mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t)); 00383 pthread_mutex_init(ring_mutex, NULL); 00384 } 00385 pthread_mutex_lock(ring_mutex); 00386 } 00387 00388 #else 00389 00390 void unlock_ring() { 00391 } 00392 00393 void lock_ring() { 00394 } 00395 00396 void Fl::awake(void*) { 00397 } 00398 00399 #endif // WIN32 00400 00401 // 00402 // End of "$Id: Fl_lock.cxx 7903 2010-11-28 21:06:39Z matt $". 00403 //