vtkMultiThreader.cxx 20.9 KB
Newer Older
Ken Martin's avatar
Ken Martin committed
1
2
3
4
5
6
7
8
9
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMultiThreader.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$


Ken Martin's avatar
Ken Martin committed
10
Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.
Ken Martin's avatar
Ken Martin committed
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.


=========================================================================*/
Lisa Avila's avatar
Lisa Avila committed
41
42
43
44
#include "vtkMultiThreader.h"

// These are the includes necessary for multithreaded rendering on an SGI
// using the sproc() call
Lisa Avila's avatar
Lisa Avila committed
45
#ifdef VTK_USE_SPROC
Lisa Avila's avatar
Lisa Avila committed
46
47
48
49
50
#include <sys/resource.h>
#include <sys/prctl.h>
#include <wait.h>
#endif

Lisa Avila's avatar
Lisa Avila committed
51
#ifdef VTK_USE_PTHREADS
Lisa Avila's avatar
Lisa Avila committed
52
53
54
#include <pthread.h>
#endif

Ken Martin's avatar
Ken Martin committed
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Initialize static member that controls global maximum number of threads
static int vtkMultiThreaderGlobalMaximumNumberOfThreads = 0;

void vtkMultiThreader::SetGlobalMaximumNumberOfThreads(int val)
{
  if (val == vtkMultiThreaderGlobalMaximumNumberOfThreads) return;
  vtkMultiThreaderGlobalMaximumNumberOfThreads = val;
}

int vtkMultiThreader::GetGlobalMaximumNumberOfThreads()
{
  return vtkMultiThreaderGlobalMaximumNumberOfThreads;
}

Lisa Avila's avatar
Lisa Avila committed
69
70
71
72
73
74
75
76
77
78
// Description:
// Constructor. Default all the methods to NULL. Since the
// ThreadInfoArray is static, the ThreadIDs can be initialized here
// and will not change.
vtkMultiThreader::vtkMultiThreader()
{
  int i;

  for ( i = 0; i < VTK_MAX_THREADS; i++ )
    {
79
80
81
82
83
84
85
    this->ThreadInfoArray[i].ThreadID           = i;
    this->ThreadInfoArray[i].ActiveFlag         = NULL;
    this->ThreadInfoArray[i].ActiveFlagLock     = NULL;
    this->MultipleMethod[i]                     = NULL;
    this->SpawnedThreadActiveFlag[i]            = 0;
    this->SpawnedThreadActiveFlagLock[i]        = NULL;
    this->SpawnedThreadInfoArray[i].ThreadID    = 0;
Lisa Avila's avatar
Lisa Avila committed
86
87
88
89
    }

  this->SingleMethod = NULL;

Lisa Avila's avatar
Lisa Avila committed
90
#ifdef VTK_USE_SPROC
Lisa Avila's avatar
Lisa Avila committed
91
92
  // Default the number of threads to be the number of available
  // processors if we are using sproc()
93
  this->NumberOfThreads             = prctl( PR_MAXPPROCS );
Lisa Avila's avatar
Lisa Avila committed
94
95
#endif

Lisa Avila's avatar
Lisa Avila committed
96
#ifdef VTK_USE_PTHREADS
Lisa Avila's avatar
Lisa Avila committed
97
98
  // Default the number of threads to be the number of available
  // processors if we are using pthreads()
Ken Martin's avatar
Ken Martin committed
99
#ifdef _SC_NPROCESSORS_ONLN
100
  this->NumberOfThreads             = sysconf( _SC_NPROCESSORS_ONLN );
Ken Martin's avatar
Ken Martin committed
101
102
103
#else
  this->NumberOfThreads             = 1;
#endif
Lisa Avila's avatar
Lisa Avila committed
104
105
#endif

Ken Martin's avatar
Ken Martin committed
106
107
108
109
#ifdef _WIN32
  {
    SYSTEM_INFO sysInfo;
    GetSystemInfo(&sysInfo);
110
    this->NumberOfThreads = sysInfo.dwNumberOfProcessors;
Ken Martin's avatar
Ken Martin committed
111
112
113
114
  }
#endif

#ifndef _WIN32
Lisa Avila's avatar
Lisa Avila committed
115
116
#ifndef VTK_USE_SPROC
#ifndef VTK_USE_PTHREADS
Lisa Avila's avatar
Lisa Avila committed
117
118
  // If we are not multithreading, the number of threads should
  // always be 1
119
  this->NumberOfThreads             = 1;
Lisa Avila's avatar
Lisa Avila committed
120
121
#endif  
#endif  
Ken Martin's avatar
Ken Martin committed
122
#endif
Lisa Avila's avatar
Lisa Avila committed
123
124
125
126
127
128
129
130
131
}

