Try Contains enum as an enum class
[folly.git] / folly / wangle / ManualExecutor.cpp
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "ManualExecutor.h"
18
19 #include <string.h>
20
21 #include <stdexcept>
22
23 namespace folly { namespace wangle {
24
25 ManualExecutor::ManualExecutor() {
26   if (sem_init(&sem_, 0, 0) == -1) {
27     throw std::runtime_error(std::string("sem_init: ") + strerror(errno));
28   }
29 }
30
31 void ManualExecutor::add(std::function<void()>&& callback) {
32   std::lock_guard<std::mutex> lock(lock_);
33   runnables_.push(callback);
34   sem_post(&sem_);
35 }
36
37 size_t ManualExecutor::run() {
38   size_t count;
39   size_t n;
40   std::function<void()> runnable;
41
42   {
43     std::lock_guard<std::mutex> lock(lock_);
44     n = runnables_.size();
45   }
46
47   for (count = 0; count < n; count++) {
48     {
49       std::lock_guard<std::mutex> lock(lock_);
50       if (runnables_.empty()) {
51         break;
52       }
53
54       // Balance the semaphore so it doesn't grow without bound
55       // if nobody is calling wait().
56       // This may fail (with EAGAIN), that's fine.
57       sem_trywait(&sem_);
58
59       runnable = std::move(runnables_.front());
60       runnables_.pop();
61     }
62     runnable();
63   }
64
65   return count;
66 }
67
68 void ManualExecutor::wait() {
69   while (true) {
70     {
71       std::lock_guard<std::mutex> lock(lock_);
72       if (!runnables_.empty())
73         break;
74     }
75
76     auto ret = sem_wait(&sem_);
77     if (ret == 0) {
78       break;
79     }
80     if (errno != EINVAL) {
81       throw std::runtime_error(std::string("sem_wait: ") + strerror(errno));
82     }
83   }
84 }
85
86 }} // namespace