1 | #ifndef SQL_MY_APC_INCLUDED |
2 | #define SQL_MY_APC_INCLUDED |
3 | /* |
4 | Copyright (c) 2011, 2013 Monty Program Ab. |
5 | |
6 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ |
18 | |
19 | /* |
20 | Interface |
21 | ~~~~~~~~~ |
22 | ( |
23 | - This is an APC request queue |
24 | - We assume there is a particular owner thread which periodically calls |
25 | process_apc_requests() to serve the call requests. |
26 | - Other threads can post call requests, and block until they are exectued. |
27 | ) |
28 | |
29 | Implementation |
30 | ~~~~~~~~~~~~~~ |
31 | - The target has a mutex-guarded request queue. |
32 | |
33 | - After the request has been put into queue, the requestor waits for request |
34 | to be satisfied. The worker satisifes the request and signals the |
35 | requestor. |
36 | */ |
37 | |
38 | class THD; |
39 | |
40 | /* |
41 | Target for asynchronous procedure calls (APCs). |
42 | - A target is running in some particular thread, |
43 | - One can make calls to it from other threads. |
44 | */ |
45 | class Apc_target |
46 | { |
47 | mysql_mutex_t *LOCK_thd_kill_ptr; |
48 | public: |
49 | Apc_target() : enabled(0), apc_calls(NULL) {} |
50 | ~Apc_target() { DBUG_ASSERT(!enabled && !apc_calls);} |
51 | |
52 | void init(mysql_mutex_t *target_mutex); |
53 | |
54 | /* Destroy the target. The target must be disabled when this call is made. */ |
55 | void destroy() { DBUG_ASSERT(!enabled); } |
56 | |
57 | /* Enter ther state where the target is available for serving APC requests */ |
58 | void enable() { enabled++; } |
59 | |
60 | /* |
61 | Make the target unavailable for serving APC requests. |
62 | |
63 | @note |
64 | This call will serve all requests that were already enqueued |
65 | */ |
66 | void disable() |
67 | { |
68 | DBUG_ASSERT(enabled); |
69 | mysql_mutex_lock(LOCK_thd_kill_ptr); |
70 | bool process= !--enabled && have_apc_requests(); |
71 | mysql_mutex_unlock(LOCK_thd_kill_ptr); |
72 | if (unlikely(process)) |
73 | process_apc_requests(); |
74 | } |
75 | |
76 | void process_apc_requests(); |
77 | /* |
78 | A lightweight function, intended to be used in frequent checks like this: |
79 | |
80 | if (apc_target.have_requests()) apc_target.process_apc_requests() |
81 | */ |
82 | inline bool have_apc_requests() |
83 | { |
84 | return MY_TEST(apc_calls); |
85 | } |
86 | |
87 | inline bool is_enabled() { return enabled; } |
88 | |
89 | /* Functor class for calls you can schedule */ |
90 | class Apc_call |
91 | { |
92 | public: |
93 | /* This function will be called in the target thread */ |
94 | virtual void call_in_target_thread()= 0; |
95 | virtual ~Apc_call() {} |
96 | }; |
97 | |
98 | /* Make a call in the target thread (see function definition for details) */ |
99 | bool make_apc_call(THD *caller_thd, Apc_call *call, int timeout_sec, bool *timed_out); |
100 | |
101 | #ifndef DBUG_OFF |
102 | int n_calls_processed; /* Number of calls served by this target */ |
103 | #endif |
104 | private: |
105 | class Call_request; |
106 | |
107 | /* |
108 | Non-zero value means we're enabled. It's an int, not bool, because one can |
109 | call enable() N times (and then needs to call disable() N times before the |
110 | target is really disabled) |
111 | */ |
112 | int enabled; |
113 | |
114 | /* |
115 | Circular, double-linked list of all enqueued call requests. |
116 | We use this structure, because we |
117 | - process requests sequentially: requests are added at the end of the |
118 | list and removed from the front. With circular list, we can keep one |
119 | pointer, and access both front an back of the list with it. |
120 | - a thread that has posted a request may time out (or be KILLed) and |
121 | cancel the request, which means we need a fast request-removal |
122 | operation. |
123 | */ |
124 | Call_request *apc_calls; |
125 | |
126 | class Call_request |
127 | { |
128 | public: |
129 | Apc_call *call; /* Functor to be called */ |
130 | |
131 | /* The caller will actually wait for "processed==TRUE" */ |
132 | bool processed; |
133 | |
134 | /* Condition that will be signalled when the request has been served */ |
135 | mysql_cond_t COND_request; |
136 | |
137 | /* Double linked-list linkage */ |
138 | Call_request *next; |
139 | Call_request *prev; |
140 | |
141 | const char *what; /* (debug) state of the request */ |
142 | }; |
143 | |
144 | void enqueue_request(Call_request *qe); |
145 | void dequeue_request(Call_request *qe); |
146 | |
147 | /* return the first call request in queue, or NULL if there are none enqueued */ |
148 | Call_request *get_first_in_queue() |
149 | { |
150 | return apc_calls; |
151 | } |
152 | }; |
153 | |
154 | #ifdef HAVE_PSI_INTERFACE |
155 | void init_show_explain_psi_keys(void); |
156 | #else |
157 | #define init_show_explain_psi_keys() /* no-op */ |
158 | #endif |
159 | |
160 | #endif //SQL_MY_APC_INCLUDED |
161 | |
162 | |