GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/air/threadAir.c Lines: 0 56 0.0 %
Date: 2017-05-26 Branches: 0 24 0.0 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "air.h"
25
26
/* HEY: the whole matter of function returns has to be standardized. */
27
28
int airThreadNoopWarning = AIR_TRUE;
29
30
/* ------------------------------------------------------------------ */
31
#if TEEM_PTHREAD /* ----------------------------------------- PTHREAD */
32
/* ------------------------------------------------------------------ */
33
34
#include <pthread.h>
35
36
const int airThreadCapable = AIR_TRUE;
37
38
struct _airThread {
39
  pthread_t id;
40
};
41
42
struct _airThreadMutex {
43
  pthread_mutex_t id;
44
};
45
46
struct _airThreadCond {
47
  pthread_cond_t id;
48
};
49
50
airThread *
51
airThreadNew(void) {
52
  airThread *thread;
53
54
  thread = AIR_CALLOC(1, airThread);
55
  /* HEY: not sure if this can be usefully initialized */
56
  return thread;
57
}
58
59
int
60
airThreadStart(airThread *thread, void *(*threadBody)(void *), void *arg) {
61
  pthread_attr_t attr;
62
63
  pthread_attr_init(&attr);
64
#ifdef __sgi
65
  pthread_attr_setscope(&attr, PTHREAD_SCOPE_BOUND_NP);
66
#endif
67
  return pthread_create(&(thread->id), &attr, threadBody, arg);
68
}
69
70
int
71
airThreadJoin(airThread *thread, void **retP) {
72
73
  return pthread_join(thread->id, retP);
74
}
75
76
airThread *
77
airThreadNix(airThread *thread) {
78
79
  airFree(thread);
80
  return NULL;
81
}
82
83
airThreadMutex *
84
airThreadMutexNew(void) {
85
  airThreadMutex *mutex;
86
87
  mutex = AIR_CALLOC(1, airThreadMutex);
88
  if (mutex) {
89
    if (pthread_mutex_init(&(mutex->id), NULL)) {
90
      mutex = (airThreadMutex *)airFree(mutex);
91
    }
92
  }
93
  return mutex;
94
}
95
96
int
97
airThreadMutexLock(airThreadMutex *mutex) {
98
99
  return pthread_mutex_lock(&(mutex->id));
100
}
101
102
int
103
airThreadMutexUnlock(airThreadMutex *mutex) {
104
105
  return pthread_mutex_unlock(&(mutex->id));
106
}
107
108
airThreadMutex *
109
airThreadMutexNix(airThreadMutex *mutex) {
110
111
  if (mutex) {
112
    if (!pthread_mutex_destroy(&(mutex->id))) {
113
      /* there was no error */
114
      mutex = (airThreadMutex *)airFree(mutex);
115
    }
116
  }
117
  return mutex;
118
}
119
120
airThreadCond *
121
airThreadCondNew(void) {
122
  airThreadCond *cond;
123
124
  cond = AIR_CALLOC(1, airThreadCond);
125
  if (cond) {
126
    if (pthread_cond_init(&(cond->id), NULL)) {
127
      /* there was an error */
128
      cond = (airThreadCond *)airFree(cond);
129
    }
130
  }
131
  return cond;
132
}
133
134
int
135
airThreadCondWait(airThreadCond *cond, airThreadMutex *mutex) {
136
137
  return pthread_cond_wait(&(cond->id), &(mutex->id));
138
}
139
140
int
141
airThreadCondSignal(airThreadCond *cond) {
142
143
  return pthread_cond_signal(&(cond->id));
144
}
145
146
int
147
airThreadCondBroadcast(airThreadCond *cond) {
148
149
  return pthread_cond_broadcast(&(cond->id));
150
}
151
152
airThreadCond *
153
airThreadCondNix(airThreadCond *cond) {
154
155
  if (cond) {
156
    if (!pthread_cond_destroy(&(cond->id))) {
157
      /* there was no error */
158
      cond = (airThreadCond *)airFree(cond);
159
    }
160
  }
161
  return cond;
162
}
163
164
/* ------------------------------------------------------------------ */
165
#elif defined(_WIN32) /* ------------------------------------- WIN 32 */
166
/* ------------------------------------------------------------------ */
167
168
#if defined(_WIN32)
169
   /* SignalObjectAndWait supported by NT4.0 and greater only */