// Description:
// Destructor. Nothing allocated so nothing needs to be done here.
vtkMultiThreader::~vtkMultiThreader()
{
}

// Description:
132
// Set the user defined method that will be run on NumberOfThreads threads
Lisa Avila's avatar
Lisa Avila committed
133
// when SingleMethodExecute is called.
Ken Martin's avatar
Ken Martin committed
134
void vtkMultiThreader::SetSingleMethod( vtkThreadFunctionType f, 
Lisa Avila's avatar
Lisa Avila committed
135
136
137
138
139
140
141
					void *data )
{ 
  this->SingleMethod = f;
  this->SingleData   = data;
}

// Description:
142
// Set one of the user defined methods that will be run on NumberOfThreads
Lisa Avila's avatar
Lisa Avila committed
143
// threads when MultipleMethodExecute is called. This method should be
144
// called with index = 0, 1, ..,  NumberOfThreads-1 to set up all the
Lisa Avila's avatar
Lisa Avila committed
145
146
// required user defined methods
void vtkMultiThreader::SetMultipleMethod( int index, 
Ken Martin's avatar
Ken Martin committed
147
					  vtkThreadFunctionType f, void *data )
Lisa Avila's avatar
Lisa Avila committed
148
{ 
149
150
  // You can only set the method for 0 through NumberOfThreads-1
  if ( index >= this->NumberOfThreads ) {
Lisa Avila's avatar
Lisa Avila committed
151
    vtkErrorMacro( << "Can't set method " << index << 
152
    " with a thread count of " << this->NumberOfThreads );
Charles Law's avatar
Charles Law committed
153
    }
Lisa Avila's avatar
Lisa Avila committed
154
155
156
157
158
159
160
161
  else
    {
    this->MultipleMethod[index] = f;
    this->MultipleData[index]   = data;
    }
}

