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