FreeWRL / FreeX3D 4.3.0
threads.c
1/*
2
3 FreeWRL support library.
4 Threads & process (fork).
5
6*/
7
8/****************************************************************************
9 This file is part of the FreeWRL/FreeX3D Distribution.
10
11 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12
13 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14 it under the terms of the GNU Lesser Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25****************************************************************************/
26
27
28
29#include <config.h>
30#include <system.h>
31#include <system_threads.h>
32#include <internal.h>
33#include <display.h>
34#include <threads.h>
35
36#include <errno.h>
37
38#ifdef FREEWRL_THREAD_COLORIZED
39
40/* Notes on thread ids and colors
41
42 We have 5 threads max: main, display, parse, texture and shape.
43 Each has its thread variable (pthread_t), it's number (1 through 5).
44
45 Each thead has a "name" now (FREEWRL_THREAD_*).
46
47 Now we associate a color for each thread in thread_colors[].
48 The color is an ANSI color code for console output.
49
50 In internal.h/c the code for console output is modified to use
51 the thread color ([F]PRINTF gets the thread id with fw_thread_id()
52 and gets the thread color from the array thread_colors through the
53 fw_thread_color() function).
54
55*/
56
57static int threads_colors[FREEWRL_MAX_THREADS] = {
58 32, /* main thread is green */
59 36, /* display thread is cyan */
60 35, /* parser thread is purple */
61 33, /* texture thread is brown */
62 34, /* shape thread is blue */
63 /* red color is reserved for important threading functions */
64};
65#define FREEWRL_DEFAULT_COLOR 37 /* white */
66
67#endif /* FREEWRL_THREAD_COLORIZED */
68
69DEF_THREAD(_THREAD_NULL_); //used to initialize thread members in generatedcode.c via system_threads.h
70
71
72/* Thread global variables */
73//pthread_t mainThread; /* main (default) thread */
74//
75//DEF_THREAD(DispThrd); /* display thread */
76//
77//DEF_THREAD(PCthread); /* parser thread */
78//
79//DEF_THREAD(loadThread); /* texture thread */
80
81/* Thread synchronization global variables */
82
84//pthread_mutex_t mutex_resource_tree = PTHREAD_MUTEX_INITIALIZER;
85//
87//pthread_mutex_t mutex_resource_list = PTHREAD_MUTEX_INITIALIZER;
88//pthread_cond_t resource_list_condition = PTHREAD_COND_INITIALIZER;
89//
91//pthread_mutex_t mutex_texture_list = PTHREAD_MUTEX_INITIALIZER;
92//pthread_cond_t texture_list_condition = PTHREAD_COND_INITIALIZER;
93
94//typedef struct pthreads{
95//}*ppthreads;
96//void *threads_constructor(){
97// void *v = MALLOCV(sizeof(struct pthreads));
98// memset(v, 0, sizeof(struct pthreads));
99// return v;
100//}
101#ifdef DOWEREALYNEEDTHIS
102static int fw_once = 0;
103#endif
104void threads_init(struct tthreads* t)
105{
106 //public
107//pthread_t mainThread; /* main (default) thread */
108//t->DispThrd = {NULL,0}; /* display thread */
109//t->PCthread = {NULL,0}; /* parser thread */
110//t->loadThread = {NULL,0}; /* texture thread */
111/* Synchronize / exclusion root_res and below */
112//t->mutex_resource_tree = PTHREAD_MUTEX_INITIALIZER;
113//
115//t->mutex_resource_list = PTHREAD_MUTEX_INITIALIZER;
116//t->resource_list_condition = PTHREAD_COND_INITIALIZER;
117//
119//t->mutex_texture_list = PTHREAD_MUTEX_INITIALIZER;
120//t->texture_list_condition = PTHREAD_COND_INITIALIZER;
121
122#ifdef DOWEREALYNEEDTHIS
123 //for windows I found a gthreads implementation of pthreads that does need this
124 if (fw_once == 0){
125 //once per process
126#ifdef _MSC_VER
127 pthread_win32_process_attach_np();
128#endif
129 fw_once = 1;
130 }
131
132/* Synchronize / exclusion root_res and below */
133 pthread_mutex_init (&t->mutex_resource_tree,NULL); // = PTHREAD_MUTEX_INITIALIZER;
134/* Synchronize / exclusion : resource queue for parser */
135 pthread_mutex_init (&t->mutex_resource_list,NULL); // = PTHREAD_MUTEX_INITIALIZER;
136 pthread_cond_init (&t->resource_list_condition,NULL); // = PTHREAD_COND_INITIALIZER;
137 /* Synchronize / exclusion (main<=>texture) */
138 pthread_mutex_init (&t->mutex_texture_list,NULL); // = PTHREAD_MUTEX_INITIALIZER;
139 pthread_cond_init(&t->texture_list_condition,NULL); // = PTHREAD_COND_INITIALIZER;
140
141 pthread_mutex_init(&t->mutex_frontend_list,NULL);
142#endif
143
144 t->ResourceThreadRunning = false;
145 t->TextureThreadRunning = false;
146 t->ResourceThreadWaiting = false;
147 t->TextureThreadWaiting = false;
148 t->MainLoopQuit = 0;
149 t->flushing = false;
150 //private
151 //t->prv = threads_constructor();
152 //{
153 // ppthreads p = (ppthreads)t->prv;
154 //}
155
156}
157
158
159
160#ifdef _MSC_VER
161void sync(){}
162#endif
163
164
165
166
167/* create consumer thread and set the "read only" flag indicating this */
168void fwl_initializeInputParseThread()
169{
170 int ret;
171 ttglobal tg = gglobal();
172
173 /* Synchronize trace/error log... */
174 fflush(stdout);
175 fflush(stderr);
176
177 /* Initialize all mutex/condition variables ... */
178 pthread_mutex_init( &tg->threads.mutex_resource_tree, NULL );
179 pthread_mutex_init( &tg->threads.mutex_resource_list, NULL );
180 pthread_cond_init( &tg->threads.resource_list_condition, NULL );
181 pthread_mutex_init(&tg->threads.mutex_frontend_list,NULL);
182
183
184 ASSERT(TEST_NULL_THREAD(tg->threads.PCthread));
185 ret = pthread_create(&tg->threads.PCthread, NULL, (void *(*)(void *))&_inputParseThread, tg);
186 //printf ("input parse thread, I am %p\n",tg->threads.PCthread);
187 switch (ret) {
188 case 0:
189 break;
190 case EAGAIN:
191 ERROR_MSG("initializeInputParseThread: not enough system resources to create a process for the new thread.");
192 return;
193 }
194}
195
196void fwl_initializeTextureThread()
197{
198 int ret;
199 ttglobal tg = gglobal();
200
201 pthread_mutex_init( &tg->threads.mutex_texture_list, NULL );
202 pthread_cond_init( &tg->threads.texture_list_condition, NULL );
203
204 /* Synchronize trace/error log... */
205 fflush(stdout);
206 fflush(stderr);
207
208 ASSERT(TEST_NULL_THREAD(tg->threads.loadThread));
209 ret = pthread_create(&tg->threads.loadThread, NULL, (void *(*)(void *))&_textureThread, tg);
210 //printf ("input texture thread, I am %p\n",tg->threads.loadThread);
211 switch (ret) {
212 case 0:
213 break;
214 case EAGAIN:
215 ERROR_MSG("initializeTextureThread: not enough system resources to create a process for the new thread.");
216 return;
217 }
218}
219
220int fw_thread_id()
221{
222 pthread_t current_thread;
223 ttglobal tg = gglobal();
224 current_thread = pthread_self();
225
226//#ifdef _MSC_VER
227// if (!current_thread.p) {
228//#else
229// if (!current_thread) {
230//#endif
231 if(TEST_NULL_THREAD(current_thread)){
232 ERROR_MSG("Critical: pthread_self returned 0\n");
233 return 0;
234 }
235
236 if (pthread_equal(current_thread, tg->threads.mainThread))
237 return FREEWRL_THREAD_MAIN;
238
239 if (pthread_equal(current_thread, tg->threads.DispThrd))
240 return FREEWRL_THREAD_DISPLAY;
241
242 if (pthread_equal(current_thread, tg->threads.PCthread))
243 return FREEWRL_THREAD_PARSER;
244
245 if (pthread_equal(current_thread, tg->threads.loadThread))
246 return FREEWRL_THREAD_TEXTURE;
247
248/*#endif*/
249 return -1;
250}
251
252#ifdef FREEWRL_THREAD_COLORIZED
253
254int fw_thread_color(int thread_id)
255{
256 /* id will range from 1 to 5 */
257 if ((thread_id > 0) && (thread_id <= FREEWRL_MAX_THREADS)) {
258 return threads_colors[ thread_id - 1 ];
259 }
260 return FREEWRL_DEFAULT_COLOR;
261}
262
263#endif /* FREEWRL_THREAD_COLORIZED */
264
265void fwl_thread_dump()
266{
267 if (gglobal()->internalc.global_trace_threads) {
268 /* Synchronize trace/error log... */
269 fflush(stdout);
270 fflush(stderr);
271 TRACE_MSG("FreeWRL CURRENT THREAD: %d\n", fw_thread_id());
272 }
273}
274
275void trace_enter_thread(const char *str)
276{
277 int nloops = 0;
278 ttglobal tg = gglobal0(); // get the value if we can
279 while(tg == NULL){
280 usleep(50);
281 tg = gglobal0(); //<< new function ttglobal0() just returns NULL if thread not registered yet
282 nloops++;
283 }
284 //printf("trace_enter_thread spent %d loops\n",nloops);
285
286 if (gglobal()->internalc.global_trace_threads) {
287 /* Synchronize trace/error log... */
288 fflush(stdout);
289 fflush(stderr);
290 sync();
291//#ifdef _MSC_VER
292// TRACE_MSG("*** ENTERING THREAD: %s, ID=%d self=%p\n", str, fw_thread_id(), (void*) pthread_self().p);
293//#else
294 TRACE_MSG("*** ENTERING THREAD: %s, ID=%d self=%p\n", str, fw_thread_id(), (void*) ID_THREAD(pthread_self()));
295//#endif
296 }
297}