Break some long lines.
[platform/upstream/glib.git] / glib / gthreadpool.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GAsyncQueue: thread pool implementation.
5  * Copyright (C) 2000 Sebastian Wilhelmi; University of Karlsruhe
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * MT safe
25  */
26
27 #include "config.h"
28
29 #include "glib.h"
30 #include "galias.h"
31
32 #define DEBUG_MSG(x) /* */
33 /* #define DEBUG_MSG(args) g_message args ; */
34
35
36 typedef struct _GRealThreadPool GRealThreadPool;
37
38 struct _GRealThreadPool
39 {
40   GThreadPool pool;
41   GAsyncQueue* queue;
42   gint max_threads;
43   gint num_threads;
44   gboolean running;
45   gboolean immediate;
46   gboolean waiting;
47   GCompareDataFunc sort_func;
48   gpointer sort_user_data;
49 };
50
51 /* The following is just an address to mark the stop order for a
52  * thread, it could be any address (as long, as it isn't a valid
53  * GThreadPool address) */
54 static const gpointer stop_this_thread_marker = (gpointer) &g_thread_pool_new;
55
56 /* Here all unused threads are waiting  */
57 static GAsyncQueue *unused_thread_queue;
58 static gint unused_threads = 0;
59 static gint max_unused_threads = 0;
60 static guint max_idle_time = 0;
61 G_LOCK_DEFINE_STATIC (settings);
62
63 static GMutex *inform_mutex = NULL;
64 static GCond *inform_cond = NULL;
65
66
67 static void     g_thread_pool_queue_push_unlocked (GRealThreadPool  *pool,
68                                                    gpointer          data);
69 static void     g_thread_pool_free_internal       (GRealThreadPool  *pool);
70 static gpointer g_thread_pool_thread_proxy        (gpointer          data);
71 static void     g_thread_pool_start_thread        (GRealThreadPool  *pool,
72                                                    GError          **error);
73 static void     g_thread_pool_wakeup_and_stop_all (GRealThreadPool  *pool);
74
75
76 #define g_thread_should_run(pool, len) \
77   ((pool)->running || (!(pool)->immediate && (len) > 0))
78
79
80 static void
81 g_thread_pool_queue_push_unlocked (GRealThreadPool *pool,
82                                    gpointer         data)
83 {
84   if (pool->sort_func) 
85     g_async_queue_push_sorted_unlocked (pool->queue, 
86                                         data,
87                                         pool->sort_func, 
88                                         pool->sort_user_data);
89   else
90     g_async_queue_push_unlocked (pool->queue, data);
91 }
92
93 static gpointer 
94 g_thread_pool_thread_proxy (gpointer data)
95 {
96   GRealThreadPool *pool = data;
97   gboolean watcher = FALSE;
98
99   DEBUG_MSG(("pool:0x%.8x entering proxy ...\n", (guint)pool));
100
101   g_async_queue_lock (pool->queue);
102   while (TRUE)
103     {
104       gpointer task = NULL; 
105       gboolean goto_global_pool = !pool->pool.exclusive;
106       gint len = g_async_queue_length_unlocked (pool->queue);
107
108       if (g_thread_should_run (pool, len))
109         {
110           if (watcher)
111             {
112               /* This thread is actually not needed here, but it waits
113                * for some time anyway. If during that time a new
114                * request arrives, this saves process
115                * swicthes. Otherwise the thread will go to the global
116                * pool afterwards */
117               GTimeVal end_time;
118               g_get_current_time (&end_time);
119               g_time_val_add (&end_time, G_USEC_PER_SEC / 2); /* 1/2 second */
120               DEBUG_MSG(("pool:0x%.8x waiting 1/2 second to pop next item "
121                          "in queue (%d running, %d unprocessed) ...\n", 
122                          (guint)pool, 
123                          pool->num_threads, 
124                          g_async_queue_length_unlocked (pool->queue)));
125               task = g_async_queue_timed_pop_unlocked (pool->queue, &end_time);
126             }
127           else if (g_thread_pool_get_max_idle_time() > 0) 
128             {
129               /* We always give a maximum time to pop the next task so
130                * we know that when we evaluate task further down, that
131                * it has had the maximum time to get a new task and it
132                * can die */
133               GTimeVal end_time;
134               g_get_current_time (&end_time);
135               DEBUG_MSG(("pool:0x%.8x waiting %d ms max to pop next item in "
136                          "queue (%d running, %d unprocessed) or exiting ...\n", 
137                          (guint)pool, 
138                          g_thread_pool_get_max_idle_time (), 
139                          pool->num_threads, 
140                          g_async_queue_length_unlocked (pool->queue)));
141               
142               g_time_val_add (&end_time, g_thread_pool_get_max_idle_time () * 1000);
143               task = g_async_queue_timed_pop_unlocked (pool->queue, &end_time);
144             }
145           else
146             {
147               task = g_async_queue_pop_unlocked (pool->queue);
148               DEBUG_MSG(("pool:0x%.8x new task:0x%.8x poped from pool queue ...\n", 
149                          (guint)pool, (guint)task));
150         }
151
152           if (task)
153             {
154               watcher = FALSE;
155               if (pool->num_threads > pool->max_threads && 
156                   pool->max_threads != -1)
157                 /* We are in fact a superfluous threads, so we go to
158                  * the global pool and just hand the data further to
159                  * the next one waiting in the queue */
160                 {
161                   DEBUG_MSG(("pool:0x%.8x, task:0x%.8x we have too many threads "
162                              "and max is set, pushing task into queue ...\n", 
163                              (guint)pool, (guint)task));
164                   g_thread_pool_queue_push_unlocked (pool, task);
165                   goto_global_pool = TRUE;
166                 }
167               else if (pool->running || !pool->immediate)
168                 {
169                   g_async_queue_unlock (pool->queue);
170                   DEBUG_MSG(("pool:0x%.8x, task:0x%.8x calling func ...\n", 
171                              (guint)pool, (guint)task));
172                   pool->pool.func (task, pool->pool.user_data);
173                   g_async_queue_lock (pool->queue);
174                 }
175             } 
176           else if (g_thread_pool_get_max_idle_time() > 0)  
177             {
178               G_LOCK (settings);
179               if (pool->num_threads > max_unused_threads) {
180                 G_UNLOCK (settings);
181                 pool->num_threads--;      
182                 
183                 DEBUG_MSG(("pool:0x%.8x queue timed pop has no tasks waiting, "
184                            "so stopping thread (%d running, %d unprocessed) ...\n", 
185                            (guint)pool, 
186                            pool->num_threads, 
187                            g_async_queue_length_unlocked (pool->queue)));
188                 g_async_queue_unlock (pool->queue);
189                 
190                 return NULL; 
191               }
192               G_UNLOCK (settings);
193             }
194           len = g_async_queue_length_unlocked (pool->queue);
195         }
196
197       DEBUG_MSG(("pool:0x%.8x, len:%d, watcher:%s, exclusive:%s, should run:%s\n",
198                  (guint)pool, 
199                  len, 
200                  watcher ? "true" : "false", 
201                  pool->pool.exclusive ? "true" : "false", 
202                  g_thread_should_run (pool, len) ? "true" : "false"));
203
204       if (!g_thread_should_run (pool, len))
205         {
206           g_cond_broadcast (inform_cond);
207           goto_global_pool = TRUE;
208         }
209       else if (len > 0)
210         {
211           /* At this pool there are no threads waiting, but tasks are. */
212           goto_global_pool = FALSE; 
213         }
214       else if (len < 1 && g_thread_pool_get_max_idle_time () > 0) 
215         {
216           goto_global_pool = FALSE;
217           watcher = FALSE;
218         }
219       else if (len == 0 && !watcher && !pool->pool.exclusive)
220         {
221           /* Here neither threads nor tasks are queued and we didn't
222            * just return from a timed wait. We now wait for a limited
223            * time at this pool for new tasks to avoid costly context
224            * switches. */
225           goto_global_pool = FALSE;
226           watcher = TRUE;
227         } 
228
229       if (goto_global_pool)
230         {
231           DEBUG_MSG(("pool:0x%.8x, now in the global pool\n", (guint)pool));
232           pool->num_threads--;
233
234           if (!pool->running && !pool->waiting)
235             {
236               if (pool->num_threads == 0)
237                 {
238                   g_async_queue_unlock (pool->queue);
239                   g_thread_pool_free_internal (pool);
240                 }               
241               else 
242                 {
243                   if (len == - pool->num_threads)
244                     g_thread_pool_wakeup_and_stop_all (pool);
245
246                   g_async_queue_unlock (pool->queue);
247                 }
248             }
249           else
250             g_async_queue_unlock (pool->queue);
251           
252           g_async_queue_lock (unused_thread_queue);
253
254           G_LOCK (settings);
255           if ((unused_threads >= max_unused_threads &&
256                max_unused_threads != -1))
257             {
258               G_UNLOCK (settings);
259               g_async_queue_unlock (unused_thread_queue);
260               DEBUG_MSG(("pool:0x%.8x stopping thread (%d running, %d unprocessed) ...\n", 
261                          (guint)pool, 
262                          pool->num_threads, 
263                          g_async_queue_length_unlocked (pool->queue)));
264               /* Stop this thread */
265               return NULL;      
266             }
267           unused_threads++;
268           G_UNLOCK (settings);
269
270           pool = g_async_queue_pop_unlocked (unused_thread_queue);
271
272           G_LOCK (settings);
273           unused_threads--;
274           G_UNLOCK (settings);
275
276           g_async_queue_unlock (unused_thread_queue);
277           
278           if (pool == stop_this_thread_marker)
279             /* Stop this thread */
280             return NULL;
281           
282           g_async_queue_lock (pool->queue);
283
284           /* pool->num_threads++ is not done here, but in
285            * g_thread_pool_start_thread to make the new started thread
286            * known to the pool, before itself can do it. */
287         }
288     }
289   return NULL;
290 }
291
292 static void
293 g_thread_pool_start_thread (GRealThreadPool  *pool, 
294                             GError          **error)
295 {
296   gboolean success = FALSE;
297   
298   if (pool->num_threads >= pool->max_threads && pool->max_threads != -1)
299     /* Enough threads are already running */
300     return;
301
302   g_async_queue_lock (unused_thread_queue);
303
304   if (g_async_queue_length_unlocked (unused_thread_queue) < 0)
305     {
306       g_async_queue_push_unlocked (unused_thread_queue, pool);
307       success = TRUE;
308     }
309
310   g_async_queue_unlock (unused_thread_queue);
311
312   if (!success)
313     {
314       GError *local_error = NULL;
315       /* No thread was found, we have to start a new one */
316       g_thread_create (g_thread_pool_thread_proxy, pool, FALSE, &local_error);
317       
318       if (local_error)
319         {
320           g_propagate_error (error, local_error);
321           return;
322         }
323     }
324
325   /* See comment in g_thread_pool_thread_proxy as to why this is done
326    * here and not there */
327   pool->num_threads++;
328   DEBUG_MSG(("pool:0x%.8x thread created, (running:%d)\n", 
329              (guint)pool, pool->num_threads));
330 }
331
332 /**
333  * g_thread_pool_new: 
334  * @func: a function to execute in the threads of the new thread pool
335  * @user_data: user data that is handed over to @func every time it 
336  *   is called
337  * @max_threads: the maximal number of threads to execute concurrently in 
338  *   the new thread pool, -1 means no limit
339  * @exclusive: should this thread pool be exclusive?
340  * @error: return location for error
341  *
342  * This function creates a new thread pool.
343  *
344  * Whenever you call g_thread_pool_push(), either a new thread is
345  * created or an unused one is reused. At most @max_threads threads
346  * are running concurrently for this thread pool. @max_threads = -1
347  * allows unlimited threads to be created for this thread pool. The
348  * newly created or reused thread now executes the function @func with
349  * the two arguments. The first one is the parameter to
350  * g_thread_pool_push() and the second one is @user_data.
351  *
352  * The parameter @exclusive determines, whether the thread pool owns
353  * all threads exclusive or whether the threads are shared
354  * globally. If @exclusive is %TRUE, @max_threads threads are started
355  * immediately and they will run exclusively for this thread pool until
356  * it is destroyed by g_thread_pool_free(). If @exclusive is %FALSE,
357  * threads are created, when needed and shared between all
358  * non-exclusive thread pools. This implies that @max_threads may not
359  * be -1 for exclusive thread pools.
360  *
361  * @error can be %NULL to ignore errors, or non-%NULL to report
362  * errors. An error can only occur when @exclusive is set to %TRUE and
363  * not all @max_threads threads could be created.
364  *
365  * Return value: the new #GThreadPool
366  **/
367 GThreadPool* 
368 g_thread_pool_new (GFunc            func,
369                    gpointer         user_data,
370                    gint             max_threads,
371                    gboolean         exclusive,
372                    GError         **error)
373 {
374   GRealThreadPool *retval;
375   G_LOCK_DEFINE_STATIC (init);
376
377   g_return_val_if_fail (func, NULL);
378   g_return_val_if_fail (!exclusive || max_threads != -1, NULL);
379   g_return_val_if_fail (max_threads >= -1, NULL);
380   g_return_val_if_fail (g_thread_supported (), NULL);
381
382   retval = g_new (GRealThreadPool, 1);
383
384   retval->pool.func = func;
385   retval->pool.user_data = user_data;
386   retval->pool.exclusive = exclusive;
387   retval->queue = g_async_queue_new ();
388   retval->max_threads = max_threads;
389   retval->num_threads = 0;
390   retval->running = TRUE;
391   retval->sort_func = NULL;
392   retval->sort_user_data = NULL;
393
394   G_LOCK (init);
395   
396   if (!inform_mutex)
397     {
398       inform_mutex = g_mutex_new ();
399       inform_cond = g_cond_new ();
400       unused_thread_queue = g_async_queue_new ();
401     }
402
403   G_UNLOCK (init);
404
405   if (retval->pool.exclusive)
406     {
407       g_async_queue_lock (retval->queue);
408   
409       while (retval->num_threads < retval->max_threads)
410         {
411           GError *local_error = NULL;
412           g_thread_pool_start_thread (retval, &local_error);
413           if (local_error)
414             {
415               g_propagate_error (error, local_error);
416               break;
417             }
418         }
419
420       g_async_queue_unlock (retval->queue);
421     }
422
423   return (GThreadPool*) retval;
424 }
425
426 /**
427  * g_thread_pool_push:
428  * @pool: a #GThreadPool
429  * @data: a new task for @pool
430  * @error: return location for error
431  * 
432  * Inserts @data into the list of tasks to be executed by @pool. When
433  * the number of currently running threads is lower than the maximal
434  * allowed number of threads, a new thread is started (or reused) with
435  * the properties given to g_thread_pool_new (). Otherwise @data stays
436  * in the queue until a thread in this pool finishes its previous task
437  * and processes @data. 
438  *
439  * @error can be %NULL to ignore errors, or non-%NULL to report
440  * errors. An error can only occur when a new thread couldn't be
441  * created. In that case @data is simply appended to the queue of work
442  * to do.  
443  **/
444 void 
445 g_thread_pool_push (GThreadPool     *pool,
446                     gpointer         data,
447                     GError         **error)
448 {
449   GRealThreadPool *real = (GRealThreadPool*) pool;
450
451   g_return_if_fail (real);
452
453   g_async_queue_lock (real->queue);
454   
455   if (!real->running)
456     {
457       g_async_queue_unlock (real->queue);
458       g_return_if_fail (real->running);
459     }
460
461   if (g_async_queue_length_unlocked (real->queue) >= 0)
462     /* No thread is waiting in the queue */
463     g_thread_pool_start_thread (real, error);
464
465   g_thread_pool_queue_push_unlocked (real, data);
466   g_async_queue_unlock (real->queue);
467 }
468
469 /**
470  * g_thread_pool_set_max_threads:
471  * @pool: a #GThreadPool
472  * @max_threads: a new maximal number of threads for @pool
473  * @error: return location for error
474  * 
475  * Sets the maximal allowed number of threads for @pool. A value of -1
476  * means, that the maximal number of threads is unlimited.
477  *
478  * Setting @max_threads to 0 means stopping all work for @pool. It is
479  * effectively frozen until @max_threads is set to a non-zero value
480  * again.
481  * 
482  * A thread is never terminated while calling @func, as supplied by
483  * g_thread_pool_new (). Instead the maximal number of threads only
484  * has effect for the allocation of new threads in g_thread_pool_push(). 
485  * A new thread is allocated, whenever the number of currently
486  * running threads in @pool is smaller than the maximal number.
487  *
488  * @error can be %NULL to ignore errors, or non-%NULL to report
489  * errors. An error can only occur when a new thread couldn't be
490  * created. 
491  **/
492 void
493 g_thread_pool_set_max_threads (GThreadPool     *pool,
494                                gint             max_threads,
495                                GError         **error)
496 {
497   GRealThreadPool *real = (GRealThreadPool*) pool;
498   gint to_start;
499
500   g_return_if_fail (real);
501   g_return_if_fail (real->running);
502   g_return_if_fail (!real->pool.exclusive || max_threads != -1);
503   g_return_if_fail (max_threads >= -1);
504
505   g_async_queue_lock (real->queue);
506
507   real->max_threads = max_threads;
508   
509   if (pool->exclusive)
510     to_start = real->max_threads - real->num_threads;
511   else
512     to_start = g_async_queue_length_unlocked (real->queue);
513   
514   for ( ; to_start > 0; to_start--)
515     {
516       GError *local_error = NULL;
517       g_thread_pool_start_thread (real, &local_error);
518       if (local_error)
519         {
520           g_propagate_error (error, local_error);
521           break;
522         }
523     }
524    
525   g_async_queue_unlock (real->queue);
526 }
527
528 /**
529  * g_thread_pool_get_max_threads:
530  * @pool: a #GThreadPool
531  *
532  * Returns the maximal number of threads for @pool.
533  *
534  * Return value: the maximal number of threads
535  **/
536 gint
537 g_thread_pool_get_max_threads (GThreadPool     *pool)
538 {
539   GRealThreadPool *real = (GRealThreadPool*) pool;
540   gint retval;
541
542   g_return_val_if_fail (real, 0);
543   g_return_val_if_fail (real->running, 0);
544
545   g_async_queue_lock (real->queue);
546
547   retval = real->max_threads;
548     
549   g_async_queue_unlock (real->queue);
550
551   return retval;
552 }
553
554 /**
555  * g_thread_pool_get_num_threads:
556  * @pool: a #GThreadPool
557  *
558  * Returns the number of threads currently running in @pool.
559  *
560  * Return value: the number of threads currently running
561  **/
562 guint
563 g_thread_pool_get_num_threads (GThreadPool     *pool)
564 {
565   GRealThreadPool *real = (GRealThreadPool*) pool;
566   guint retval;
567
568   g_return_val_if_fail (real, 0);
569   g_return_val_if_fail (real->running, 0);
570
571   g_async_queue_lock (real->queue);
572
573   retval = real->num_threads;
574     
575   g_async_queue_unlock (real->queue);
576
577   return retval;
578 }
579
580 /**
581  * g_thread_pool_unprocessed:
582  * @pool: a #GThreadPool
583  *
584  * Returns the number of tasks still unprocessed in @pool.
585  *
586  * Return value: the number of unprocessed tasks
587  **/
588 guint
589 g_thread_pool_unprocessed (GThreadPool     *pool)
590 {
591   GRealThreadPool *real = (GRealThreadPool*) pool;
592   gint unprocessed;
593
594   g_return_val_if_fail (real, 0);
595   g_return_val_if_fail (real->running, 0);
596
597   unprocessed = g_async_queue_length (real->queue);
598
599   return MAX (unprocessed, 0);
600 }
601
602 /**
603  * g_thread_pool_free:
604  * @pool: a #GThreadPool
605  * @immediate: should @pool shut down immediately?
606  * @wait: should the function wait for all tasks to be finished?
607  *
608  * Frees all resources allocated for @pool.
609  *
610  * If @immediate is %TRUE, no new task is processed for
611  * @pool. Otherwise @pool is not freed before the last task is
612  * processed. Note however, that no thread of this pool is
613  * interrupted, while processing a task. Instead at least all still
614  * running threads can finish their tasks before the @pool is freed.
615  *
616  * If @wait is %TRUE, the functions does not return before all tasks
617  * to be processed (dependent on @immediate, whether all or only the
618  * currently running) are ready. Otherwise the function returns immediately.
619  *
620  * After calling this function @pool must not be used anymore. 
621  **/
622 void
623 g_thread_pool_free (GThreadPool     *pool,
624                     gboolean         immediate,
625                     gboolean         wait)
626 {
627   GRealThreadPool *real = (GRealThreadPool*) pool;
628
629   g_return_if_fail (real);
630   g_return_if_fail (real->running);
631   /* It there's no thread allowed here, there is not much sense in
632    * not stopping this pool immediately, when it's not empty */
633   g_return_if_fail (immediate || real->max_threads != 0 || 
634                     g_async_queue_length (real->queue) == 0);
635
636   g_async_queue_lock (real->queue);
637
638   real->running = FALSE;
639   real->immediate = immediate;
640   real->waiting = wait;
641
642   if (wait)
643     {
644       g_mutex_lock (inform_mutex);
645       while (g_async_queue_length_unlocked (real->queue) != -real->num_threads &&
646              !(immediate && real->num_threads == 0))
647         {
648           g_async_queue_unlock (real->queue); 
649           g_cond_wait (inform_cond, inform_mutex); 
650           g_async_queue_lock (real->queue); 
651         }
652       g_mutex_unlock (inform_mutex); 
653     }
654
655   if (immediate ||
656       g_async_queue_length_unlocked (real->queue) == -real->num_threads)
657     {
658       /* No thread is currently doing something (and nothing is left
659        * to process in the queue) */
660       if (real->num_threads == 0) /* No threads left, we clean up */
661         {
662           g_async_queue_unlock (real->queue);
663           g_thread_pool_free_internal (real);
664           return;
665         }
666
667       g_thread_pool_wakeup_and_stop_all (real);
668     }
669   
670   real->waiting = FALSE; /* The last thread should cleanup the pool */
671   g_async_queue_unlock (real->queue);
672 }
673
674 static void
675 g_thread_pool_free_internal (GRealThreadPool* pool)
676 {
677   g_return_if_fail (pool);
678   g_return_if_fail (!pool->running);
679   g_return_if_fail (pool->num_threads == 0);
680
681   g_async_queue_unref (pool->queue);
682
683   g_free (pool);
684 }
685
686 static void
687 g_thread_pool_wakeup_and_stop_all (GRealThreadPool* pool)
688 {
689   guint i;
690   
691   g_return_if_fail (pool);
692   g_return_if_fail (!pool->running);
693   g_return_if_fail (pool->num_threads != 0);
694   g_return_if_fail (g_async_queue_length_unlocked (pool->queue) == 
695                     -pool->num_threads);
696
697   pool->immediate = TRUE; 
698   for (i = 0; i < pool->num_threads; i++)
699     g_thread_pool_queue_push_unlocked (pool, GUINT_TO_POINTER (1));
700 }
701
702 /**
703  * g_thread_pool_set_max_unused_threads:
704  * @max_threads: maximal number of unused threads
705  *
706  * Sets the maximal number of unused threads to @max_threads. If
707  * @max_threads is -1, no limit is imposed on the number of unused
708  * threads.
709  **/
710 void
711 g_thread_pool_set_max_unused_threads (gint max_threads)
712 {
713   g_return_if_fail (max_threads >= -1);  
714
715   G_LOCK (settings);
716   
717   max_unused_threads = max_threads;
718
719   if (max_unused_threads < unused_threads && max_unused_threads != -1)
720     {
721       guint i;
722
723       g_async_queue_lock (unused_thread_queue);
724       for (i = unused_threads - max_unused_threads; i > 0; i--)
725         g_async_queue_push_unlocked (unused_thread_queue, 
726                                      stop_this_thread_marker);
727       g_async_queue_unlock (unused_thread_queue);
728     }
729     
730   G_UNLOCK (settings);
731 }
732
733 /**
734  * g_thread_pool_get_max_unused_threads:
735  * 
736  * Returns the maximal allowed number of unused threads.
737  *
738  * Return value: the maximal number of unused threads
739  **/
740 gint
741 g_thread_pool_get_max_unused_threads (void)
742 {
743   gint retval;
744   
745   G_LOCK (settings);
746   retval = max_unused_threads;
747   G_UNLOCK (settings);
748
749   return retval;
750 }
751
752 /**
753  * g_thread_pool_get_num_unused_threads:
754  * 
755  * Returns the number of currently unused threads.
756  *
757  * Return value: the number of currently unused threads
758  **/
759 guint 
760 g_thread_pool_get_num_unused_threads (void)
761 {
762   guint retval;
763   
764   G_LOCK (settings);
765   retval = unused_threads;
766   G_UNLOCK (settings);
767
768   return retval;
769 }
770
771 /**
772  * g_thread_pool_stop_unused_threads:
773  * 
774  * Stops all currently unused threads. This does not change the
775  * maximal number of unused threads. This function can be used to
776  * regularly stop all unused threads e.g. from g_timeout_add().
777  **/
778 void
779 g_thread_pool_stop_unused_threads (void)
780
781   guint oldval = g_thread_pool_get_max_unused_threads ();
782   g_thread_pool_set_max_unused_threads (0);
783   g_thread_pool_set_max_unused_threads (oldval);
784 }
785
786 /**
787  * g_thread_pool_set_sort_function:
788  * @pool: a #GThreadPool
789  * @func: the #GCompareDataFunc used to sort the list of tasks. 
790  *     This function is passed two tasks. It should return
791  *     0 if the order in which they are handled does not matter, 
792  *     a negative value if the first task should be processed before
793  *     the second or a positive value if the second task should be 
794  *     processed first.
795  * @user_data: user data passed to @func.
796  *
797  * Sets the function used to sort the list of tasks. This allows the
798  * tasks to be processed by a priority determined by @func, and not
799  * just in the order in which they were added to the pool.
800  *
801  * Since: 2.10
802  **/
803 void 
804 g_thread_pool_set_sort_function (GThreadPool      *pool,
805                                  GCompareDataFunc  func,
806                                  gpointer          user_data)
807
808   GRealThreadPool *real = (GRealThreadPool*) pool;
809
810   g_return_if_fail (real);
811   g_return_if_fail (real->running);
812
813   g_async_queue_lock (real->queue);
814
815   real->sort_func = func;
816   real->sort_user_data = user_data;
817   
818   if (func) 
819     g_async_queue_sort_unlocked (real->queue, 
820                                  real->sort_func,
821                                  real->sort_user_data);
822
823   g_async_queue_unlock (real->queue);
824 }
825
826 /**
827  * g_thread_pool_set_max_idle_time:
828  * @interval: the maximum @interval (1/1000ths of a second) a thread
829  *     can be idle. 
830  *
831  * This function will set the maximum @interval that a thread waiting
832  * in the pool for new tasks can be idle for before being
833  * stopped. This function is similar to calling
834  * g_thread_pool_stop_unused_threads() on a regular timeout, except,
835  * this is done on a per thread basis.    
836  *
837  * By setting @interval to 0, idle threads will not be stopped.
838  *  
839  * This function makes use of g_async_queue_timed_pop () using
840  * @interval.
841  *
842  * Since: 2.10
843  **/
844 void
845 g_thread_pool_set_max_idle_time (guint interval)
846
847   G_LOCK (settings);
848   max_idle_time = interval;
849   G_UNLOCK (settings);
850 }
851
852 /**
853  * g_thread_pool_get_max_idle_time:
854  * 
855  * This function will return the maximum @interval that a thread will
856  * wait in the thread pool for new tasks before being stopped.
857  *
858  * If this function returns 0, threads waiting in the thread pool for
859  * new work are not stopped.
860  *
861  * Return value: the maximum @interval to wait for new tasks in the
862  *     thread pool before stopping the thread (1/1000ths of a second).
863  *  
864  * Since: 2.10
865  **/
866 guint
867 g_thread_pool_get_max_idle_time (void)
868
869   guint retval;
870
871   G_LOCK (settings);
872   retval = max_idle_time;
873   G_UNLOCK (settings);
874
875   return retval;
876 }
877
878 #define __G_THREADPOOL_C__
879 #include "galiasdef.c"