2 // "$Id: Fl_lock.cxx 8393 2011-02-06 19:46:11Z manolo $"
4 // Multi-threading support code for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2010 by Bill Spitzak and others.
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.
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.
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
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
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.
45 Starting with 1.1.8, we now have a callback so that you can
46 process awake() messages as they come in.
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.
56 Fl::unlock() - release the recursive lock.
58 Fl::awake(void*) - Causes Fl::wait() to return (with the lock
59 locked) even if there are no events ready.
61 Fl::awake(void (*cb)(void *), void*) - Call a function
62 in the main thread from within another thread of execution.
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!
71 Fl_Awake_Handler
*Fl::awake_ring_
;
72 void **Fl::awake_data_
;
73 int Fl::awake_ring_size_
;
74 int Fl::awake_ring_head_
;
75 int Fl::awake_ring_tail_
;
78 static const int AWAKE_RING_SIZE
= 1024;
79 static void lock_ring();
80 static void unlock_ring();
83 /** Adds an awake handler for use in awake(). */
84 int Fl::add_awake_handler_(Fl_Awake_Handler func
, void *data
)
89 awake_ring_size_
= AWAKE_RING_SIZE
;
90 awake_ring_
= (Fl_Awake_Handler
*)malloc(awake_ring_size_
*sizeof(Fl_Awake_Handler
));
91 awake_data_
= (void**)malloc(awake_ring_size_
*sizeof(void*));
93 if (awake_ring_head_
==awake_ring_tail_
-1 || awake_ring_head_
+1==awake_ring_tail_
) {
94 // ring is full. Return -1 as an error indicator.
97 awake_ring_
[awake_ring_head_
] = func
;
98 awake_data_
[awake_ring_head_
] = data
;
100 if (awake_ring_head_
== awake_ring_size_
)
101 awake_ring_head_
= 0;
106 /** Gets the last stored awake handler for use in awake(). */
107 int Fl::get_awake_handler_(Fl_Awake_Handler
&func
, void *&data
)
111 if (!awake_ring_
|| awake_ring_head_
== awake_ring_tail_
) {
114 func
= awake_ring_
[awake_ring_tail_
];
115 data
= awake_data_
[awake_ring_tail_
];
117 if (awake_ring_tail_
== awake_ring_size_
)
118 awake_ring_tail_
= 0;
125 Let the main thread know an update is pending and have it call a specific function.
126 Registers a function that will be
127 called by the main thread during the next message handling cycle.
128 Returns 0 if the callback function was registered,
129 and -1 if registration failed. Over a thousand awake callbacks can be
130 registered simultaneously.
132 \see Fl::awake(void* message=0)
134 int Fl::awake(Fl_Awake_Handler func
, void *data
) {
135 int ret
= add_awake_handler_(func
, data
);
140 ////////////////////////////////////////////////////////////////
141 // Windows threading...
142 /** \fn int Fl::lock()
143 The lock() method blocks the current thread until it
144 can safely access FLTK widgets and data. Child threads should
145 call this method prior to updating any widgets or accessing
146 data. The main thread must call lock() to initialize
147 the threading support in FLTK. lock() will return non-zero
148 if threading is not available on the platform.
150 Child threads must call unlock() when they are done
153 When the wait() method is waiting
154 for input or timeouts, child threads are given access to FLTK.
155 Similarly, when the main thread needs to do processing, it will
156 wait until all child threads have called unlock() before processing
159 \return 0 if threading is available on the platform; non-zero
162 See also: \ref advanced_multithreading
164 /** \fn void Fl::unlock()
165 The unlock() method releases the lock that was set
166 using the lock() method. Child
167 threads should call this method as soon as they are finished
170 See also: \ref advanced_multithreading
172 /** \fn void Fl::awake(void* msg)
173 Sends a message pointer to the main thread,
174 causing any pending Fl::wait() call to
175 terminate so that the main thread can retrieve the message and any pending
176 redraws can be processed.
178 Multiple calls to Fl::awake() will queue multiple pointers
179 for the main thread to process, up to a system-defined (typically several
180 thousand) depth. The default message handler saves the last message which
181 can be accessed using the
182 Fl::thread_message() function.
184 In the context of a threaded application, a call to Fl::awake() with no
185 argument will trigger event loop handling in the main thread. Since
186 it is not possible to call Fl::flush() from a subsidiary thread,
187 Fl::awake() is the best (and only, really) substitute.
189 See also: \ref advanced_multithreading
192 # include <windows.h>
193 # include <process.h>
196 // These pointers are in Fl_win32.cxx:
197 extern void (*fl_lock_function
)();
198 extern void (*fl_unlock_function
)();
200 // The main thread's ID
201 static DWORD main_thread
;
203 // Microsoft's version of a MUTEX...
205 CRITICAL_SECTION
*cs_ring
;
208 LeaveCriticalSection(cs_ring
);
213 cs_ring
= (CRITICAL_SECTION
*)malloc(sizeof(CRITICAL_SECTION
));
214 InitializeCriticalSection(cs_ring
);
216 EnterCriticalSection(cs_ring
);
220 // 'unlock_function()' - Release the lock.
223 static void unlock_function() {
224 LeaveCriticalSection(&cs
);
228 // 'lock_function()' - Get the lock.
231 static void lock_function() {
232 EnterCriticalSection(&cs
);
236 if (!main_thread
) InitializeCriticalSection(&cs
);
241 fl_lock_function
= lock_function
;
242 fl_unlock_function
= unlock_function
;
243 main_thread
= GetCurrentThreadId();
252 void Fl::awake(void* msg
) {
253 PostThreadMessage( main_thread
, fl_wake_msg
, (WPARAM
)msg
, 0);
256 ////////////////////////////////////////////////////////////////
257 // POSIX threading...
261 # include <pthread.h>
263 // Pipe for thread messaging via Fl::awake()...
264 static int thread_filedes
[2];
266 // Mutex and state information for Fl::lock() and Fl::unlock()...
267 static pthread_mutex_t fltk_mutex
;
268 static pthread_t owner
;
271 static void lock_function_init_std() {
272 pthread_mutex_init(&fltk_mutex
, NULL
);
275 static void lock_function_std() {
276 if (!counter
|| owner
!= pthread_self()) {
277 pthread_mutex_lock(&fltk_mutex
);
278 owner
= pthread_self();
283 static void unlock_function_std() {
284 if (!--counter
) pthread_mutex_unlock(&fltk_mutex
);
287 # ifdef HAVE_PTHREAD_MUTEX_RECURSIVE
288 static bool lock_function_init_rec() {
289 pthread_mutexattr_t attrib
;
290 pthread_mutexattr_init(&attrib
);
291 if (pthread_mutexattr_settype(&attrib
, PTHREAD_MUTEX_RECURSIVE
)) {
292 pthread_mutexattr_destroy(&attrib
);
296 pthread_mutex_init(&fltk_mutex
, &attrib
);
300 static void lock_function_rec() {
301 pthread_mutex_lock(&fltk_mutex
);
304 static void unlock_function_rec() {
305 pthread_mutex_unlock(&fltk_mutex
);
307 # endif // PTHREAD_MUTEX_RECURSIVE
309 void Fl::awake(void* msg
) {
310 if (write(thread_filedes
[1], &msg
, sizeof(void*))==0) { /* ignore */ }
313 static void* thread_message_
;
314 void* Fl::thread_message() {
315 void* r
= thread_message_
;
320 static void thread_awake_cb(int fd
, void*) {
321 if (read(fd
, &thread_message_
, sizeof(void*))==0) {
322 /* This should never happen */
324 Fl_Awake_Handler func
;
326 while (Fl::get_awake_handler_(func
, data
)==0) {
331 // These pointers are in Fl_x.cxx:
332 extern void (*fl_lock_function
)();
333 extern void (*fl_unlock_function
)();
336 if (!thread_filedes
[1]) {
337 // Initialize thread communication pipe to let threads awake FLTK
339 if (pipe(thread_filedes
)==-1) {
340 /* this should not happen */
343 // Make the write side of the pipe non-blocking to avoid deadlock
344 // conditions (STR #1537)
345 fcntl(thread_filedes
[1], F_SETFL
,
346 fcntl(thread_filedes
[1], F_GETFL
) | O_NONBLOCK
);
348 // Monitor the read side of the pipe so that messages sent via
349 // Fl::awake() from a thread will "wake up" the main thread in
351 Fl::add_fd(thread_filedes
[0], FL_READ
, thread_awake_cb
);
353 // Set lock/unlock functions for this system, using a system-supplied
354 // recursive mutex if supported...
355 # ifdef HAVE_PTHREAD_MUTEX_RECURSIVE
356 if (!lock_function_init_rec()) {
357 fl_lock_function
= lock_function_rec
;
358 fl_unlock_function
= unlock_function_rec
;
360 # endif // PTHREAD_MUTEX_RECURSIVE
361 lock_function_init_std();
362 fl_lock_function
= lock_function_std
;
363 fl_unlock_function
= unlock_function_std
;
364 # ifdef HAVE_PTHREAD_MUTEX_RECURSIVE
366 # endif // PTHREAD_MUTEX_RECURSIVE
374 fl_unlock_function();
377 // Mutex code for the awake ring buffer
378 static pthread_mutex_t
*ring_mutex
;
381 pthread_mutex_unlock(ring_mutex
);
386 ring_mutex
= (pthread_mutex_t
*)malloc(sizeof(pthread_mutex_t
));
387 pthread_mutex_init(ring_mutex
, NULL
);
389 pthread_mutex_lock(ring_mutex
);
400 void Fl::awake(void*) {
410 void* Fl::thread_message() {
417 // End of "$Id: Fl_lock.cxx 8393 2011-02-06 19:46:11Z manolo $".