1 #include <mbgl/actor/mailbox.hpp> 2 #include <mbgl/actor/message.hpp> 3 #include <mbgl/actor/scheduler.hpp> 4 5 #include <cassert> 6 7 namespace mbgl { 8 Mailbox()9Mailbox::Mailbox() { 10 } 11 Mailbox(Scheduler & scheduler_)12Mailbox::Mailbox(Scheduler& scheduler_) 13 : scheduler(&scheduler_) { 14 } 15 open(Scheduler & scheduler_)16void Mailbox::open(Scheduler& scheduler_) { 17 assert(!scheduler); 18 19 // As with close(), block until neither receive() nor push() are in progress, and acquire the two 20 // mutexes in the same order. 21 std::lock_guard<std::recursive_mutex> receivingLock(receivingMutex); 22 std::lock_guard<std::mutex> pushingLock(pushingMutex); 23 24 scheduler = &scheduler_; 25 26 if (closed) { 27 return; 28 } 29 30 if (!queue.empty()) { 31 (*scheduler)->schedule(shared_from_this()); 32 } 33 } 34 close()35void Mailbox::close() { 36 // Block until neither receive() nor push() are in progress. Two mutexes are used because receive() 37 // must not block send(). Of the two, the receiving mutex must be acquired first, because that is 38 // the order that an actor will obtain them when it self-sends a message, and consistent lock 39 // acquisition order prevents deadlocks. 40 // The receiving mutex is recursive to allow a mailbox (and thus the actor) to close itself. 41 std::lock_guard<std::recursive_mutex> receivingLock(receivingMutex); 42 std::lock_guard<std::mutex> pushingLock(pushingMutex); 43 44 closed = true; 45 } 46 isOpen() const47bool Mailbox::isOpen() const { return bool(scheduler); } 48 49 push(std::unique_ptr<Message> message)50void Mailbox::push(std::unique_ptr<Message> message) { 51 std::lock_guard<std::mutex> pushingLock(pushingMutex); 52 53 if (closed) { 54 return; 55 } 56 57 std::lock_guard<std::mutex> queueLock(queueMutex); 58 bool wasEmpty = queue.empty(); 59 queue.push(std::move(message)); 60 if (wasEmpty && scheduler) { 61 (*scheduler)->schedule(shared_from_this()); 62 } 63 } 64 receive()65void Mailbox::receive() { 66 std::lock_guard<std::recursive_mutex> receivingLock(receivingMutex); 67 68 assert(scheduler); 69 70 if (closed) { 71 return; 72 } 73 74 std::unique_ptr<Message> message; 75 bool wasEmpty; 76 77 { 78 std::lock_guard<std::mutex> queueLock(queueMutex); 79 assert(!queue.empty()); 80 message = std::move(queue.front()); 81 queue.pop(); 82 wasEmpty = queue.empty(); 83 } 84 85 (*message)(); 86 87 if (!wasEmpty) { 88 (*scheduler)->schedule(shared_from_this()); 89 } 90 } 91 maybeReceive(std::weak_ptr<Mailbox> mailbox)92void Mailbox::maybeReceive(std::weak_ptr<Mailbox> mailbox) { 93 if (auto locked = mailbox.lock()) { 94 locked->receive(); 95 } 96 } 97 98 } // namespace mbgl 99