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 02110-1335 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: Apc_target()49 Apc_target() : enabled(0), apc_calls(NULL) {} ~Apc_target()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. */ destroy()55 void destroy() { DBUG_ASSERT(!enabled); } 56 57 /* Enter ther state where the target is available for serving APC requests */ enable()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 */ disable()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 */ have_apc_requests()82 inline bool have_apc_requests() 83 { 84 return MY_TEST(apc_calls); 85 } 86 is_enabled()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; ~Apc_call()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 */ get_first_in_queue()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