Remove the trace of a TODO file.
[gliv.git] / src / thread.c
blobbd20137ff322c4c22231ec9a0e5623544786e669
1 /*
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>
21 /*******************
22 * Thread handling *
23 *******************/
25 #include <unistd.h> /* pipe() */
26 #include <stdio.h> /* perror() */
28 #include "gliv.h"
29 #include "thread.h"
30 #include "messages.h"
32 typedef struct {
33 GThreadFunc function;
34 gpointer argument;
35 gpointer result;
36 } running_data;
38 typedef struct {
39 GIOChannel *start_read;
40 GIOChannel *start_write;
41 GIOChannel *end_read;
42 GIOChannel *end_write;
43 volatile running_data *run;
44 } thread_data;
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)
52 gchar buf = '\0';
54 for (;;) {
55 /* Wait start. */
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);
65 return NULL;
68 /* Create a new thread. */
69 static thread_data *new_thread(void)
71 thread_data *thread = g_new(thread_data, 1);
72 gint start_pipe[2];
73 gint end_pipe[2];
74 GError *err = NULL;
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)");
83 goto end_pipe_error;
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);
99 if (err != NULL) {
100 g_printerr("%s\n", err->message);
101 g_error_free(err);
102 goto thread_error;
105 return thread;
107 thread_error:
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);
113 end_pipe_error:
114 close(start_pipe[0]);
115 close(start_pipe[1]);
117 start_pipe_error:
118 return NULL;
121 static thread_data *find_free_thread(void)
123 GSList *node;
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;
132 break;
136 if (thread == NULL) {
137 thread = new_thread();
138 if (thread != NULL)
139 threads_list = g_slist_prepend(threads_list, thread);
142 return thread;
145 /* Called when a threaded job is finished. */
146 static gboolean done(GIOChannel * tmp1, GIOCondition tmp2,
147 volatile GThreadFunc * f)
149 *f = NULL;
150 return FALSE;
153 gpointer do_threaded(GThreadFunc f, gpointer arg)
155 thread_data *thread;
156 gpointer result;
157 guchar buf = '\0';
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);
164 return f(arg);
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);
176 /* Start. */
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);
186 thread->run = NULL;
188 return result;