FreeWRL/FreeX3D  3.0.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 
57 static 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 
69 DEF_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
102 static int fw_once = 0;
103 #endif
104 void 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
161 void sync(){}
162 #endif
163 
164 
165 
166 
167 /* create consumer thread and set the "read only" flag indicating this */
168 void 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 
196 void 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 
220 int 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 
254 int 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 
265 void 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 
275 void 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 }