PageRenderTime 85ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/mordor/parallel.cpp

http://github.com/mozy/mordor
C++ | 134 lines | 107 code | 19 blank | 8 comment | 30 complexity | 523a11b4f7dbf60d06784d828d8c7d93 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include "parallel.h"
  3. #include <boost/scoped_ptr.hpp>
  4. #include "assert.h"
  5. #include "atomic.h"
  6. #include "fibersynchronization.h"
  7. namespace Mordor {
  8. static Logger::ptr g_log = Log::lookup("mordor:parallel");
  9. static
  10. void
  11. parallel_do_impl(boost::function<void ()> dg, size_t &completed,
  12. size_t total, boost::exception_ptr &exception, Scheduler *scheduler,
  13. Fiber::ptr caller, FiberSemaphore *sem)
  14. {
  15. if (sem)
  16. sem->wait();
  17. try {
  18. dg();
  19. } catch (boost::exception &ex) {
  20. removeTopFrames(ex);
  21. exception = boost::current_exception();
  22. } catch (...) {
  23. exception = boost::current_exception();
  24. }
  25. if (sem)
  26. sem->notify();
  27. if (atomicIncrement(completed) == total)
  28. scheduler->schedule(caller);
  29. }
  30. void
  31. parallel_do(const std::vector<boost::function<void ()> > &dgs,
  32. int parallelism)
  33. {
  34. size_t completed = 0;
  35. Scheduler *scheduler = Scheduler::getThis();
  36. Fiber::ptr caller = Fiber::getThis();
  37. std::vector<boost::function<void ()> >::const_iterator it;
  38. if (scheduler == NULL || dgs.size() <= 1) {
  39. for(it = dgs.begin(); it != dgs.end(); ++it) {
  40. (*it)();
  41. }
  42. return;
  43. }
  44. MORDOR_ASSERT(parallelism != 0);
  45. boost::scoped_ptr<FiberSemaphore> sem;
  46. if (parallelism != -1)
  47. sem.reset(new FiberSemaphore(parallelism));
  48. std::vector<Fiber::ptr> fibers;
  49. std::vector<boost::exception_ptr> exceptions;
  50. fibers.reserve(dgs.size());
  51. exceptions.resize(dgs.size());
  52. for(size_t i = 0; i < dgs.size(); ++i) {
  53. Fiber::ptr f(new Fiber(boost::bind(&parallel_do_impl, dgs[i],
  54. boost::ref(completed), dgs.size(), boost::ref(exceptions[i]),
  55. scheduler, caller, sem.get())));
  56. fibers.push_back(f);
  57. scheduler->schedule(f);
  58. }
  59. Scheduler::yieldTo();
  60. // Pass the first exception along
  61. // TODO: group exceptions?
  62. for(std::vector<boost::exception_ptr>::iterator it2 = exceptions.begin();
  63. it2 != exceptions.end();
  64. ++it2) {
  65. if (*it2)
  66. Mordor::rethrow_exception(*it2);
  67. }
  68. }
  69. void
  70. parallel_do(const std::vector<boost::function<void ()> > &dgs,
  71. std::vector<Fiber::ptr> &fibers,
  72. int parallelism)
  73. {
  74. MORDOR_ASSERT(fibers.size() >= dgs.size());
  75. size_t completed = 0;
  76. Scheduler *scheduler = Scheduler::getThis();
  77. Fiber::ptr caller = Fiber::getThis();
  78. std::vector<boost::function<void ()> >::const_iterator it;
  79. if (scheduler == NULL || dgs.size() <= 1) {
  80. for(it = dgs.begin(); it != dgs.end(); ++it) {
  81. (*it)();
  82. }
  83. return;
  84. }
  85. boost::scoped_ptr<FiberSemaphore> sem;
  86. MORDOR_ASSERT(parallelism != 0);
  87. if (parallelism != -1)
  88. sem.reset(new FiberSemaphore(parallelism));
  89. std::vector<boost::exception_ptr> exceptions;
  90. exceptions.resize(dgs.size());
  91. for(size_t i = 0; i < dgs.size(); ++i) {
  92. fibers[i]->reset(boost::bind(&parallel_do_impl, dgs[i],
  93. boost::ref(completed), dgs.size(), boost::ref(exceptions[i]),
  94. scheduler, caller, sem.get()));
  95. scheduler->schedule(fibers[i]);
  96. }
  97. Scheduler::yieldTo();
  98. // Make sure all fibers have actually exited, to avoid the caller
  99. // immediately calling Fiber::reset, and the Fiber hasn't actually exited
  100. // because it is running in a different thread.
  101. for (size_t i = 0; i < dgs.size(); ++i)
  102. while (fibers[i]->state() == Fiber::EXEC) Scheduler::yield();
  103. // Pass the first exception along
  104. // TODO: group exceptions?
  105. for (size_t i = 0; i < dgs.size(); ++i) {
  106. if (exceptions[i])
  107. Mordor::rethrow_exception(exceptions[i]);
  108. }
  109. }
  110. namespace Detail {
  111. Logger::ptr getLogger()
  112. {
  113. return g_log;
  114. }
  115. }}