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() */
27 #include <fcntl.h> /* _O_BINARY for MinGW */
40 GIOChannel
*start_read
;
41 GIOChannel
*start_write
;
43 GIOChannel
*end_write
;
44 volatile running_data
*run
;
47 static GSList
*threads_list
= NULL
;
48 G_LOCK_DEFINE_STATIC(threads_list
);
50 /* This is executed in a separate thread. */
51 static gpointer
thread_func(thread_data
* data
)
57 g_io_channel_read_chars(data
->start_read
, &buf
, 1, NULL
, NULL
);
59 data
->run
->result
= data
->run
->function(data
->run
->argument
);
61 /* Inform that we have finished. */
62 g_io_channel_write_chars(data
->end_write
, &buf
, 1, NULL
, NULL
);
63 g_io_channel_flush(data
->end_write
, NULL
);
69 /* Create a new thread. */
70 static thread_data
*new_thread(void)
72 thread_data
*thread
= g_new(thread_data
, 1);
77 if (pipe(start_pipe
) < 0) {
78 perror("pipe(start_pipe)");
79 goto start_pipe_error
;
82 if (pipe(end_pipe
) < 0) {
83 perror("pipe(end_pipe)");
87 thread
->start_read
= g_io_channel_unix_new(start_pipe
[0]);
88 g_io_channel_set_encoding(thread
->start_read
, NULL
, NULL
);
90 thread
->start_write
= g_io_channel_unix_new(start_pipe
[1]);
91 g_io_channel_set_encoding(thread
->start_write
, NULL
, NULL
);
93 thread
->end_read
= g_io_channel_unix_new(end_pipe
[0]);
94 g_io_channel_set_encoding(thread
->end_read
, NULL
, NULL
);
96 thread
->end_write
= g_io_channel_unix_new(end_pipe
[1]);
97 g_io_channel_set_encoding(thread
->end_write
, NULL
, NULL
);
99 g_thread_create((GThreadFunc
) thread_func
, thread
, TRUE
, &err
);
101 g_printerr("%s\n", err
->message
);
109 g_io_channel_shutdown(thread
->start_read
, FALSE
, NULL
);
110 g_io_channel_shutdown(thread
->start_write
, FALSE
, NULL
);
111 g_io_channel_shutdown(thread
->end_read
, FALSE
, NULL
);
112 g_io_channel_shutdown(thread
->end_write
, FALSE
, NULL
);
115 close(start_pipe
[0]);
116 close(start_pipe
[1]);
122 static thread_data
*find_free_thread(void)
125 thread_data
*thread
= NULL
;
127 for (node
= threads_list
; node
!= NULL
; node
= node
->next
) {
128 thread_data
*node_thread
;
130 node_thread
= node
->data
;
131 if (node_thread
->run
== NULL
) {
132 thread
= node_thread
;
137 if (thread
== NULL
) {
138 thread
= new_thread();
140 threads_list
= g_slist_prepend(threads_list
, thread
);
146 /* Called when a threaded job is finished. */
147 static gboolean
done(GIOChannel
* tmp1
, GIOCondition tmp2
,
148 volatile GThreadFunc
* f
)
154 gpointer
do_threaded(GThreadFunc f
, gpointer arg
)
160 G_LOCK(threads_list
);
161 thread
= find_free_thread();
162 if (thread
== NULL
) {
163 G_UNLOCK(threads_list
);
164 g_printerr(_("Cannot use a thread\n"));
168 thread
->run
= g_new(running_data
, 1);
169 thread
->run
->function
= f
;
170 thread
->run
->argument
= arg
;
172 G_UNLOCK(threads_list
);
174 g_io_add_watch(thread
->end_read
, G_IO_IN
, (GIOFunc
) done
,
175 (gpointer
) & thread
->run
->function
);
178 g_io_channel_write_chars(thread
->start_write
, &buf
, 1, NULL
, NULL
);
179 g_io_channel_flush(thread
->start_write
, NULL
);
181 while (thread
->run
->function
!= NULL
)
182 gtk_main_iteration();
184 g_io_channel_read_chars(thread
->end_read
, &buf
, 1, NULL
, NULL
);
185 result
= thread
->run
->result
;
186 g_free((gpointer
) thread
->run
);