00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdafx.h"
00027 #include "parallel.h"
00028 #include "memory.h"
00029 #ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH
00030 #include <dispatch/dispatch.h>
00031 #endif // PBRT_USE_GRAND_CENTRAL_DISPATCH
00032 #if !defined(PBRT_IS_WINDOWS)
00033 #include <fcntl.h>
00034 #include <unistd.h>
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 #include <sys/param.h>
00038 #include <sys/sysctl.h>
00039 #include <errno.h>
00040 #endif
00041 #include <list>
00042
00043
00044 #if defined(PBRT_IS_WINDOWS)
00045 static HANDLE *threads;
00046 #elif !defined(PBRT_USE_GRAND_CENTRAL_DISPATCH)
00047 static pthread_t *threads;
00048 #endif
00049 #ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH
00050 static dispatch_queue_t gcdQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
00051 static dispatch_group_t gcdGroup = dispatch_group_create();
00052 #else
00053 static Mutex *taskQueueMutex = Mutex::Create();
00054 static std::vector<Task *> taskQueue;
00055 #endif // PBRT_USE_GRAND_CENTRAL_DISPATCH
00056 #ifndef PBRT_USE_GRAND_CENTRAL_DISPATCH
00057 static Semaphore *workerSemaphore;
00058 static uint32_t numUnfinishedTasks;
00059 static ConditionVariable *tasksRunningCondition;
00060 #endif // PBRT_USE_GRAND_CENTRAL_DISPATCH
00061 #ifndef PBRT_USE_GRAND_CENTRAL_DISPATCH
00062 static
00063 #if defined(PBRT_IS_WINDOWS)
00064 DWORD WINAPI taskEntry(LPVOID arg);
00065 #else
00066 void *taskEntry(void *arg);
00067 #endif
00068 #endif // !PBRT_USE_GRAND_CENTRAL_DISPATCH
00069
00070
00071 #if !defined(PBRT_IS_WINDOWS)
00072
00073 Mutex *Mutex::Create() {
00074 int sz = sizeof(Mutex);
00075 sz = (sz + (PBRT_L1_CACHE_LINE_SIZE-1)) & ~(PBRT_L1_CACHE_LINE_SIZE-1);
00076 return new (AllocAligned(sz)) Mutex;
00077 }
00078
00079
00080
00081 void Mutex::Destroy(Mutex *m) {
00082 m->~Mutex();
00083 FreeAligned(m);
00084 }
00085
00086
00087
00088 Mutex::Mutex() {
00089 int err;
00090 if ((err = pthread_mutex_init(&mutex, NULL)) != 0)
00091 Severe("Error from pthread_mutex_init: %s", strerror(err));
00092 }
00093
00094
00095
00096 Mutex::~Mutex() {
00097 int err;
00098 if ((err = pthread_mutex_destroy(&mutex)) != 0)
00099 Severe("Error from pthread_mutex_destroy: %s", strerror(err));
00100 }
00101
00102
00103
00104
00105 MutexLock::MutexLock(Mutex &m) : mutex(m) {
00106 int err;
00107 if ((err = pthread_mutex_lock(&m.mutex)) != 0)
00108 Severe("Error from pthread_mutex_lock: %s", strerror(err));
00109 }
00110
00111
00112
00113 MutexLock::~MutexLock() {
00114 int err;
00115 if ((err = pthread_mutex_unlock(&mutex.mutex)) != 0)
00116 Severe("Error from pthread_mutex_unlock: %s", strerror(err));
00117 }
00118
00119
00120
00121
00122 RWMutex *RWMutex::Create() {
00123 int sz = sizeof(RWMutex);
00124 sz = (sz + (PBRT_L1_CACHE_LINE_SIZE-1)) & ~(PBRT_L1_CACHE_LINE_SIZE-1);
00125 return new (AllocAligned(sz)) RWMutex;
00126 }
00127
00128
00129
00130 void RWMutex::Destroy(RWMutex *m) {
00131 m->~RWMutex();
00132 FreeAligned(m);
00133 }
00134
00135
00136
00137 RWMutex::RWMutex() {
00138 int err;
00139 if ((err = pthread_rwlock_init(&mutex, NULL)) != 0)
00140 Severe("Error from pthread_rwlock_init: %s", strerror(err));
00141 }
00142
00143
00144
00145 RWMutex::~RWMutex() {
00146 int err;
00147 if ((err = pthread_rwlock_destroy(&mutex)) != 0)
00148 Severe("Error from pthread_rwlock_destroy: %s", strerror(err));
00149 }
00150
00151
00152
00153
00154 RWMutexLock::RWMutexLock(RWMutex &m, RWMutexLockType t) : type(t), mutex(m) {
00155 int err;
00156 if (t == READ) err = pthread_rwlock_rdlock(&m.mutex);
00157 else err = pthread_rwlock_wrlock(&m.mutex);
00158 }
00159
00160
00161
00162 RWMutexLock::~RWMutexLock() {
00163 int err;
00164 if ((err = pthread_rwlock_unlock(&mutex.mutex)) != 0)
00165 Severe("Error from pthread_rwlock_unlock: %s", strerror(err));
00166 }
00167
00168
00169
00170 void RWMutexLock::UpgradeToWrite() {
00171 Assert(type == READ);
00172 int err;
00173 if ((err = pthread_rwlock_unlock(&mutex.mutex)) != 0)
00174 Severe("Error from pthread_rwlock_unlock: %s", strerror(err));
00175 if ((err = pthread_rwlock_wrlock(&mutex.mutex)) != 0)
00176 Severe("Error from pthread_rwlock_wrlock: %s", strerror(err));
00177 type = WRITE;
00178 }
00179
00180
00181
00182 void RWMutexLock::DowngradeToRead() {
00183 Assert(type == WRITE);
00184 int err;
00185 if ((err = pthread_rwlock_unlock(&mutex.mutex)) != 0)
00186 Severe("Error from pthread_rwlock_unlock: %s", strerror(err));
00187 if ((err = pthread_rwlock_rdlock(&mutex.mutex)) != 0)
00188 Severe("Error from pthread_rwlock_rdlock: %s", strerror(err));
00189 type = READ;
00190 }
00191
00192
00193 #endif // !PBRT_IS_WINDOWS
00194 #if defined(PBRT_IS_WINDOWS)
00195
00196 Mutex *Mutex::Create() {
00197 return new Mutex;
00198 }
00199
00200
00201
00202 void Mutex::Destroy(Mutex *m) {
00203 delete m;
00204 }
00205
00206
00207
00208 Mutex::Mutex() {
00209 InitializeCriticalSection(&criticalSection);
00210 }
00211
00212
00213
00214 Mutex::~Mutex() {
00215 DeleteCriticalSection(&criticalSection);
00216 }
00217
00218
00219
00220 MutexLock::MutexLock(Mutex &m) : mutex(m) {
00221 EnterCriticalSection(&mutex.criticalSection);
00222 }
00223
00224
00225
00226 MutexLock::~MutexLock() {
00227 LeaveCriticalSection(&mutex.criticalSection);
00228 }
00229
00230
00231
00232 RWMutex *RWMutex::Create() {
00233 return new RWMutex;
00234 }
00235
00236
00237
00238 void RWMutex::Destroy(RWMutex *m) {
00239 delete m;
00240 }
00241
00242
00243
00244
00245
00246 RWMutex::RWMutex() {
00247 numWritersWaiting = numReadersWaiting = activeWriterReaders = 0;
00248 InitializeCriticalSection(&cs);
00249
00250 hReadyToRead = CreateEvent(NULL, TRUE, FALSE, NULL);
00251 if (hReadyToRead == NULL) {
00252 Severe("Error creating event for RWMutex: %d", GetLastError());
00253 }
00254
00255 hReadyToWrite = CreateSemaphore(NULL, 0, 1, NULL);
00256 if (hReadyToWrite == NULL) {
00257 DWORD lastError = GetLastError();
00258 CloseHandle(hReadyToRead);
00259 Severe("Error creating semaphore for RWMutex: %d", lastError);
00260 }
00261 }
00262
00263
00264
00265 RWMutex::~RWMutex() {
00266 if (hReadyToRead)
00267 CloseHandle(hReadyToRead);
00268 if (hReadyToWrite != NULL)
00269 CloseHandle(hReadyToWrite);
00270 DeleteCriticalSection(&cs);
00271 }
00272
00273
00274
00275
00276 RWMutexLock::RWMutexLock(RWMutex &m, RWMutexLockType t)
00277 : type(t), mutex(m) {
00278 if (type == READ) mutex.AcquireRead();
00279 else mutex.AcquireWrite();
00280 }
00281
00282
00283
00284 void
00285 RWMutex::AcquireRead() {
00286 bool fNotifyReaders = false;
00287
00288 EnterCriticalSection(&cs);
00289
00290 if ((numWritersWaiting > 0) || (HIWORD(activeWriterReaders) > 0)) {
00291 ++numReadersWaiting;
00292
00293 while (true) {
00294 ResetEvent(hReadyToRead);
00295 LeaveCriticalSection(&cs);
00296 WaitForSingleObject(hReadyToRead, INFINITE);
00297 EnterCriticalSection(&cs);
00298
00299
00300
00301
00302 if ((numWritersWaiting == 0) && (HIWORD(activeWriterReaders) == 0))
00303 break;
00304 }
00305
00306
00307 --numReadersWaiting;
00308
00309
00310 ++activeWriterReaders;
00311 }
00312 else {
00313
00314 if ((++activeWriterReaders == 1) && (numReadersWaiting != 0)) {
00315
00316
00317
00318
00319
00320
00321 fNotifyReaders = true;
00322 }
00323 }
00324
00325 Assert(HIWORD(activeWriterReaders) == 0);
00326 LeaveCriticalSection(&cs);
00327
00328 if (fNotifyReaders)
00329 SetEvent(hReadyToRead);
00330 }
00331
00332
00333
00334
00335 void
00336 RWMutex::AcquireWrite() {
00337 EnterCriticalSection(&cs);
00338
00339
00340 if (activeWriterReaders != 0) {
00341 ++numWritersWaiting;
00342
00343 LeaveCriticalSection(&cs);
00344 WaitForSingleObject(hReadyToWrite, INFINITE);
00345
00346
00347
00348
00349
00350 }
00351 else {
00352 Assert(activeWriterReaders == 0);
00353
00354
00355 activeWriterReaders = MAKELONG(0, 1);
00356
00357 LeaveCriticalSection(&cs);
00358 }
00359 }
00360
00361
00362
00363 void
00364 RWMutex::ReleaseRead() {
00365 EnterCriticalSection(&cs);
00366
00367
00368 Assert(HIWORD(activeWriterReaders) == 0);
00369
00370
00371 Assert(LOWORD(activeWriterReaders > 0));
00372
00373
00374 if (--activeWriterReaders == 0)
00375 ResetEvent(hReadyToRead);
00376
00377
00378
00379 if ((numWritersWaiting != 0) && (activeWriterReaders == 0)) {
00380
00381 --numWritersWaiting;
00382
00383
00384 activeWriterReaders = MAKELONG(0, 1);
00385 ReleaseSemaphore(hReadyToWrite, 1, NULL);
00386 }
00387
00388 LeaveCriticalSection(&cs);
00389 }
00390
00391
00392
00393 void
00394 RWMutex::ReleaseWrite() {
00395 bool fNotifyWriter = false;
00396 bool fNotifyReaders = false;
00397
00398 EnterCriticalSection(&cs);
00399
00400
00401 Assert(HIWORD(activeWriterReaders) == 1);
00402
00403
00404 Assert(LOWORD(activeWriterReaders) == 0);
00405
00406 if (numWritersWaiting != 0) {
00407
00408
00409
00410
00411 --numWritersWaiting;
00412 fNotifyWriter = true;
00413 }
00414 else {
00415
00416
00417 activeWriterReaders = 0;
00418
00419
00420
00421
00422
00423
00424
00425 if (numReadersWaiting != 0)
00426 fNotifyReaders = true;
00427 }
00428
00429 LeaveCriticalSection(&cs);
00430
00431 if (fNotifyWriter)
00432 ReleaseSemaphore(hReadyToWrite, 1, NULL);
00433 else if (fNotifyReaders)
00434 SetEvent(hReadyToRead);
00435 }
00436
00437
00438
00439 RWMutexLock::~RWMutexLock() {
00440 if (type == READ) mutex.ReleaseRead();
00441 else mutex.ReleaseWrite();
00442 }
00443
00444
00445
00446 void RWMutexLock::UpgradeToWrite() {
00447 Assert(type == READ);
00448 mutex.ReleaseRead();
00449 mutex.AcquireWrite();
00450 type = WRITE;
00451 }
00452
00453
00454
00455 void RWMutexLock::DowngradeToRead() {
00456 Assert(type == WRITE);
00457 mutex.ReleaseWrite();
00458 mutex.AcquireRead();
00459 type = READ;
00460 }
00461
00462
00463 #endif
00464 #if !defined(PBRT_IS_WINDOWS)
00465 Semaphore::Semaphore() {
00466 #ifdef __OpenBSD__
00467 sem = (sem_t *)malloc(sizeof(sem_t));
00468 if (!sem)
00469 Severe("Error from sem_open");
00470 int err = sem_init(sem, 0, 0);
00471 if (err == -1)
00472 Severe("Error from sem_init: %s", strerror(err));
00473 #else
00474 char name[32];
00475 sprintf(name, "pbrt.%d-%d", (int)getpid(), count++);
00476 sem = sem_open(name, O_CREAT, S_IRUSR|S_IWUSR, 0);
00477 if (!sem)
00478 Severe("Error from sem_open: %s", strerror(errno));
00479 #endif // !__OpenBSD__
00480 }
00481
00482
00483 #endif // !PBRT_IS_WINDOWS
00484 #if defined(PBRT_IS_WINDOWS)
00485 Semaphore::Semaphore() {
00486 handle = CreateSemaphore(NULL, 0, 65535, NULL);
00487 if (!handle)
00488 Severe("Error from CreateSemaphore: %d", GetLastError());
00489 }
00490
00491
00492 #endif // PBRT_IS_WINDOWS
00493 #if !defined(PBRT_IS_WINDOWS)
00494 int Semaphore::count = 0;
00495 #endif // !PBRT_IS_WINDOWS
00496 #if !defined(PBRT_IS_WINDOWS)
00497 Semaphore::~Semaphore() {
00498 #ifdef __OpenBSD__
00499 int err = sem_destroy(sem);
00500 free((void *)sem);
00501 sem = NULL;
00502 if (err != 0)
00503 Severe("Error from sem_destroy: %s", strerror(err));
00504 #else
00505 int err;
00506 if ((err = sem_close(sem)) != 0)
00507 Severe("Error from sem_close: %s", strerror(err));
00508 #endif // !__OpenBSD__
00509 }
00510
00511
00512 #endif // !PBRT_IS_WINDOWS
00513 #if defined(PBRT_IS_WINDOWS)
00514 Semaphore::~Semaphore() {
00515 CloseHandle(handle);
00516 }
00517
00518
00519 #endif // PBRT_IS_WINDOWS
00520 #if !defined(PBRT_IS_WINDOWS)
00521 void Semaphore::Wait() {
00522 int err;
00523 if ((err = sem_wait(sem)) != 0)
00524 Severe("Error from sem_wait: %s", strerror(err));
00525 }
00526
00527
00528 #endif // !PBRT_IS_WINDOWS
00529 #if !defined(PBRT_IS_WINDOWS)
00530 bool Semaphore::TryWait() {
00531 return (sem_trywait(sem) == 0);
00532 }
00533
00534
00535 #endif // !PBRT_IS_WINDOWS
00536 #if !defined(PBRT_IS_WINDOWS)
00537 void Semaphore::Post(int count) {
00538 int err;
00539 while (count-- > 0)
00540 if ((err = sem_post(sem)) != 0)
00541 Severe("Error from sem_post: %s", strerror(err));
00542 }
00543
00544
00545 #endif // !PBRT_IS_WINDOWS
00546 #if defined(PBRT_IS_WINDOWS)
00547 void Semaphore::Wait() {
00548 if (WaitForSingleObject(handle, INFINITE) == WAIT_FAILED)
00549 Severe("Error from WaitForSingleObject: %d", GetLastError());
00550
00551 }
00552
00553
00554 #endif // PBRT_IS_WINDOWS
00555 #if defined(PBRT_IS_WINDOWS)
00556 bool Semaphore::TryWait() {
00557 return (WaitForSingleObject(handle, 0L) == WAIT_OBJECT_0);
00558 }
00559
00560
00561 #endif // PBRT_IS_WINDOWS
00562 #if defined(PBRT_IS_WINDOWS)
00563 void Semaphore::Post(int count) {
00564 if (!ReleaseSemaphore(handle, count, NULL))
00565 Severe("Error from ReleaseSemaphore: %d", GetLastError());
00566 }
00567
00568
00569 #endif // PBRT_IS_WINDOWS
00570 #if !defined(PBRT_IS_WINDOWS)
00571 ConditionVariable::ConditionVariable() {
00572 int err;
00573 if ((err = pthread_cond_init(&cond, NULL)) != 0)
00574 Severe("Error from pthread_cond_init: %s", strerror(err));
00575 if ((err = pthread_mutex_init(&mutex, NULL)) != 0)
00576 Severe("Error from pthread_mutex_init: %s", strerror(err));
00577 }
00578
00579
00580 #endif // !PBRT_IS_WINDOWS
00581 #if !defined(PBRT_IS_WINDOWS)
00582 ConditionVariable::~ConditionVariable() {
00583 pthread_cond_destroy(&cond);
00584 pthread_mutex_destroy(&mutex);
00585 }
00586
00587
00588 #endif // !PBRT_IS_WINDOWS
00589 #if !defined(PBRT_IS_WINDOWS)
00590 void ConditionVariable::Lock() {
00591 int err;
00592 if ((err = pthread_mutex_lock(&mutex)) != 0)
00593 Severe("Error from pthread_mutex_lock: %s", strerror(err));
00594 }
00595
00596
00597 #endif // !PBRT_IS_WINDOWS
00598 #if !(defined(PBRT_IS_WINDOWS))
00599 void ConditionVariable::Unlock() {
00600 int err;
00601 if ((err = pthread_mutex_unlock(&mutex)) != 0)
00602 Severe("Error from pthread_mutex_unlock: %s", strerror(err));
00603 }
00604
00605
00606 #endif // !PBRT_IS_WINDOWS
00607 #if !defined(PBRT_IS_WINDOWS)
00608 void ConditionVariable::Wait() {
00609 int err;
00610 if ((err = pthread_cond_wait(&cond, &mutex)) != 0)
00611 Severe("Error from pthread_cond_wait: %s", strerror(err));
00612 }
00613
00614
00615 #endif // !PBRT_IS_WINDOWS
00616 #if !defined(PBRT_IS_WINDOWS)
00617 void ConditionVariable::Signal() {
00618 int err;
00619 if ((err = pthread_cond_signal(&cond)) != 0)
00620 Severe("Error from pthread_cond_signal: %s", strerror(err));
00621 }
00622
00623
00624 #endif // !PBRT_IS_WINDOWS
00625 #if defined(PBRT_IS_WINDOWS)
00626
00627
00628
00629 ConditionVariable::ConditionVariable() {
00630 waitersCount = 0;
00631 InitializeCriticalSection(&waitersCountMutex);
00632 InitializeCriticalSection(&conditionMutex);
00633
00634 events[SIGNAL] = CreateEvent (NULL,
00635 FALSE,
00636 FALSE,
00637 NULL);
00638 events[BROADCAST] = CreateEvent (NULL,
00639 TRUE,
00640 FALSE,
00641 NULL);
00642
00643 }
00644
00645
00646 #endif // PBRT_IS_WINDOWS
00647 #if defined(PBRT_IS_WINDOWS)
00648 ConditionVariable::~ConditionVariable() {
00649 CloseHandle(events[SIGNAL]);
00650 CloseHandle(events[BROADCAST]);
00651 }
00652
00653
00654 #endif // PBRT_IS_WINDOWS
00655 #if defined(PBRT_IS_WINDOWS)
00656 void ConditionVariable::Lock() {
00657 EnterCriticalSection(&conditionMutex);
00658 }
00659
00660
00661 #endif // PBRT_IS_WINDOWS
00662 #if defined(PBRT_IS_WINDOWS)
00663 void ConditionVariable::Unlock() {
00664 LeaveCriticalSection(&conditionMutex);
00665 }
00666
00667
00668 #endif // PBRT_IS_WINDOWS
00669 #if defined(PBRT_IS_WINDOWS)
00670 void ConditionVariable::Wait() {
00671
00672 EnterCriticalSection(&waitersCountMutex);
00673 waitersCount++;
00674 LeaveCriticalSection(&waitersCountMutex);
00675
00676
00677
00678
00679 LeaveCriticalSection(&conditionMutex);
00680
00681
00682
00683 int result = WaitForMultipleObjects(2, events, FALSE, INFINITE);
00684
00685 EnterCriticalSection(&waitersCountMutex);
00686 waitersCount--;
00687 int last_waiter = (result == WAIT_OBJECT_0 + BROADCAST) &&
00688 (waitersCount == 0);
00689 LeaveCriticalSection(&waitersCountMutex);
00690
00691
00692 if (last_waiter)
00693
00694
00695 ResetEvent(events[BROADCAST]);
00696
00697 EnterCriticalSection(&conditionMutex);
00698 }
00699
00700
00701 #endif // PBRT_IS_WINDOWS
00702 #if defined(PBRT_IS_WINDOWS)
00703 void ConditionVariable::Signal() {
00704 EnterCriticalSection(&waitersCountMutex);
00705 int haveWaiters = (waitersCount > 0);
00706 LeaveCriticalSection(&waitersCountMutex);
00707
00708 if (haveWaiters)
00709 SetEvent(events[SIGNAL]);
00710 }
00711
00712
00713 #endif // PBRT_IS_WINDOWS
00714 void TasksInit() {
00715 if (PbrtOptions.nCores == 1)
00716 return;
00717 #ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH
00718 return;
00719 #else // PBRT_USE_GRAND_CENTRAL_DISPATCH
00720 static const int nThreads = NumSystemCores();
00721 workerSemaphore = new Semaphore;
00722 tasksRunningCondition = new ConditionVariable;
00723 #if !defined(PBRT_IS_WINDOWS)
00724 threads = new pthread_t[nThreads];
00725 for (int i = 0; i < nThreads; ++i) {
00726 int err = pthread_create(&threads[i], NULL, &taskEntry, reinterpret_cast<void *>(i));
00727 if (err != 0)
00728 Severe("Error from pthread_create: %s", strerror(err));
00729 }
00730 #else
00731 threads = new HANDLE[nThreads];
00732 for (int i = 0; i < nThreads; ++i) {
00733 threads[i] = CreateThread(NULL, 0, taskEntry, reinterpret_cast<void *>(i), 0, NULL);
00734 if (threads[i] == NULL)
00735 Severe("Error from CreateThread");
00736 }
00737 #endif // PBRT_IS_WINDOWS
00738 #endif // PBRT_USE_GRAND_CENTRAL_DISPATCH
00739 }
00740
00741
00742 void TasksCleanup() {
00743 if (PbrtOptions.nCores == 1)
00744 return;
00745 #ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH
00746 return;
00747 #else // // PBRT_USE_GRAND_CENTRAL_DISPATCH
00748 { MutexLock lock(*taskQueueMutex);
00749 Assert(taskQueue.size() == 0);
00750 }
00751
00752 static const int nThreads = NumSystemCores();
00753 workerSemaphore->Post(nThreads);
00754
00755 if (threads != NULL) {
00756 #if !defined(PBRT_IS_WINDOWS)
00757 for (int i = 0; i < nThreads; ++i) {
00758 int err = pthread_join(threads[i], NULL);
00759 if (err != 0)
00760 Severe("Error from pthread_join: %s", strerror(err));
00761 }
00762 #else
00763 WaitForMultipleObjects(nThreads, threads, TRUE, INFINITE);
00764 for (int i = 0; i < nThreads; ++i) {
00765 CloseHandle(threads[i]);
00766 }
00767 #endif // PBRT_IS_WINDOWS
00768 delete[] threads;
00769 threads = NULL;
00770 }
00771 #endif // PBRT_USE_GRAND_CENTRAL_DISPATCH
00772 }
00773
00774
00775 Task::~Task() {
00776 }
00777
00778
00779 #ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH
00780 static void lRunTask(void *t) {
00781 Task *task = (Task *)t;
00782 PBRT_STARTED_TASK(task);
00783 task->Run();
00784 PBRT_FINISHED_TASK(task);
00785 }
00786
00787
00788 #endif
00789 void EnqueueTasks(const vector<Task *> &tasks) {
00790 if (PbrtOptions.nCores == 1) {
00791 for (unsigned int i = 0; i < tasks.size(); ++i)
00792 tasks[i]->Run();
00793 return;
00794 }
00795 #ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH
00796 for (uint32_t i = 0; i < tasks.size(); ++i)
00797 dispatch_group_async_f(gcdGroup, gcdQueue, tasks[i], lRunTask);
00798 #else
00799 if (!threads)
00800 TasksInit();
00801
00802 { MutexLock lock(*taskQueueMutex);
00803 for (unsigned int i = 0; i < tasks.size(); ++i)
00804 taskQueue.push_back(tasks[i]);
00805 }
00806 tasksRunningCondition->Lock();
00807 numUnfinishedTasks += tasks.size();
00808 tasksRunningCondition->Unlock();
00809
00810 workerSemaphore->Post(tasks.size());
00811 #endif
00812 }
00813
00814
00815 #ifndef PBRT_USE_GRAND_CENTRAL_DISPATCH
00816 #if defined(PBRT_IS_WINDOWS)
00817 static DWORD WINAPI taskEntry(LPVOID arg) {
00818 #else
00819 static void *taskEntry(void *arg) {
00820 #endif
00821 while (true) {
00822 workerSemaphore->Wait();
00823
00824 Task *myTask = NULL;
00825 { MutexLock lock(*taskQueueMutex);
00826 if (taskQueue.size() == 0)
00827 break;
00828 myTask = taskQueue.back();
00829 taskQueue.pop_back();
00830 }
00831
00832
00833 PBRT_STARTED_TASK(myTask);
00834 myTask->Run();
00835 PBRT_FINISHED_TASK(myTask);
00836 tasksRunningCondition->Lock();
00837 int unfinished = --numUnfinishedTasks;
00838 if (unfinished == 0)
00839 tasksRunningCondition->Signal();
00840 tasksRunningCondition->Unlock();
00841 }
00842
00843 #if !defined(PBRT_IS_WINDOWS)
00844 pthread_exit(NULL);
00845 #endif // !PBRT_IS_WINDOWS
00846 return 0;
00847 }
00848
00849
00850 #endif // !PBRT_USE_GRAND_CENTRAL_DISPATCH
00851 void WaitForAllTasks() {
00852 if (PbrtOptions.nCores == 1)
00853 return;
00854 #ifdef PBRT_USE_GRAND_CENTRAL_DISPATCH
00855 dispatch_group_wait(gcdGroup, DISPATCH_TIME_FOREVER);
00856 #else
00857 if (!tasksRunningCondition)
00858 return;
00859 tasksRunningCondition->Lock();
00860 while (numUnfinishedTasks > 0)
00861 tasksRunningCondition->Wait();
00862 tasksRunningCondition->Unlock();
00863 #endif
00864 }
00865
00866
00867 int NumSystemCores() {
00868 if (PbrtOptions.nCores > 0) return PbrtOptions.nCores;
00869 #if defined(PBRT_IS_WINDOWS)
00870 SYSTEM_INFO sysinfo;
00871 GetSystemInfo(&sysinfo);
00872 return sysinfo.dwNumberOfProcessors;
00873 #elif defined(__linux__)
00874 return sysconf(_SC_NPROCESSORS_ONLN);
00875 #else
00876
00877 #ifdef __OpenBSD__
00878 int mib[2] = { CTL_HW, HW_NCPU };
00879 #else
00880 int mib[2];
00881 mib[0] = CTL_HW;
00882 size_t length = 2;
00883 if (sysctlnametomib("hw.logicalcpu", mib, &length) == -1) {
00884 Error("sysctlnametomib() filed. Guessing 2 CPU cores.");
00885 return 2;
00886 }
00887 Assert(length == 2);
00888 #endif
00889 int nCores = 0;
00890 size_t size = sizeof(nCores);
00891
00892
00893 if (sysctl(mib, 2, &nCores, &size, NULL, 0) == -1) {
00894 Error("sysctl() to find number of cores present failed");
00895 return 2;
00896 }
00897 return nCores;
00898 #endif
00899 }
00900
00901