source: rtems-graphics-toolkit/fltk-1.1.10/src/Fl_lock.cxx @ 513eea1

Last change on this file since 513eea1 was 513eea1, checked in by Joel Sherrill <joel.sherrill@…>, on 01/09/10 at 22:43:24

2010-01-08 Joel Sherrill <joel.sherrill@…>

fltk 1.1.10. imported

  • ORIGIN: Updated.
  • Property mode set to 100644
File size: 8.6 KB
Line 
1//
2// "$Id$"
3//
4// Multi-threading support code for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2007 by Bill Spitzak and others.
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Library General Public
10// License as published by the Free Software Foundation; either
11// version 2 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16// Library General Public License for more details.
17//
18// You should have received a copy of the GNU Library General Public
19// License along with this library; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21// USA.
22//
23// Please report all bugs and problems on the following page:
24//
25//     http://www.fltk.org/str.php
26//
27
28
29#include <FL/Fl.H>
30#include <config.h>
31
32#include <stdlib.h>
33
34/*
35   From Bill:
36
37   I would prefer that FLTK contain the minimal amount of extra
38   stuff for doing threads.  There are other portable thread
39   wrapper libraries out there and FLTK should not be providing
40   another.  This file is an attempt to make minimal additions
41   and make them self-contained in this source file.
42
43   From Mike:
44
45   Starting with 1.1.8, we now have a callback so that you can
46   process awake() messages as they come in.
47
48
49   The API:
50
51   Fl::lock() - recursive lock.  You must call this before the
52   first call to Fl::wait()/run() to initialize the thread
53   system. The lock is locked all the time except when
54   Fl::wait() is waiting for events.
55
56   Fl::unlock() - release the recursive lock.
57
58   Fl::awake(void*) - Causes Fl::wait() to return (with the lock
59   locked) even if there are no events ready.
60
61   Fl::awake(void (*cb)(void *), void*) - Call a function
62   in the main thread from within another thread of execution.
63
64   Fl::thread_message() - returns an argument sent to an
65   Fl::awake() call, or returns NULL if none.  WARNING: the
66   current implementation only has a one-entry queue and only
67   returns the most recent value!
68*/
69
70Fl_Awake_Handler *Fl::awake_ring_;
71void **Fl::awake_data_;
72int Fl::awake_ring_size_;
73int Fl::awake_ring_head_;
74int Fl::awake_ring_tail_;
75static const int AWAKE_RING_SIZE = 1024;
76
77static void lock_ring();
78static void unlock_ring();
79
80
81int Fl::add_awake_handler_(Fl_Awake_Handler func, void *data)
82{
83  int ret = 0;
84  lock_ring();
85  if (!awake_ring_) {
86    awake_ring_size_ = AWAKE_RING_SIZE;
87    awake_ring_ = (Fl_Awake_Handler*)malloc(awake_ring_size_*sizeof(Fl_Awake_Handler));
88    awake_data_ = (void**)malloc(awake_ring_size_*sizeof(void*));
89  }
90  if (awake_ring_head_==awake_ring_tail_-1 || awake_ring_head_+1==awake_ring_tail_) {
91    // ring is full. Return -1 as an error indicator.
92    ret = -1;
93  } else {
94    awake_ring_[awake_ring_head_] = func;
95    awake_data_[awake_ring_head_] = data;
96    ++awake_ring_head_;
97    if (awake_ring_head_ == awake_ring_size_)
98      awake_ring_head_ = 0;
99  }
100  unlock_ring();
101  return ret;
102}
103
104int Fl::get_awake_handler_(Fl_Awake_Handler &func, void *&data)
105{
106  int ret = 0;
107  lock_ring();
108  if (!awake_ring_ || awake_ring_head_ == awake_ring_tail_) {
109    ret = -1;
110  } else {
111    func = awake_ring_[awake_ring_tail_];
112    data = awake_data_[awake_ring_tail_];
113    ++awake_ring_tail_;
114    if (awake_ring_tail_ == awake_ring_size_)
115      awake_ring_tail_ = 0;
116  }
117  unlock_ring();
118  return ret;
119}
120
121//
122// 'Fl::awake()' - Let the main thread know an update is pending
123//                 and have it cal a specific function
124//
125int Fl::awake(Fl_Awake_Handler func, void *data) {
126  int ret = add_awake_handler_(func, data);
127  Fl::awake();
128  return ret;
129}
130
131////////////////////////////////////////////////////////////////
132// Windows threading...
133#ifdef WIN32
134#  include <windows.h>
135#  include <process.h>
136#  include <FL/x.H>
137
138// These pointers are in Fl_win32.cxx:
139extern void (*fl_lock_function)();
140extern void (*fl_unlock_function)();
141
142// The main thread's ID
143static DWORD main_thread;
144
145// Microsoft's version of a MUTEX...
146CRITICAL_SECTION cs;
147CRITICAL_SECTION *cs_ring;
148
149void unlock_ring() {
150  LeaveCriticalSection(cs_ring);
151}
152
153void lock_ring() {
154  if (!cs_ring) {
155    cs_ring = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION));
156    InitializeCriticalSection(cs_ring);
157  }
158  EnterCriticalSection(cs_ring);
159}
160
161//
162// 'unlock_function()' - Release the lock.
163//
164
165static void unlock_function() {
166  LeaveCriticalSection(&cs);
167}
168
169//
170// 'lock_function()' - Get the lock.
171//
172
173static void lock_function() {
174  EnterCriticalSection(&cs);
175}
176
177//
178// 'Fl::lock()' - Lock access to FLTK data structures...
179//
180
181void Fl::lock() {
182  if (!main_thread) InitializeCriticalSection(&cs);
183
184  lock_function();
185
186  if (!main_thread) {
187    fl_lock_function   = lock_function;
188    fl_unlock_function = unlock_function;
189    main_thread        = GetCurrentThreadId();
190  }
191}
192
193//
194// 'Fl::unlock()' - Unlock access to FLTK data structures...
195//
196
197void Fl::unlock() {
198  unlock_function();
199}
200
201
202//
203// 'Fl::awake()' - Let the main thread know an update is pending.
204//
205// When called from a thread, it causes FLTK to awake from Fl::wait()...
206//
207
208void Fl::awake(void* msg) {
209  PostThreadMessage( main_thread, fl_wake_msg, (WPARAM)msg, 0);
210}
211
212////////////////////////////////////////////////////////////////
213// POSIX threading...
214#elif HAVE_PTHREAD
215#  include <unistd.h>
216#  include <fcntl.h>
217#  include <pthread.h>
218
219// Pipe for thread messaging via Fl::awake()...
220static int thread_filedes[2];
221
222// Mutex and state information for Fl::lock() and Fl::unlock()...
223static pthread_mutex_t fltk_mutex;
224static pthread_t owner;
225static int counter;
226
227static void lock_function_init_std() {
228  pthread_mutex_init(&fltk_mutex, NULL);
229}
230
231static void lock_function_std() {
232  if (!counter || owner != pthread_self()) {
233    pthread_mutex_lock(&fltk_mutex);
234    owner = pthread_self();
235  }
236  counter++;
237}
238
239static void unlock_function_std() {
240  if (!--counter) pthread_mutex_unlock(&fltk_mutex);
241}
242
243#  ifdef PTHREAD_MUTEX_RECURSIVE
244static bool lock_function_init_rec() {
245  pthread_mutexattr_t attrib;
246  pthread_mutexattr_init(&attrib);
247  if (pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE)) {
248    pthread_mutexattr_destroy(&attrib);
249    return true;
250  }
251
252  pthread_mutex_init(&fltk_mutex, &attrib);
253  return false;
254}
255
256static void lock_function_rec() {
257  pthread_mutex_lock(&fltk_mutex);
258}
259
260static void unlock_function_rec() {
261  pthread_mutex_unlock(&fltk_mutex);
262}
263#  endif // PTHREAD_MUTEX_RECURSIVE
264
265void Fl::awake(void* msg) {
266  write(thread_filedes[1], &msg, sizeof(void*));
267}
268
269static void* thread_message_;
270void* Fl::thread_message() {
271  void* r = thread_message_;
272  thread_message_ = 0;
273  return r;
274}
275
276static void thread_awake_cb(int fd, void*) {
277  read(fd, &thread_message_, sizeof(void*));
278  Fl_Awake_Handler func;
279  void *data;
280  while (Fl::get_awake_handler_(func, data)==0) {
281    (*func)(data);
282  }
283}
284
285// These pointers are in Fl_x.cxx:
286extern void (*fl_lock_function)();
287extern void (*fl_unlock_function)();
288
289void Fl::lock() {
290  if (!thread_filedes[1]) {
291    // Initialize thread communication pipe to let threads awake FLTK
292    // from Fl::wait()
293    pipe(thread_filedes);
294
295    // Make the write side of the pipe non-blocking to avoid deadlock
296    // conditions (STR #1537)
297    fcntl(thread_filedes[1], F_SETFL,
298          fcntl(thread_filedes[1], F_GETFL) | O_NONBLOCK);
299
300    // Monitor the read side of the pipe so that messages sent via
301    // Fl::awake() from a thread will "wake up" the main thread in
302    // Fl::wait().
303    Fl::add_fd(thread_filedes[0], FL_READ, thread_awake_cb);
304
305    // Set lock/unlock functions for this system, using a system-supplied
306    // recursive mutex if supported...
307#  ifdef PTHREAD_MUTEX_RECURSIVE
308    if (!lock_function_init_rec()) {
309      fl_lock_function   = lock_function_rec;
310      fl_unlock_function = unlock_function_rec;
311    } else {
312#  endif // PTHREAD_MUTEX_RECURSIVE
313      lock_function_init_std();
314      fl_lock_function   = lock_function_std;
315      fl_unlock_function = unlock_function_std;
316#  ifdef PTHREAD_MUTEX_RECURSIVE
317    }
318#  endif // PTHREAD_MUTEX_RECURSIVE
319  }
320
321  fl_lock_function();
322}
323
324void Fl::unlock() {
325  fl_unlock_function();
326}
327
328// Mutex code for the awake ring buffer
329static pthread_mutex_t *ring_mutex;
330
331void unlock_ring() {
332  pthread_mutex_unlock(ring_mutex);
333}
334
335void lock_ring() {
336  if (!ring_mutex) {
337    ring_mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
338    pthread_mutex_init(ring_mutex, NULL);
339  }
340  pthread_mutex_lock(ring_mutex);
341}
342
343#else
344
345void unlock_ring() {
346}
347
348void lock_ring() {
349}
350
351void Fl::awake(void*) {
352}
353
354#endif // WIN32
355
356//
357// End of "$Id$".
358//
Note: See TracBrowser for help on using the repository browser.