You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 lines
6.4 KiB

  1. /* Copyright(C) 2019 MariaDB
  2. This program is free software; you can redistribute itand /or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; version 2 of the License.
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License
  10. along with this program; if not, write to the Free Software
  11. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 - 1301 USA*/
  12. #pragma once
  13. #include <memory> /* unique_ptr */
  14. #include <condition_variable>
  15. #include <mutex>
  16. #include <atomic>
  17. #include <tpool_structs.h>
  18. #ifdef LINUX_NATIVE_AIO
  19. #include <libaio.h>
  20. #endif
  21. #ifdef _WIN32
  22. #ifndef NOMINMAX
  23. #define NOMINMAX
  24. #endif
  25. #include <windows.h>
  26. /**
  27. Windows-specific native file handle struct.
  28. Apart from the actual handle, contains PTP_IO
  29. used by the Windows threadpool.
  30. */
  31. struct native_file_handle
  32. {
  33. HANDLE m_handle;
  34. PTP_IO m_ptp_io;
  35. native_file_handle(){};
  36. native_file_handle(HANDLE h) : m_handle(h), m_ptp_io() {}
  37. operator HANDLE() const { return m_handle; }
  38. };
  39. #else
  40. #include <unistd.h>
  41. typedef int native_file_handle;
  42. #endif
  43. namespace tpool
  44. {
  45. /**
  46. Task callback function
  47. */
  48. typedef void (*callback_func)(void *);
  49. typedef void (*callback_func_np)(void);
  50. class task;
  51. /** A class that can be used e.g. for
  52. restricting concurrency for specific class of tasks. */
  53. class task_group
  54. {
  55. private:
  56. circular_queue<task*> m_queue;
  57. std::mutex m_mtx;
  58. std::condition_variable m_cv;
  59. unsigned int m_tasks_running;
  60. unsigned int m_max_concurrent_tasks;
  61. public:
  62. task_group(unsigned int max_concurrency= 100000);
  63. void set_max_tasks(unsigned int max_concurrent_tasks);
  64. void execute(task* t);
  65. void cancel_pending(task *t);
  66. ~task_group();
  67. };
  68. class task
  69. {
  70. public:
  71. callback_func m_func;
  72. void *m_arg;
  73. task_group* m_group;
  74. virtual void add_ref() {};
  75. virtual void release() {};
  76. task() {};
  77. task(callback_func func, void* arg, task_group* group = nullptr);
  78. void* get_arg() { return m_arg; }
  79. callback_func get_func() { return m_func; }
  80. virtual void execute();
  81. virtual ~task() {}
  82. };
  83. class waitable_task :public task
  84. {
  85. std::mutex m_mtx;
  86. std::condition_variable m_cv;
  87. int m_ref_count;
  88. int m_waiter_count;
  89. public:
  90. waitable_task(callback_func func, void* arg, task_group* group = nullptr);
  91. void add_ref() override;
  92. void release() override;
  93. bool is_running() { return m_ref_count > 0; }
  94. bool get_ref_count() {return m_ref_count;}
  95. void wait();
  96. virtual ~waitable_task() {};
  97. };
  98. enum class aio_opcode
  99. {
  100. AIO_PREAD,
  101. AIO_PWRITE
  102. };
  103. const int MAX_AIO_USERDATA_LEN= 40;
  104. /** IO control block, includes parameters for the IO, and the callback*/
  105. struct aiocb
  106. #ifdef _WIN32
  107. :OVERLAPPED
  108. #elif defined LINUX_NATIVE_AIO
  109. :iocb
  110. #endif
  111. {
  112. native_file_handle m_fh;
  113. aio_opcode m_opcode;
  114. unsigned long long m_offset;
  115. void *m_buffer;
  116. unsigned int m_len;
  117. callback_func m_callback;
  118. task_group* m_group;
  119. /* Returned length and error code*/
  120. size_t m_ret_len;
  121. int m_err;
  122. void *m_internal;
  123. task m_internal_task;
  124. char m_userdata[MAX_AIO_USERDATA_LEN];
  125. aiocb() : m_internal_task(nullptr, nullptr)
  126. {}
  127. void execute_callback()
  128. {
  129. task t(m_callback, this,m_group);
  130. t.execute();
  131. }
  132. };
  133. /**
  134. AIO interface
  135. */
  136. class aio
  137. {
  138. public:
  139. /**
  140. Submit asyncronous IO.
  141. On completion, cb->m_callback is executed.
  142. */
  143. virtual int submit_io(aiocb *cb)= 0;
  144. /** "Bind" file to AIO handler (used on Windows only) */
  145. virtual int bind(native_file_handle &fd)= 0;
  146. /** "Unind" file to AIO handler (used on Windows only) */
  147. virtual int unbind(const native_file_handle &fd)= 0;
  148. virtual ~aio(){};
  149. };
  150. class timer
  151. {
  152. public:
  153. virtual void set_time(int initial_delay_ms, int period_ms) = 0;
  154. virtual void disarm() = 0;
  155. virtual ~timer(){}
  156. };
  157. class thread_pool;
  158. extern aio *create_simulated_aio(thread_pool *tp);
  159. #ifndef DBUG_OFF
  160. /*
  161. This function is useful for debugging to make sure all mutexes are released
  162. inside a task callback
  163. */
  164. void set_after_task_callback(callback_func_np cb);
  165. void execute_after_task_callback();
  166. #define dbug_execute_after_task_callback() execute_after_task_callback()
  167. #else
  168. #define dbug_execute_after_task_callback() do{}while(0)
  169. #endif
  170. class thread_pool
  171. {
  172. protected:
  173. /* AIO handler */
  174. std::unique_ptr<aio> m_aio;
  175. virtual aio *create_native_aio(int max_io)= 0;
  176. /**
  177. Functions to be called at worker thread start/end
  178. can be used for example to set some TLS variables
  179. */
  180. void (*m_worker_init_callback)(void);
  181. void (*m_worker_destroy_callback)(void);
  182. public:
  183. thread_pool() : m_aio(), m_worker_init_callback(), m_worker_destroy_callback()
  184. {
  185. }
  186. virtual void submit_task(task *t)= 0;
  187. virtual timer* create_timer(callback_func func, void *data=nullptr) = 0;
  188. void set_thread_callbacks(void (*init)(), void (*destroy)())
  189. {
  190. m_worker_init_callback= init;
  191. m_worker_destroy_callback= destroy;
  192. }
  193. int configure_aio(bool use_native_aio, int max_io)
  194. {
  195. if (use_native_aio)
  196. m_aio.reset(create_native_aio(max_io));
  197. if (!m_aio)
  198. m_aio.reset(create_simulated_aio(this));
  199. return !m_aio ? -1 : 0;
  200. }
  201. void disable_aio()
  202. {
  203. m_aio.reset();
  204. }
  205. int bind(native_file_handle &fd) { return m_aio->bind(fd); }
  206. void unbind(const native_file_handle &fd) { m_aio->unbind(fd); }
  207. int submit_io(aiocb *cb) { return m_aio->submit_io(cb); }
  208. virtual void wait_begin() {};
  209. virtual void wait_end() {};
  210. virtual ~thread_pool() {}
  211. };
  212. const int DEFAULT_MIN_POOL_THREADS= 1;
  213. const int DEFAULT_MAX_POOL_THREADS= 500;
  214. extern thread_pool *
  215. create_thread_pool_generic(int min_threads= DEFAULT_MIN_POOL_THREADS,
  216. int max_threads= DEFAULT_MAX_POOL_THREADS);
  217. extern "C" void tpool_wait_begin();
  218. extern "C" void tpool_wait_end();
  219. #ifdef _WIN32
  220. extern thread_pool *
  221. create_thread_pool_win(int min_threads= DEFAULT_MIN_POOL_THREADS,
  222. int max_threads= DEFAULT_MAX_POOL_THREADS);
  223. /*
  224. Helper functions, to execute pread/pwrite even if file is
  225. opened with FILE_FLAG_OVERLAPPED, and bound to completion
  226. port.
  227. */
  228. int pwrite(const native_file_handle &h, void *buf, size_t count,
  229. unsigned long long offset);
  230. int pread(const native_file_handle &h, void *buf, size_t count,
  231. unsigned long long offset);
  232. HANDLE win_get_syncio_event();
  233. #endif
  234. } // namespace tpool