2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <guichaz@yahoo.fr>
25 #include <unistd.h> /* pipe() */
26 #include <stdio.h> /* perror() */
39 GIOChannel
*start_read
;
40 GIOChannel
*start_write
;
42 GIOChannel
*end_write
;
43 volatile running_data
*run
;
46 static GSList
*threads_list
= NULL
;
47 G_LOCK_DEFINE_STATIC(threads_list
);
49 /* This is executed in a separate thread. */
50 static gpointer
thread_func(thread_data
* data
)
56 g_io_channel_read_chars(data
->start_read
, &buf
, 1, NULL
, NULL
);
58 data
->run
->result
= data
->run
->function(data
->run
->argument
);
60 /* Inform that we have finished. */
61 g_io_channel_write_chars(data
->end_write
, &buf
, 1, NULL
, NULL
);
62 g_io_channel_flush(data
->end_write
, NULL
);
68 /* Create a new thread. */
69 static thread_data
*new_thread(void)
71 thread_data
*thread
= g_new(thread_data
, 1);
76 if (pipe(start_pipe
) < 0) {
77 perror("pipe(start_pipe)");
78 goto start_pipe_error
;
81 if (pipe(end_pipe
) < 0) {
82 perror("pipe(end_pipe)");
86 thread
->start_read
= g_io_channel_unix_new(start_pipe
[0]);
87 g_io_channel_set_encoding(thread
->start_read
, NULL
, NULL
);
89 thread
->start_write
= g_io_channel_unix_new(start_pipe
[1]);
90 g_io_channel_set_encoding(thread
->start_write
, NULL
, NULL
);
92 thread
->end_read
= g_io_channel_unix_new(end_pipe
[0]);
93 g_io_channel_set_encoding(thread
->end_read
, NULL
, NULL
);
95 thread
->end_write
= g_io_channel_unix_new(end_pipe
[1]);
96 g_io_channel_set_encoding(thread
->end_write
, NULL
, NULL
);
98 g_thread_create((GThreadFunc
) thread_func
, thread
, TRUE
, &err
);
100 g_printerr("%s\n", err
->message
);
108 g_io_channel_shutdown(thread
->start_read
, FALSE
, NULL
);
109 g_io_channel_shutdown(thread
->start_write
, FALSE
, NULL
);
110 g_io_channel_shutdown(thread
->end_read
, FALSE
, NULL
);
111 g_io_channel_shutdown(thread
->end_write
, FALSE
, NULL
);
114 close(start_pipe
[0]);
115 close(start_pipe
[1]);
121 static thread_data
*find_free_thread(void)
124 thread_data
*thread
= NULL
;
126 for (node
= threads_list
; node
!= NULL
; node
= node
->next
) {
127 thread_data
*node_thread
;
129 node_thread
= node
->data
;
130 if (node_thread
->run
== NULL
) {
131 thread
= node_thread
;
136 if (thread
== NULL
) {
137 thread
= new_thread();
139 threads_list
= g_slist_prepend(threads_list
, thread
);
145 /* Called when a threaded job is finished. */
146 static gboolean
done(GIOChannel
* tmp1
, GIOCondition tmp2
,
147 volatile GThreadFunc
* f
)
153 gpointer
do_threaded(GThreadFunc f
, gpointer arg
)
159 G_LOCK(threads_list
);
160 thread
= find_free_thread();
161 if (thread
== NULL
) {
162 ERROR_MSG(_("Cannot use a thread"));
163 G_UNLOCK(threads_list
);
167 thread
->run
= g_new(running_data
, 1);
168 thread
->run
->function
= f
;
169 thread
->run
->argument
= arg
;
171 G_UNLOCK(threads_list
);
173 g_io_add_watch(thread
->end_read
, G_IO_IN
, (GIOFunc
) done
,
174 (gpointer
) & thread
->run
->function
);
177 g_io_channel_write_chars(thread
->start_write
, &buf
, 1, NULL
, NULL
);
178 g_io_channel_flush(thread
->start_write
, NULL
);
180 while (thread
->run
->function
!= NULL
)
181 gtk_main_iteration();
183 g_io_channel_read_chars(thread
->end_read
, &buf
, 1, NULL
, NULL
);
184 result
= thread
->run
->result
;
185 g_free((gpointer
) thread
->run
);