diff options
| author | Michael R Sweet <michael.r.sweet@gmail.com> | 2007-01-29 17:15:41 +0000 |
|---|---|---|
| committer | Michael R Sweet <michael.r.sweet@gmail.com> | 2007-01-29 17:15:41 +0000 |
| commit | 56eb04fc67cae694ef3d52c9f1f4edb2b645fa3d (patch) | |
| tree | b597a08477d39a80cbfc23400e029286d85eb7fa | |
| parent | b7be6fb47e88e0d39a1ba3513dbb5ea69dd98935 (diff) | |
Incorporate run-time check and initialization of recursive mutexes.
This adds support for system-supplied recursive mutexes on OS's other
than Linux (not all define the _NP static initializer) while making
sure that the mutex we do use works as we expect (STR #1575)
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@5648 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
| -rw-r--r-- | CHANGES | 6 | ||||
| -rw-r--r-- | src/Fl_lock.cxx | 88 |
2 files changed, 71 insertions, 23 deletions
@@ -1,9 +1,9 @@ CHANGES IN FLTK 1.1.8 - Fl::awake() could block on X11 and OSX (STR #1537) - - Dropped "native" recursive POSIX mutex support since the kernel's - underlying implementation may not support it even if the C - library does (STR #1575) + - Updated recursive mutex code to run on platforms other + than Linux and to do a run-time check to determine + whether they are supported by the kernel (STR #1575) - WIN32 did check callbacks after the event processing instead of before as documented (STR #1535) - Fl_File_Chooser now hides the window before doing a callback diff --git a/src/Fl_lock.cxx b/src/Fl_lock.cxx index 6db23cdc5..be52f78d1 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-2005 by Bill Spitzak and others. +// Copyright 1998-2007 by Bill Spitzak and others. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public @@ -130,15 +130,19 @@ void Fl::awake(void* msg) { # include <fcntl.h> # include <pthread.h> -// Make a recursive lock out of the pthread mutex; we don't use "native" -// recursive locks since they may not be implemented by the running kernel -// (see discussions in STR #1575) +// Pipe for thread messaging via Fl::awake()... +static int thread_filedes[2]; -static pthread_mutex_t fltk_mutex = PTHREAD_MUTEX_INITIALIZER; +// Mutux and state information for Fl::lock() and Fl::unlock()... +static pthread_mutex_t fltk_mutex; static pthread_t owner; static int counter; -static void lock_function() { +static void lock_function_init_std() { + pthread_mutex_init(&fltk_mutex, NULL); +} + +static void lock_function_std() { if (!counter || owner != pthread_self()) { pthread_mutex_lock(&fltk_mutex); owner = pthread_self(); @@ -146,16 +150,35 @@ static void lock_function() { counter++; } -void Fl::unlock() { +static void unlock_function_std() { if (!--counter) pthread_mutex_unlock(&fltk_mutex); } -// Pipe for thread messaging... -static int thread_filedes[2]; +# ifdef PTHREAD_MUTEX_RECURSIVE +static bool lock_function_init_rec() { + pthread_mutexattr_t attrib; + pthread_mutexattr_init(&attrib); + if (pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE)) { + pthread_mutexattr_destroy(&attrib); + return true; + } -// These pointers are in Fl_x.cxx: -extern void (*fl_lock_function)(); -extern void (*fl_unlock_function)(); + pthread_mutex_init(&fltk_mutex, &attrib); + return false; +} + +static void lock_function_rec() { + pthread_mutex_lock(&fltk_mutex); +} + +static void unlock_function_rec() { + pthread_mutex_unlock(&fltk_mutex); +} +# endif // PTHREAD_MUTEX_RECURSIVE + +void Fl::awake(void* msg) { + write(thread_filedes[1], &msg, sizeof(void*)); +} static void* thread_message_; void* Fl::thread_message() { @@ -168,23 +191,48 @@ static void thread_awake_cb(int fd, void*) { read(fd, &thread_message_, sizeof(void*)); } +// These pointers are in Fl_x.cxx: +extern void (*fl_lock_function)(); +extern void (*fl_unlock_function)(); + void Fl::lock() { - lock_function(); - if (!thread_filedes[1]) { // initialize the mt support - // Init threads communication pipe to let threads awake FLTK from wait + if (!thread_filedes[1]) { + // Initialize thread communication pipe to let threads awake FLTK + // from Fl::wait() pipe(thread_filedes); + + // Make the write side of the pipe non-blocking to avoid deadlock + // conditions (STR #1537) fcntl(thread_filedes[1], F_SETFL, fcntl(thread_filedes[1], F_GETFL) | O_NONBLOCK); + + // Monitor the read side of the pipe so that messages sent via + // Fl::awake() from a thread will "wake up" the main thread in + // Fl::wait(). Fl::add_fd(thread_filedes[0], FL_READ, thread_awake_cb); - fl_lock_function = lock_function; - fl_unlock_function = Fl::unlock; + + // Set lock/unlock functions for this system, using a system-supplied + // recursive mutex if supported... +# ifdef PTHREAD_MUTEX_RECURSIVE + if (!lock_function_init_rec()) { + fl_lock_function = lock_function_rec; + fl_unlock_function = unlock_function_rec; + } else { +# endif // PTHREAD_MUTEX_RECURSIVE + lock_function_init_std(); + fl_lock_function = lock_function_std; + fl_unlock_function = unlock_function_std; +# ifdef PTHREAD_MUTEX_RECURSIVE + } +# endif // PTHREAD_MUTEX_RECURSIVE } -} -void Fl::awake(void* msg) { - write(thread_filedes[1], &msg, sizeof(void*)); + fl_lock_function(); } +void Fl::unlock() { + fl_unlock_function(); +} #endif // WIN32 // |
