1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 2006, 2015, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | #include "ut0list.h" |
21 | #include "mem0mem.h" |
22 | #include "ut0wqueue.h" |
23 | |
24 | /*******************************************************************//** |
25 | @file ut/ut0wqueue.cc |
26 | A work queue |
27 | |
28 | Created 4/26/2006 Osku Salerma |
29 | ************************************************************************/ |
30 | |
31 | /* Work queue. */ |
32 | struct ib_wqueue_t { |
33 | ib_mutex_t mutex; /*!< mutex protecting everything */ |
34 | ib_list_t* items; /*!< work item list */ |
35 | os_event_t event; /*!< event we use to signal additions to list; |
36 | os_event_set() and os_event_reset() are |
37 | protected by ib_wqueue_t::mutex */ |
38 | }; |
39 | |
40 | /****************************************************************//** |
41 | Create a new work queue. |
42 | @return work queue */ |
43 | ib_wqueue_t* |
44 | ib_wqueue_create(void) |
45 | /*===================*/ |
46 | { |
47 | ib_wqueue_t* wq = static_cast<ib_wqueue_t*>( |
48 | ut_malloc_nokey(sizeof(*wq))); |
49 | |
50 | /* Function ib_wqueue_create() has not been used anywhere, |
51 | not necessary to instrument this mutex */ |
52 | |
53 | mutex_create(LATCH_ID_WORK_QUEUE, &wq->mutex); |
54 | |
55 | wq->items = ib_list_create(); |
56 | wq->event = os_event_create(0); |
57 | |
58 | return(wq); |
59 | } |
60 | |
61 | /****************************************************************//** |
62 | Free a work queue. */ |
63 | void |
64 | ib_wqueue_free( |
65 | /*===========*/ |
66 | ib_wqueue_t* wq) /*!< in: work queue */ |
67 | { |
68 | mutex_free(&wq->mutex); |
69 | ib_list_free(wq->items); |
70 | os_event_destroy(wq->event); |
71 | |
72 | ut_free(wq); |
73 | } |
74 | |
75 | /****************************************************************//** |
76 | Add a work item to the queue. */ |
77 | void |
78 | ib_wqueue_add( |
79 | /*==========*/ |
80 | ib_wqueue_t* wq, /*!< in: work queue */ |
81 | void* item, /*!< in: work item */ |
82 | mem_heap_t* heap) /*!< in: memory heap to use for allocating the |
83 | list node */ |
84 | { |
85 | mutex_enter(&wq->mutex); |
86 | |
87 | ib_list_add_last(wq->items, item, heap); |
88 | os_event_set(wq->event); |
89 | |
90 | mutex_exit(&wq->mutex); |
91 | } |
92 | |
93 | /****************************************************************//** |
94 | Wait for a work item to appear in the queue. |
95 | @return work item */ |
96 | void* |
97 | ib_wqueue_wait( |
98 | /*===========*/ |
99 | ib_wqueue_t* wq) /*!< in: work queue */ |
100 | { |
101 | ib_list_node_t* node; |
102 | |
103 | for (;;) { |
104 | os_event_wait(wq->event); |
105 | |
106 | mutex_enter(&wq->mutex); |
107 | |
108 | node = ib_list_get_first(wq->items); |
109 | |
110 | if (node) { |
111 | ib_list_remove(wq->items, node); |
112 | |
113 | if (!ib_list_get_first(wq->items)) { |
114 | /* We must reset the event when the list |
115 | gets emptied. */ |
116 | os_event_reset(wq->event); |
117 | } |
118 | |
119 | break; |
120 | } |
121 | |
122 | mutex_exit(&wq->mutex); |
123 | } |
124 | |
125 | mutex_exit(&wq->mutex); |
126 | |
127 | return(node->data); |
128 | } |
129 | |
130 | |
131 | /******************************************************************** |
132 | Wait for a work item to appear in the queue for specified time. */ |
133 | void* |
134 | ib_wqueue_timedwait( |
135 | /*================*/ |
136 | /* out: work item or NULL on timeout*/ |
137 | ib_wqueue_t* wq, /* in: work queue */ |
138 | ib_time_t wait_in_usecs) /* in: wait time in micro seconds */ |
139 | { |
140 | ib_list_node_t* node = NULL; |
141 | |
142 | for (;;) { |
143 | ulint error; |
144 | int64_t sig_count; |
145 | |
146 | mutex_enter(&wq->mutex); |
147 | |
148 | node = ib_list_get_first(wq->items); |
149 | |
150 | if (node) { |
151 | ib_list_remove(wq->items, node); |
152 | |
153 | mutex_exit(&wq->mutex); |
154 | break; |
155 | } |
156 | |
157 | sig_count = os_event_reset(wq->event); |
158 | |
159 | mutex_exit(&wq->mutex); |
160 | |
161 | error = os_event_wait_time_low(wq->event, |
162 | (ulint) wait_in_usecs, |
163 | sig_count); |
164 | |
165 | if (error == OS_SYNC_TIME_EXCEEDED) { |
166 | break; |
167 | } |
168 | } |
169 | |
170 | return(node ? node->data : NULL); |
171 | } |
172 | |
173 | /******************************************************************** |
174 | Return first item on work queue or NULL if queue is empty |
175 | @return work item or NULL */ |
176 | void* |
177 | ib_wqueue_nowait( |
178 | /*=============*/ |
179 | ib_wqueue_t* wq) /*<! in: work queue */ |
180 | { |
181 | ib_list_node_t* node = NULL; |
182 | |
183 | mutex_enter(&wq->mutex); |
184 | |
185 | if(!ib_list_is_empty(wq->items)) { |
186 | node = ib_list_get_first(wq->items); |
187 | |
188 | if (node) { |
189 | ib_list_remove(wq->items, node); |
190 | |
191 | } |
192 | } |
193 | |
194 | /* We must reset the event when the list |
195 | gets emptied. */ |
196 | if(ib_list_is_empty(wq->items)) { |
197 | os_event_reset(wq->event); |
198 | } |
199 | |
200 | mutex_exit(&wq->mutex); |
201 | |
202 | return (node ? node->data : NULL); |
203 | } |
204 | /******************************************************************** |
205 | Check if queue is empty. */ |
206 | ibool |
207 | ib_wqueue_is_empty( |
208 | /*===============*/ |
209 | /* out: TRUE if queue empty |
210 | else FALSE */ |
211 | const ib_wqueue_t* wq) /* in: work queue */ |
212 | { |
213 | return(ib_list_is_empty(wq->items)); |
214 | } |
215 | |
216 | /******************************************************************** |
217 | Get number of items on queue. |
218 | @return number of items on queue */ |
219 | ulint |
220 | ib_wqueue_len( |
221 | /*==========*/ |
222 | ib_wqueue_t* wq) /*<! in: work queue */ |
223 | { |
224 | ulint len = 0; |
225 | |
226 | mutex_enter(&wq->mutex); |
227 | len = ib_list_len(wq->items); |
228 | mutex_exit(&wq->mutex); |
229 | |
230 | return(len); |
231 | } |
232 | |