Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 1 | /* |
| 2 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 3 | * Copyright 2016 gRPC authors. |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 4 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 8 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 10 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 16 | * |
| 17 | */ |
| 18 | |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 19 | #ifndef GRPC_INTERNAL_CPP_THREAD_MANAGER_H |
| 20 | #define GRPC_INTERNAL_CPP_THREAD_MANAGER_H |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 21 | |
Vijay Pai | 320ed13 | 2016-11-01 17:16:55 -0700 | [diff] [blame] | 22 | #include <condition_variable> |
Vijay Pai | 92e267e | 2018-01-10 00:39:06 +0000 | [diff] [blame] | 23 | #include <functional> |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 24 | #include <list> |
| 25 | #include <memory> |
Vijay Pai | 320ed13 | 2016-11-01 17:16:55 -0700 | [diff] [blame] | 26 | #include <mutex> |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 27 | |
Sree Kuchibhotla | 33d5494 | 2016-10-25 10:03:52 -0700 | [diff] [blame] | 28 | #include <grpc++/support/config.h> |
Vijay Pai | 5dd3226 | 2017-11-14 19:04:02 -0800 | [diff] [blame] | 29 | #include <grpc/support/thd.h> |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 30 | |
| 31 | namespace grpc { |
| 32 | |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 33 | class ThreadManager { |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 34 | public: |
Vijay Pai | 5dd3226 | 2017-11-14 19:04:02 -0800 | [diff] [blame] | 35 | ThreadManager(int min_pollers, int max_pollers, |
| 36 | std::function<int(gpr_thd_id*, const char*, void (*)(void*), |
| 37 | void*, const gpr_thd_options*)> |
| 38 | thread_creator, |
| 39 | std::function<void(gpr_thd_id)> thread_joiner); |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 40 | virtual ~ThreadManager(); |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 41 | |
Sree Kuchibhotla | 33382d0 | 2016-10-03 15:08:48 -0700 | [diff] [blame] | 42 | // Initializes and Starts the Rpc Manager threads |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 43 | void Initialize(); |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 44 | |
Sree Kuchibhotla | acd64db | 2016-10-03 14:29:47 -0700 | [diff] [blame] | 45 | // The return type of PollForWork() function |
Sree Kuchibhotla | aabada9 | 2016-08-24 10:01:13 -0700 | [diff] [blame] | 46 | enum WorkStatus { WORK_FOUND, SHUTDOWN, TIMEOUT }; |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 47 | |
Sree Kuchibhotla | aabada9 | 2016-08-24 10:01:13 -0700 | [diff] [blame] | 48 | // "Polls" for new work. |
| 49 | // If the return value is WORK_FOUND: |
| 50 | // - The implementaion of PollForWork() MAY set some opaque identifier to |
| 51 | // (identify the work item found) via the '*tag' parameter |
| 52 | // - The implementaion MUST set the value of 'ok' to 'true' or 'false'. A |
| 53 | // value of 'false' indicates some implemenation specific error (that is |
| 54 | // neither SHUTDOWN nor TIMEOUT) |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 55 | // - ThreadManager does not interpret the values of 'tag' and 'ok' |
| 56 | // - ThreadManager WILL call DoWork() and pass '*tag' and 'ok' as input to |
Sree Kuchibhotla | aabada9 | 2016-08-24 10:01:13 -0700 | [diff] [blame] | 57 | // DoWork() |
Vijay Pai | 5dd3226 | 2017-11-14 19:04:02 -0800 | [diff] [blame] | 58 | // - ThreadManager will also pass DoWork a bool saying if there are actually |
| 59 | // resources to do the work |
Sree Kuchibhotla | aabada9 | 2016-08-24 10:01:13 -0700 | [diff] [blame] | 60 | // |
| 61 | // If the return value is SHUTDOWN:, |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 62 | // - ThreadManager WILL NOT call DoWork() and terminates the thead |
Sree Kuchibhotla | aabada9 | 2016-08-24 10:01:13 -0700 | [diff] [blame] | 63 | // |
| 64 | // If the return value is TIMEOUT:, |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 65 | // - ThreadManager WILL NOT call DoWork() |
| 66 | // - ThreadManager MAY terminate the thread depending on the current number |
| 67 | // of active poller threads and mix_pollers/max_pollers settings |
Sree Kuchibhotla | aabada9 | 2016-08-24 10:01:13 -0700 | [diff] [blame] | 68 | // - Also, the value of timeout is specific to the derived class |
| 69 | // implementation |
| 70 | virtual WorkStatus PollForWork(void** tag, bool* ok) = 0; |
| 71 | |
| 72 | // The implementation of DoWork() is supposed to perform the work found by |
| 73 | // PollForWork(). The tag and ok parameters are the same as returned by |
| 74 | // PollForWork() |
| 75 | // |
| 76 | // The implementation of DoWork() should also do any setup needed to ensure |
| 77 | // that the next call to PollForWork() (not necessarily by the current thread) |
| 78 | // actually finds some work |
Vijay Pai | 5dd3226 | 2017-11-14 19:04:02 -0800 | [diff] [blame] | 79 | virtual void DoWork(void* tag, bool ok, bool resources) = 0; |
Sree Kuchibhotla | aabada9 | 2016-08-24 10:01:13 -0700 | [diff] [blame] | 80 | |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 81 | // Mark the ThreadManager as shutdown and begin draining the work. This is a |
| 82 | // non-blocking call and the caller should call Wait(), a blocking call which |
| 83 | // returns only once the shutdown is complete |
Craig Tiller | 991c101 | 2017-04-18 19:43:14 +0000 | [diff] [blame] | 84 | virtual void Shutdown(); |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 85 | |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 86 | // Has Shutdown() been called |
Sree Kuchibhotla | aabada9 | 2016-08-24 10:01:13 -0700 | [diff] [blame] | 87 | bool IsShutdown(); |
| 88 | |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 89 | // A blocking call that returns only after the ThreadManager has shutdown and |
Sree Kuchibhotla | aabada9 | 2016-08-24 10:01:13 -0700 | [diff] [blame] | 90 | // all the threads have drained all the outstanding work |
Craig Tiller | a3e8789 | 2017-04-18 13:08:08 -0700 | [diff] [blame] | 91 | virtual void Wait(); |
Sree Kuchibhotla | aabada9 | 2016-08-24 10:01:13 -0700 | [diff] [blame] | 92 | |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 93 | private: |
Vijay Pai | 5dd3226 | 2017-11-14 19:04:02 -0800 | [diff] [blame] | 94 | // Helper wrapper class around thread. This takes a ThreadManager object |
| 95 | // and starts a new thread to calls the Run() function. |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 96 | // |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 97 | // The Run() function calls ThreadManager::MainWorkLoop() function and once |
| 98 | // that completes, it marks the WorkerThread completed by calling |
| 99 | // ThreadManager::MarkAsCompleted() |
| 100 | class WorkerThread { |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 101 | public: |
Vijay Pai | 5dd3226 | 2017-11-14 19:04:02 -0800 | [diff] [blame] | 102 | WorkerThread(ThreadManager* thd_mgr, bool* valid); |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 103 | ~WorkerThread(); |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 104 | |
| 105 | private: |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 106 | // Calls thd_mgr_->MainWorkLoop() and once that completes, calls |
| 107 | // thd_mgr_>MarkAsCompleted(this) to mark the thread as completed |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 108 | void Run(); |
| 109 | |
David Garcia Quintas | aef267b | 2017-07-14 18:35:50 -0700 | [diff] [blame] | 110 | ThreadManager* const thd_mgr_; |
| 111 | std::mutex wt_mu_; |
Vijay Pai | 5dd3226 | 2017-11-14 19:04:02 -0800 | [diff] [blame] | 112 | gpr_thd_id thd_; |
| 113 | bool valid_; |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 114 | }; |
| 115 | |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 116 | // The main funtion in ThreadManager |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 117 | void MainWorkLoop(); |
| 118 | |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 119 | void MarkAsCompleted(WorkerThread* thd); |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 120 | void CleanupCompletedThreads(); |
| 121 | |
| 122 | // Protects shutdown_, num_pollers_ and num_threads_ |
| 123 | // TODO: sreek - Change num_pollers and num_threads_ to atomics |
Vijay Pai | 320ed13 | 2016-11-01 17:16:55 -0700 | [diff] [blame] | 124 | std::mutex mu_; |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 125 | |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 126 | bool shutdown_; |
Vijay Pai | 320ed13 | 2016-11-01 17:16:55 -0700 | [diff] [blame] | 127 | std::condition_variable shutdown_cv_; |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 128 | |
| 129 | // Number of threads doing polling |
| 130 | int num_pollers_; |
| 131 | |
| 132 | // The minimum and maximum number of threads that should be doing polling |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 133 | int min_pollers_; |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 134 | int max_pollers_; |
| 135 | |
| 136 | // The total number of threads (includes threads includes the threads that are |
| 137 | // currently polling i.e num_pollers_) |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 138 | int num_threads_; |
Sree Kuchibhotla | 8600438 | 2016-07-18 22:27:39 -0700 | [diff] [blame] | 139 | |
Vijay Pai | 5dd3226 | 2017-11-14 19:04:02 -0800 | [diff] [blame] | 140 | // Functions for creating/joining threads. Normally, these should |
| 141 | // be gpr_thd_new/gpr_thd_join but they are overridable |
| 142 | std::function<int(gpr_thd_id*, const char*, void (*)(void*), void*, |
| 143 | const gpr_thd_options*)> |
| 144 | thread_creator_; |
| 145 | std::function<void(gpr_thd_id)> thread_joiner_; |
| 146 | |
Vijay Pai | 320ed13 | 2016-11-01 17:16:55 -0700 | [diff] [blame] | 147 | std::mutex list_mu_; |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 148 | std::list<WorkerThread*> completed_threads_; |
Sree Kuchibhotla | 9e656a4 | 2016-07-18 13:01:42 -0700 | [diff] [blame] | 149 | }; |
| 150 | |
| 151 | } // namespace grpc |
| 152 | |
Sree Kuchibhotla | 8f7739b | 2016-10-13 15:12:55 -0700 | [diff] [blame] | 153 | #endif // GRPC_INTERNAL_CPP_THREAD_MANAGER_H |