// Description:
162
// Execute the method set as the SingleMethod on NumberOfThreads threads.
Lisa Avila's avatar
Lisa Avila committed
163
164
165
void vtkMultiThreader::SingleMethodExecute()
{
  int                thread_loop;
Ken Martin's avatar
Ken Martin committed
166
167
168
169
170
171

#ifdef _WIN32
  DWORD              threadId;
  HANDLE             process_id[VTK_MAX_THREADS];
#endif

Lisa Avila's avatar
Lisa Avila committed
172
#ifdef VTK_USE_SPROC
Lisa Avila's avatar
Lisa Avila committed
173
174
175
176
  siginfo_t          info_ptr;
  int                process_id[VTK_MAX_THREADS];
#endif

Lisa Avila's avatar
Lisa Avila committed
177
#ifdef VTK_USE_PTHREADS
Lisa Avila's avatar
Lisa Avila committed
178
179
180
181
182
183
184
185
186
  pthread_t          process_id[VTK_MAX_THREADS];
#endif

  if ( !this->SingleMethod )
    {
    vtkErrorMacro( << "No single method set!" );
    return;
    }

Ken Martin's avatar
Ken Martin committed
187
188
189
190
191
192
193
194
  // obey the global maximum number of threads limit
  if (vtkMultiThreaderGlobalMaximumNumberOfThreads &&
      this->NumberOfThreads > vtkMultiThreaderGlobalMaximumNumberOfThreads)
    {
    this->NumberOfThreads = vtkMultiThreaderGlobalMaximumNumberOfThreads;
    }
  
    
Lisa Avila's avatar
Lisa Avila committed
195
196
197
  // We are using sproc (on SGIs), pthreads(on Suns), or a single thread
  // (the default)  

Ken Martin's avatar
Ken Martin committed
198
199
200
#ifdef _WIN32
  // Using CreateThread on a PC
  //
201
  // We want to use CreateThread to start this->NumberOfThreads - 1 
Ken Martin's avatar
Ken Martin committed
202
203
204
205
  // additional threads which will be used to call this->SingleMethod().
  // The parent thread will also call this routine.  When it is done,
  // it will wait for all the children to finish. 
  //
206
  // First, start up the this->NumberOfThreads-1 processes.  Keep track
Ken Martin's avatar
Ken Martin committed
207
  // of their process ids for use later in the waitid call
Ken Martin's avatar
Ken Martin committed
208
  for (thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Ken Martin's avatar
Ken Martin committed
209
210
    {
    this->ThreadInfoArray[thread_loop].UserData    = this->SingleData;
211
    this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
Ken Martin's avatar
Ken Martin committed
212
213
214
215
216
217
218
219
220
221
    process_id[thread_loop] = 
      CreateThread(NULL, 0, this->SingleMethod, 
	     ((void *)(&this->ThreadInfoArray[thread_loop])), 0, &threadId);
    if (process_id == NULL)
      {
      vtkErrorMacro("Error in thread creation !!!");
      } 
    }
  
  // Now, the parent thread calls this->SingleMethod() itself
Ken Martin's avatar
Ken Martin committed
222
223
224
  this->ThreadInfoArray[0].UserData = this->SingleData;
  this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
  this->SingleMethod((void *)(&this->ThreadInfoArray[0]));
Ken Martin's avatar
Ken Martin committed
225
226
227

  // The parent thread has finished this->SingleMethod() - so now it
  // waits for each of the other processes to exit
Ken Martin's avatar
Ken Martin committed
228
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Ken Martin's avatar
Ken Martin committed
229
230
231
232
233
    {
    WaitForSingleObject(process_id[thread_loop], INFINITE);
    }

  // close the threads
Ken Martin's avatar
Ken Martin committed
234
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Ken Martin's avatar
Ken Martin committed
235
236
237
238
239
    {
    CloseHandle(process_id[thread_loop]);
    }
#endif

Lisa Avila's avatar
Lisa Avila committed
240
#ifdef VTK_USE_SPROC
Lisa Avila's avatar
Lisa Avila committed
241
242
  // Using sproc() on an SGI
  //
243
  // We want to use sproc to start this->NumberOfThreads - 1 additional
Lisa Avila's avatar
Lisa Avila committed
244
245
246
247
  // threads which will be used to call this->SingleMethod(). The
  // parent thread will also call this routine.  When it is done,
  // it will wait for all the children to finish. 
  //
248
  // First, start up the this->NumberOfThreads-1 processes.  Keep track
Lisa Avila's avatar
Lisa Avila committed
249
  // of their process ids for use later in the waitid call
Ken Martin's avatar
Ken Martin committed
250
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Lisa Avila's avatar
Lisa Avila committed
251
252
    {
    this->ThreadInfoArray[thread_loop].UserData    = this->SingleData;
253
    this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
Lisa Avila's avatar
Lisa Avila committed
254
255
256
257
258
259
    process_id[thread_loop] = 
      sproc( this->SingleMethod, PR_SADDR, 
	     ( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
    }
  
  // Now, the parent thread calls this->SingleMethod() itself
Ken Martin's avatar
Ken Martin committed
260
261
262
  this->ThreadInfoArray[0].UserData = this->SingleData;
  this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
  this->SingleMethod((void *)(&this->ThreadInfoArray[0]) );
Lisa Avila's avatar
Lisa Avila committed
263
264
265

  // The parent thread has finished this->SingleMethod() - so now it
  // waits for each of the other processes to exit
Ken Martin's avatar
Ken Martin committed
266
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Lisa Avila's avatar
Lisa Avila committed
267
268
269
270
271
    {
    waitid( P_PID, (id_t) process_id[thread_loop], &info_ptr, WEXITED );
    }
#endif

Lisa Avila's avatar
Lisa Avila committed
272
#ifdef VTK_USE_PTHREADS
Lisa Avila's avatar
Lisa Avila committed
273
274
  // Using POSIX threads
  //
275
  // We want to use pthread_create to start this->NumberOfThreads-1 additional
Lisa Avila's avatar
Lisa Avila committed
276
277
278
279
  // threads which will be used to call this->SingleMethod(). The
  // parent thread will also call this routine.  When it is done,
  // it will wait for all the children to finish. 
  //
280
  // First, start up the this->NumberOfThreads-1 processes.  Keep track
Lisa Avila's avatar
Lisa Avila committed
281
282
  // of their process ids for use later in the pthread_join call

283
  pthread_attr_t attr;
Lisa Avila's avatar
Lisa Avila committed
284

Ken Martin's avatar
hp fix    
Ken Martin committed
285
286
287
#ifdef VTK_HP_PTHREADS
  pthread_attr_create( &attr );
#else  
288
289
  pthread_attr_init(&attr);
  pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
Ken Martin's avatar
hp fix    
Ken Martin committed
290
291
#endif
  
Ken Martin's avatar
Ken Martin committed
292
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Lisa Avila's avatar
Lisa Avila committed
293
294
    {
    this->ThreadInfoArray[thread_loop].UserData    = this->SingleData;
295
    this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
Ken Martin's avatar
hp fix    
Ken Martin committed
296
297

#ifdef VTK_HP_PTHREADS
Lisa Avila's avatar
Lisa Avila committed
298
    pthread_create( &(process_id[thread_loop]),
Ken Martin's avatar
hp fix    
Ken Martin committed
299
300
301
302
303
304
305
		    attr, this->SingleMethod,  
		    ( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
#else
    pthread_create( &(process_id[thread_loop]),
		    &attr, this->SingleMethod,  
		    ( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
#endif
Lisa Avila's avatar
Lisa Avila committed
306
307
308
    }
  
  // Now, the parent thread calls this->SingleMethod() itself
Ken Martin's avatar
Ken Martin committed
309
310
311
  this->ThreadInfoArray[0].UserData = this->SingleData;
  this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
  this->SingleMethod((void *)(&this->ThreadInfoArray[0]) );
Lisa Avila's avatar
Lisa Avila committed
312
313
314

  // The parent thread has finished this->SingleMethod() - so now it
  // waits for each of the other processes to exit
Ken Martin's avatar
Ken Martin committed
315
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Lisa Avila's avatar
Lisa Avila committed
316
317
318
319
320
    {
    pthread_join( process_id[thread_loop], NULL );
    }
#endif

Ken Martin's avatar
Ken Martin committed
321
#ifndef _WIN32
Lisa Avila's avatar
Lisa Avila committed
322
323
#ifndef VTK_USE_SPROC
#ifndef VTK_USE_PTHREADS
Lisa Avila's avatar
Lisa Avila committed
324
325
  // There is no multi threading, so there is only one thread.
  this->ThreadInfoArray[0].UserData    = this->SingleData;
326
  this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
Lisa Avila's avatar
Lisa Avila committed
327
328
329
  this->SingleMethod( (void *)(&this->ThreadInfoArray[0]) );
#endif
#endif
Ken Martin's avatar
Ken Martin committed
330
#endif
Lisa Avila's avatar
Lisa Avila committed
331
332
333
334
335
336
}

void vtkMultiThreader::MultipleMethodExecute()
{
  int                thread_loop;

Ken Martin's avatar
Ken Martin committed
337
338
339
340
341
#ifdef _WIN32
  DWORD              threadId;
  HANDLE             process_id[VTK_MAX_THREADS];
#endif

Lisa Avila's avatar
Lisa Avila committed
342
#ifdef VTK_USE_SPROC
Lisa Avila's avatar
Lisa Avila committed
343
344
345
346
  siginfo_t          info_ptr;
  int                process_id[VTK_MAX_THREADS];
#endif

Lisa Avila's avatar
Lisa Avila committed
347
#ifdef VTK_USE_PTHREADS
Lisa Avila's avatar
Lisa Avila committed
348
349
350
351
  pthread_t          process_id[VTK_MAX_THREADS];
#endif


Ken Martin's avatar
Ken Martin committed
352
353
354
355
356
357
358
  // obey the global maximum number of threads limit
  if (vtkMultiThreaderGlobalMaximumNumberOfThreads &&
      this->NumberOfThreads > vtkMultiThreaderGlobalMaximumNumberOfThreads)
    {
    this->NumberOfThreads = vtkMultiThreaderGlobalMaximumNumberOfThreads;
    }

359
  for ( thread_loop = 0; thread_loop < this->NumberOfThreads; thread_loop++ )
Ken Martin's avatar
hp fix    
Ken Martin committed
360
    if ( this->MultipleMethod[thread_loop] == (vtkThreadFunctionType)NULL)
Lisa Avila's avatar
Lisa Avila committed
361
362
363
364
365
      {
      vtkErrorMacro( << "No multiple method set for: " << thread_loop );
      return;
      }

Ken Martin's avatar
Ken Martin committed
366
367
368
369
370
371
  // We are using sproc (on SGIs), pthreads(on Suns), CreateThread
  // on a PC or a single thread (the default)  

#ifdef _WIN32
  // Using CreateThread on a PC
  //
372
373
  // We want to use CreateThread to start this->NumberOfThreads - 1 
  // additional threads which will be used to call the NumberOfThreads-1
Ken Martin's avatar
Ken Martin committed
374
  // methods defined in this->MultipleMethods[](). The parent thread
375
  // will call this->MultipleMethods[NumberOfThreads-1]().  When it is done,
Ken Martin's avatar
Ken Martin committed
376
377
  // it will wait for all the children to finish. 
  //
378
  // First, start up the this->NumberOfThreads-1 processes.  Keep track
Ken Martin's avatar
Ken Martin committed
379
  // of their process ids for use later in the waitid call
Ken Martin's avatar
Ken Martin committed
380
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Ken Martin's avatar
Ken Martin committed
381
382
383
    {
    this->ThreadInfoArray[thread_loop].UserData = 
      this->MultipleData[thread_loop];
384
    this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
Ken Martin's avatar
Ken Martin committed
385
386
387
388
389
390
391
392
393
394
    process_id[thread_loop] = 
      CreateThread(NULL, 0, this->MultipleMethod[thread_loop], 
	     ((void *)(&this->ThreadInfoArray[thread_loop])), 0, &threadId);
    if (process_id == NULL)
      {
      vtkErrorMacro("Error in thread creation !!!");
      } 
    }
  
  // Now, the parent thread calls the last method itself
Ken Martin's avatar
Ken Martin committed
395
396
397
  this->ThreadInfoArray[0].UserData = this->MultipleData[0];
  this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
  (this->MultipleMethod[0])((void *)(&this->ThreadInfoArray[0]) );
Lisa Avila's avatar
Lisa Avila committed
398

Ken Martin's avatar
Ken Martin committed
399
400
401
  // The parent thread has finished its method - so now it
  // waits for each of the other processes (created with sproc) to
  // exit
Ken Martin's avatar
Ken Martin committed
402
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Ken Martin's avatar
Ken Martin committed
403
404
405
406
407
    {
    WaitForSingleObject(process_id[thread_loop], INFINITE);
    }

  // close the threads
Ken Martin's avatar
Ken Martin committed
408
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Ken Martin's avatar
Ken Martin committed
409
410
411
412
413
    {
    CloseHandle(process_id[thread_loop]);
    }
#endif

Lisa Avila's avatar
Lisa Avila committed
414
#ifdef VTK_USE_SPROC
Lisa Avila's avatar
Lisa Avila committed
415
416
  // Using sproc() on an SGI
  //
417
418
  // We want to use sproc to start this->NumberOfThreads - 1 additional
  // threads which will be used to call the NumberOfThreads-1 methods
Lisa Avila's avatar
Lisa Avila committed
419
  // defined in this->MultipleMethods[](). The parent thread
420
  // will call this->MultipleMethods[NumberOfThreads-1]().  When it is done,
Lisa Avila's avatar
Lisa Avila committed
421
422
  // it will wait for all the children to finish. 
  //
423
  // First, start up the this->NumberOfThreads-1 processes.  Keep track
Lisa Avila's avatar
Lisa Avila committed
424
  // of their process ids for use later in the waitid call
Ken Martin's avatar
Ken Martin committed
425
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Lisa Avila's avatar
Lisa Avila committed
426
427
428
    {
    this->ThreadInfoArray[thread_loop].UserData = 
      this->MultipleData[thread_loop];
429
    this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
Lisa Avila's avatar
Lisa Avila committed
430
431
432
433
434
435
    process_id[thread_loop] = 
      sproc( this->MultipleMethod[thread_loop], PR_SADDR, 
	     ( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
    }
  
  // Now, the parent thread calls the last method itself
Ken Martin's avatar
Ken Martin committed
436
437
438
  this->ThreadInfoArray[0].UserData = this->MultipleData[0];
  this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
  (this->MultipleMethod[0])((void *)(&this->ThreadInfoArray[0]) );
Lisa Avila's avatar
Lisa Avila committed
439
440
441
442

  // The parent thread has finished its method - so now it
  // waits for each of the other processes (created with sproc) to
  // exit
Ken Martin's avatar
Ken Martin committed
443
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Lisa Avila's avatar
Lisa Avila committed
444
445
446
447
448
    {
    waitid( P_PID, (id_t) process_id[thread_loop], &info_ptr, WEXITED );
    }
#endif

Lisa Avila's avatar
Lisa Avila committed
449
#ifdef VTK_USE_PTHREADS
Lisa Avila's avatar
Lisa Avila committed
450
451
  // Using POSIX threads
  //
452
453
454
  // We want to use pthread_create to start this->NumberOfThreads - 1 
  // additional
  // threads which will be used to call the NumberOfThreads-1 methods
Lisa Avila's avatar
Lisa Avila committed
455
  // defined in this->MultipleMethods[](). The parent thread
456
  // will call this->MultipleMethods[NumberOfThreads-1]().  When it is done,
Lisa Avila's avatar
Lisa Avila committed
457
458
  // it will wait for all the children to finish. 
  //
459
  // First, start up the this->NumberOfThreads-1 processes.  Keep track
Lisa Avila's avatar
Lisa Avila committed
460
  // of their process ids for use later in the pthread_join call
Ken Martin's avatar
hp fix    
Ken Martin committed
461
462
463
464
465
466
467
468
469
470

  pthread_attr_t attr;

#ifdef VTK_HP_PTHREADS
  pthread_attr_create( &attr );
#else  
  pthread_attr_init(&attr);
  pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
#endif

Ken Martin's avatar
Ken Martin committed
471
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Lisa Avila's avatar
Lisa Avila committed
472
473
474
    {
    this->ThreadInfoArray[thread_loop].UserData = 
      this->MultipleData[thread_loop];
475
    this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
Ken Martin's avatar
hp fix    
Ken Martin committed
476
477
478
479
480
#ifdef VTK_HP_PTHREADS
    pthread_create( &(process_id[thread_loop]),
		    attr, this->MultipleMethod[thread_loop],  
		    ( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
#else
Lisa Avila's avatar
Lisa Avila committed
481
    pthread_create( &(process_id[thread_loop]),
Ken Martin's avatar
hp fix    
Ken Martin committed
482
483
484
		    &attr, this->MultipleMethod[thread_loop],  
		    ( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
#endif
Lisa Avila's avatar
Lisa Avila committed
485
486
487
    }
  
  // Now, the parent thread calls the last method itself
Ken Martin's avatar
Ken Martin committed
488
489
490
  this->ThreadInfoArray[0].UserData = this->MultipleData[0];
  this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
  (this->MultipleMethod[0])((void *)(&this->ThreadInfoArray[0]) );
Lisa Avila's avatar
Lisa Avila committed
491
492
493

  // The parent thread has finished its method - so now it
  // waits for each of the other processes to exit
Ken Martin's avatar
Ken Martin committed
494
  for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
Lisa Avila's avatar
Lisa Avila committed
495
496
497
498
499
    {
    pthread_join( process_id[thread_loop], NULL );
    }
#endif

Ken Martin's avatar
Ken Martin committed
500
#ifndef _WIN32
Lisa Avila's avatar
Lisa Avila committed
501
502
#ifndef VTK_USE_SPROC
#ifndef VTK_USE_PTHREADS
Lisa Avila's avatar
Lisa Avila committed
503
504
  // There is no multi threading, so there is only one thread.
  this->ThreadInfoArray[0].UserData    = this->MultipleData[0];
505
  this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
Lisa Avila's avatar
Lisa Avila committed
506
507
508
  (this->MultipleMethod[0])( (void *)(&this->ThreadInfoArray[0]) );
#endif
#endif
Ken Martin's avatar
Ken Martin committed
509
#endif
Lisa Avila's avatar
Lisa Avila committed
510
511
}

512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
int vtkMultiThreader::SpawnThread( vtkThreadFunctionType f, void *UserData )
{
  int id;

#ifdef _WIN32
  DWORD              threadId;
#endif

  id = 0;

  while ( id < VTK_MAX_THREADS )
    {
    if ( this->SpawnedThreadActiveFlagLock[id] == NULL ) break;
    id++;
    }

  if ( id >= VTK_MAX_THREADS )
    {
    vtkErrorMacro( << "You have too many active threads!" );
    return -1;
    }

  this->SpawnedThreadActiveFlagLock[id] = vtkMutexFunctionLock::New();
  vtkMutexLockFuncMacro(this->SpawnedThreadActiveFlagLock[id],this->SpawnedThreadActiveFlag[id]=1);

  this->SpawnedThreadInfoArray[id].UserData        = UserData;
  this->SpawnedThreadInfoArray[id].NumberOfThreads = 1;
  this->SpawnedThreadInfoArray[id].ActiveFlag = 
    &this->SpawnedThreadActiveFlag[id];
  this->SpawnedThreadInfoArray[id].ActiveFlagLock = 
    this->SpawnedThreadActiveFlagLock[id];

  // We are using sproc (on SGIs), pthreads(on Suns or HPs), 
  // CreateThread (on win32), or generating an error  

#ifdef _WIN32
  // Using CreateThread on a PC
  //
  this->SpawnedThreadProcessID[id] = 
      CreateThread(NULL, 0, f, 
	     ((void *)(&this->SpawnedThreadInfoArray[id])), 0, &threadId);
  if (this->SpawnedThreadProcessID[id] == NULL)
    {
    vtkErrorMacro("Error in thread creation !!!");
    } 
#endif

#ifdef VTK_USE_SPROC
  // Using sproc() on an SGI
  //
  this->SpawnedThreadProcessID[id] = 
    sproc( f, PR_SADDR, ( (void *)(&this->SpawnedThreadInfoArray[id]) ) );

#endif

#ifdef VTK_USE_PTHREADS
  // Using POSIX threads
  //
  pthread_attr_t attr;

#ifdef VTK_HP_PTHREADS
  pthread_attr_create( &attr );
#else  
  pthread_attr_init(&attr);
  pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
#endif
  
#ifdef VTK_HP_PTHREADS
  pthread_create( &(this->SpawnedThreadProcessID[id]),
		  attr, f,  
		  ( (void *)(&this->SpawnedThreadInfoArray[id]) ) );
#else
  pthread_create( &(this->SpawnedThreadProcessID[id]),
		  &attr, f,  
		  ( (void *)(&this->SpawnedThreadInfoArray[id]) ) );
#endif

#endif

#ifndef _WIN32
#ifndef VTK_USE_SPROC
#ifndef VTK_USE_PTHREADS
  // There is no multi threading, so there is only one thread.
  // This won't work - so give an error message.
  vtkErrorMacro( << "Cannot spawn thread in a single threaded environment!" );
  this->SpawnedThreadActiveFlagLock[id]->Delete();
  id = -1;
#endif
#endif
#endif

  return id;
}

void vtkMultiThreader::TerminateThread( int ThreadID )
{

  if ( !this->SpawnedThreadActiveFlag[ThreadID] ) {
    return;
  }

  vtkMutexLockFuncMacro(this->SpawnedThreadActiveFlagLock[ThreadID],this->SpawnedThreadActiveFlag[ThreadID]=0);


#ifdef _WIN32
  WaitForSingleObject(this->SpawnedThreadProcessID[ThreadID], INFINITE);
  CloseHandle(this->SpawnedThreadProcessID[ThreadID]);
#endif

#ifdef VTK_USE_SPROC
  siginfo_t info_ptr;

  waitid( P_PID, (id_t) this->SpawnedThreadProcessID[ThreadID], 
	  &info_ptr, WEXITED );
#endif

#ifdef VTK_USE_PTHREADS
  pthread_join( this->SpawnedThreadProcessID[ThreadID], NULL );
#endif

#ifndef _WIN32
#ifndef VTK_USE_SPROC
#ifndef VTK_USE_PTHREADS
  // There is no multi threading, so there is only one thread.
  // This won't work - so give an error message.
  vtkErrorMacro(<< "Cannot terminate thread in single threaded environment!");
#endif
#endif
#endif

  this->SpawnedThreadActiveFlagLock[ThreadID]->Delete();

}

Lisa Avila's avatar
Lisa Avila committed
646
647
648
649
650
// Description:
// Print method for the multithreader
void vtkMultiThreader::PrintSelf(ostream& os, vtkIndent indent)
{
  
651
  os << indent << "Thread Count: " << this->NumberOfThreads << "\n";
Ken Martin's avatar
Ken Martin committed
652
653
  os << indent << "Global Maximum Number Of Threads: " << 
    vtkMultiThreaderGlobalMaximumNumberOfThreads << endl;
Lisa Avila's avatar
Lisa Avila committed
654
655

}