170
#  define _WIN32_WINNT 0x400
171
#  include <windows.h>
172
#endif
173
174
const int airThreadCapable = AIR_TRUE;
175
176
struct _airThread {
177
  HANDLE handle;
178
  void *(*body)(void *);
179
  void *arg;
180
  void *ret;
181
};
182
183
struct _airThreadMutex {
184
  HANDLE handle;
185
};
186
187
struct _airThreadCond {
188
  int count;
189
  CRITICAL_SECTION lock;
190
  HANDLE sema;
191
  HANDLE done;
192
  size_t broadcast;
193
};
194
195
airThread *
196
airThreadNew(void) {
197
  airThread *thread;
198
199
  thread = AIR_CALLOC(1, airThread);
200
  /* HEY: any useful way to initialized a HANDLE? */
201
  thread->handle = NULL;
202
  thread->body = NULL;
203
  thread->arg = thread->ret = NULL;
204
  return thread;
205
}
206
207
#if defined(__BORLANDC__)
208
unsigned long
209
#else
210
int
211
#endif /* defined(__BORLANDC__) */
212
WINAPI _airThreadWin32Body(void *_thread) {
213
  airThread *thread;
214
215
  thread = (airThread *)_thread;
216
  thread->ret = thread->body(thread->arg);
217
  return 0;
218
}
219
220
int
221
airThreadStart(airThread *thread, void *(*threadBody)(void *), void *arg) {
222
223
  thread->body = threadBody;
224
  thread->arg = arg;
225
  thread->handle = CreateThread(0, 0, _airThreadWin32Body,
226
                                (void *)thread, 0, 0);
227
  return NULL == thread->handle;
228
}
229
230
int
231
airThreadJoin(airThread *thread, void **retP) {
232
  int err;
233
234
  err = (WAIT_FAILED == WaitForSingleObject(thread->handle, INFINITE));
235
  *retP = thread->ret;
236
  return err;
237
}
238
239
airThread *
240
airThreadNix(airThread *_thread) {
241
  char me[] = "airThreadNix";
242
243
  if (0 == CloseHandle(_thread->handle)) {
244
    fprintf(stderr, "%s: CloseHandle failed, something is wrong\n", me);
245
  }
246
  return airFree(_thread);
247
}
248
249
airThreadMutex *
250
airThreadMutexNew() {
251
  airThreadMutex *mutex;
252
253
  mutex = AIR_CALLOC(1, airThreadMutex);
254
  if (mutex) {
255
    if (!(mutex->handle = CreateMutex(NULL, FALSE, NULL))) {
256
      return airFree(mutex);
257
    }
258
  }
259
  return mutex;
260
}
261
262
int
263
airThreadMutexLock(airThreadMutex *mutex) {
264
265
  return WAIT_FAILED == WaitForSingleObject(mutex->handle, INFINITE);
266
}
267
268
int
269
airThreadMutexUnlock(airThreadMutex *mutex) {
270
271
  return 0 == ReleaseMutex(mutex->handle);
272
}
273
274
airThreadMutex *
275
airThreadMutexNix(airThreadMutex *mutex) {
276
277
  CloseHandle(mutex->handle);
278
  mutex = airFree(mutex);
279
  return mutex;
280
}
281
282
airThreadCond *
283
airThreadCondNew(void) {
284
  airThreadCond *cond;
285
286
  cond = AIR_CALLOC(1, airThreadCond);
287
  if (cond) {
288
    cond->count = 0;
289
    cond->broadcast = 0;
290
    cond->sema = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
291
    if (NULL == cond->sema) {
292
      return airFree(cond);
293
    }
294
    InitializeCriticalSection(&(cond->lock));
295
    cond->done = CreateEvent(NULL, FALSE, FALSE, NULL);
296
    if (NULL == cond->done) {
297
      CloseHandle(cond->sema);
298
      return airFree(cond);
299
    }
300
  }
301
  return cond;
302
}
303
304
int
305
airThreadCondWait(airThreadCond *cond, airThreadMutex *mutex) {
306
  int last;
307
308
  /* increment count */
309
  EnterCriticalSection(&(cond->lock)); /* avoid race conditions */
310
  cond->count++;
311
  LeaveCriticalSection(&(cond->lock));
312
  /* atomically release the mutex and wait on the
313
     semaphore until airThreadCondSignal or airThreadCondBroadcast
314
     are called by another thread */
315
  if (WAIT_FAILED == SignalObjectAndWait(mutex->handle, cond->sema,
316
                                         INFINITE, FALSE)) {
317
    return 1;
318
  }
319
  /* reacquire lock to avoid race conditions */
320
  EnterCriticalSection(&(cond->lock));
321
  /* we're no longer waiting... */
322
  cond->count--;
323
  /* check to see if we're the last waiter after airThreadCondBroadcast */
324
  last = (cond->broadcast && 0 == cond->count);
325
  LeaveCriticalSection(&(cond->lock));
326
  /* if we're the last waiter thread during this particular broadcast
327
     then let all the other threads proceed */
328
  if (last) {
329
    /* atomically signal the done event and waits until
330
       we can acquire the mutex (this is required to ensure fairness) */
331
    if (WAIT_FAILED == SignalObjectAndWait(cond->done, mutex->handle,
332
                                           INFINITE, FALSE)) {
333
      return 1;
334
    }
335
  } else {
336
    /* regain the external mutex since that's the guarantee to our callers */
337
    if (WAIT_FAILED == WaitForSingleObject(mutex->handle, INFINITE)) {
338
      return 1;
339
    }
340
  }
341
  return 0;
342
}
343
344
int
345
airThreadCondSignal(airThreadCond *cond) {
346
  int waiters;
347
348
  EnterCriticalSection(&(cond->lock));
349
  waiters = cond->count > 0;
350
  LeaveCriticalSection(&(cond->lock));
351
  /* if there aren't any waiters, then this is a no-op */
352
  if (waiters) {
353
    if (0 == ReleaseSemaphore(cond->sema, 1, NULL)) {
354
      return 1;
355
    }
356
  }
357
  return 0;
358
}
359
360
int
361
airThreadCondBroadcast(airThreadCond *cond) {
362
  int waiters;
363
364
  /* need to ensure that cond->count and cond->broadcast are consistent */
365
  EnterCriticalSection(&(cond->lock));
366
  waiters = 0;
367
  if (cond->count > 0) {
368
    /* we are broadcasting, even if there is just one waiter...
369
       record that we are broadcasting, which helps optimize
370
       airThreadCondWait for the non-broadcast case */
371
    cond->broadcast = 1;
372
    waiters = 1;
373
  }
374
  if (waiters) {
375
    /* wake up all the waiters atomically */
376
    if (0 == ReleaseSemaphore(cond->sema, cond->count, 0)) {
377
      return 1;
378
    }
379
    LeaveCriticalSection(&(cond->lock));
380
    /* wait for all the awakened threads to acquire the counting semaphore */
381
    if (WAIT_FAILED == WaitForSingleObject(cond->done, INFINITE)) {
382
      return 1;
383
    }
384
    /* this assignment is okay, even without the lock held
385
       because no other waiter threads can wake up to access it */
386
    cond->broadcast = 0;
387
  } else {
388
    LeaveCriticalSection(&(cond->lock));
389
  }
390
  return 0;
391
}
392
393
airThreadCond *
394
airThreadCondNix(airThreadCond *cond) {
395
  airThreadCond *ret=NULL;
396
397
  if (cond) {
398
    cond->count = 0;
399
    cond->broadcast = 0;
400
    if (0 == CloseHandle(cond->done)) {
401
      ret = cond;
402
    }
403
    DeleteCriticalSection(&(cond->lock));
404
    if (0 == CloseHandle(cond->sema)) {
405
      ret = cond;
406
    }
407
    ret = airFree(cond);
408
  }
409
  return ret;
410
}
411
412
/* ------------------------------------------------------------------ */
413
#else /* --------------------------------------- (no multi-threading) */
414
/* ------------------------------------------------------------------ */
415
416
const int airThreadCapable = AIR_FALSE;
417
418
struct _airThread {
419
  void *ret;
420
};
421
422
struct _airThreadMutex {
423
  int dummy;
424
};
425
426
struct _airThreadCond {
427
  int dummy;
428
};
429
430
airThread *
431
airThreadNew(void) {
432
  airThread *thread;
433
434
  thread = AIR_CALLOC(1, airThread);
435
  thread->ret = NULL;
436
  return thread;
437
}
438
439
int
440
airThreadStart(airThread *thread, void *(*threadBody)(void *), void *arg) {
441
442
  /* run the threadBody callback, which will return only when the
443
     task has decided to call it quits */
444
  thread->ret = (*threadBody)(arg);
445
  return 0;
446
}
447
448
int
449
airThreadJoin(airThread *thread, void **retP) {
450
451
  *retP = thread->ret;
452
  return 0;
453
}
454
455
airThread *
456
airThreadNix(airThread *thread) {
457
458
  airFree(thread);
459
  return NULL;
460
}
461
462
airThreadMutex *
463
airThreadMutexNew(void) {
464
  airThreadMutex *mutex;
465
466
  mutex = AIR_CALLOC(1, airThreadMutex);
467
  return mutex;
468
}
469
470
int
471
airThreadMutexLock(airThreadMutex *mutex) {
472
  char me[]="airThreadMutexLock";
473
474
  AIR_UNUSED(mutex);
475
  if (airThreadNoopWarning) {
476
    fprintf(stderr, "%s: WARNING: all mutex usage is a no-op!\n", me);
477
  }
478
  return 0;
479
}
480
481
int
482
airThreadMutexUnlock(airThreadMutex *mutex) {
483
  char me[]="airThreadMutexUnlock";
484
485
  AIR_UNUSED(mutex);
486
  if (airThreadNoopWarning) {
487
    fprintf(stderr, "%s: WARNING: all mutex usage is a no-op!\n", me);
488
  }
489
  return 0;
490
}
491
492
airThreadMutex *
493
airThreadMutexNix(airThreadMutex *mutex) {
494
495
  airFree(mutex);
496
  return NULL;
497
}
498
499
airThreadCond *
500
airThreadCondNew(void) {
501
  airThreadCond *cond;
502
503
  cond = AIR_CALLOC(1, airThreadCond);
504
  return cond;
505
}
506
507
int
508
airThreadCondWait(airThreadCond *cond, airThreadMutex *mutex) {
509
  char me[]="airThreadCondWait";
510
511
  AIR_UNUSED(cond);
512
  AIR_UNUSED(mutex);
513
  if (airThreadNoopWarning) {
514
    fprintf(stderr, "%s: WARNING: all cond usage is a no-op!\n", me);
515
  }
516
  return 0;
517
}
518
519
int
520
airThreadCondSignal(airThreadCond *cond) {
521
  char me[]="airThreadCondSignal";
522
523
  AIR_UNUSED(cond);
524
  if (airThreadNoopWarning) {
525
    fprintf(stderr, "%s: WARNING: all cond usage is a no-op!\n", me);
526
  }
527
  return 0;
528
}
529
530
int
531
airThreadCondBroadcast(airThreadCond *cond) {
532
  char me[]="airThreadCondBroadcast";
533
534
  AIR_UNUSED(cond);
535
  if (airThreadNoopWarning) {
536
    fprintf(stderr, "%s: WARNING: all cond usage is a no-op!\n", me);
537
  }
538
  return 0;
539
}
540
541
airThreadCond *
542
airThreadCondNix(airThreadCond *cond) {
543
544
  airFree(cond);
545
  return NULL;
546
}
547
548
/* ------------------------------------------------------------------ */
549
#endif /* ----------------------------------------------------------- */
550
/* ------------------------------------------------------------------ */
551
552
airThreadBarrier *
553
airThreadBarrierNew(unsigned int numUsers) {
554
  airThreadBarrier *barrier;
555
556
  barrier = AIR_CALLOC(1, airThreadBarrier);
557
  if (barrier) {
558
    barrier->numUsers = numUsers;
559
    barrier->numDone = 0;
560
    if (!(barrier->doneMutex = airThreadMutexNew())) {
561
      airFree(barrier);
562
      return NULL;
563
    }
564
    if (!(barrier->doneCond = airThreadCondNew())) {
565
      barrier->doneMutex = airThreadMutexNix(barrier->doneMutex);
566
      airFree(barrier);
567
      return NULL;
568
    }
569
  }
570
  return barrier;
571
}
572
573
int
574
airThreadBarrierWait(airThreadBarrier *barrier) {
575
576
  airThreadMutexLock(barrier->doneMutex);
577
  barrier->numDone += 1;
578
  if (barrier->numDone < barrier->numUsers) {
579
    airThreadCondWait(barrier->doneCond, barrier->doneMutex);
580
  } else {
581
    barrier->numDone = 0;
582
    airThreadCondBroadcast(barrier->doneCond);
583
  }
584
  airThreadMutexUnlock(barrier->doneMutex);
585
  return 0;
586
}
587
588
airThreadBarrier *
589
airThreadBarrierNix(airThreadBarrier *barrier) {
590
591
  barrier->doneMutex = airThreadMutexNix(barrier->doneMutex);
592
  barrier->doneCond = airThreadCondNix(barrier->doneCond);
593
  airFree(barrier);
594
  return NULL;
595
}