1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * BSD 3 Clause License
8 *
9 * Copyright (c) 2007, The Storage Networking Industry Association.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 *
22 * - Neither the name of The Storage Networking Industry Association (SNIA)
23 * nor the names of its contributors may be used to endorse or promote
24 * products derived from this software without specific prior written
25 * permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <sys/errno.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <pthread.h>
45 #include <synch.h>
46 #include <tlm_buffers.h>
47 #include <tlm.h>
48 #include "tlm_proto.h"
49
50
51 /*
52 * tlm_allocate_buffers
53 *
54 * build a set of buffers
55 */
56 tlm_buffers_t *
tlm_allocate_buffers(boolean_t write,long xfer_size)57 tlm_allocate_buffers(boolean_t write, long xfer_size)
58 {
59 tlm_buffers_t *buffers = ndmp_malloc(sizeof (tlm_buffers_t));
60 int buf;
61
62 if (buffers == 0)
63 return (0);
64
65 for (buf = 0; buf < TLM_TAPE_BUFFERS; buf++) {
66 buffers->tbs_buffer[buf].tb_buffer_data =
67 ndmp_malloc(xfer_size);
68 if (buffers->tbs_buffer[buf].tb_buffer_data == 0) {
69 int i;
70
71 /* Memory allocation failed. Give everything back */
72 for (i = 0; i < buf; i++)
73 free(buffers->tbs_buffer[i].tb_buffer_data);
74
75 free(buffers);
76 return (0);
77 } else {
78 buffers->tbs_buffer[buf].tb_buffer_size = (write)
79 ? xfer_size : 0;
80 buffers->tbs_buffer[buf].tb_full = FALSE;
81 buffers->tbs_buffer[buf].tb_eof = FALSE;
82 buffers->tbs_buffer[buf].tb_eot = FALSE;
83 buffers->tbs_buffer[buf].tb_errno = 0;
84 buffers->tbs_buffer[buf].tb_buffer_spot = 0;
85 }
86
87 }
88
89 (void) mutex_init(&buffers->tbs_mtx, 0, NULL);
90 (void) cond_init(&buffers->tbs_in_cv, 0, NULL);
91 (void) cond_init(&buffers->tbs_out_cv, 0, NULL);
92
93 buffers->tbs_data_transfer_size = xfer_size;
94 buffers->tbs_ref = 1;
95 return (buffers);
96 }
97
98 /*
99 * tlm_release_buffers
100 *
101 * give all memory back to the OS
102 */
103 void
tlm_release_buffers(tlm_buffers_t * buffers)104 tlm_release_buffers(tlm_buffers_t *buffers)
105 {
106 int i;
107
108 if (buffers != NULL) {
109 tlm_buffer_release_in_buf(buffers);
110 tlm_buffer_release_out_buf(buffers);
111
112 (void) mutex_lock(&buffers->tbs_mtx);
113
114 if (--buffers->tbs_ref <= 0) {
115 for (i = 0; i < TLM_TAPE_BUFFERS; i++)
116 free(buffers->tbs_buffer[i].tb_buffer_data);
117
118 }
119
120 (void) cond_destroy(&buffers->tbs_in_cv);
121 (void) cond_destroy(&buffers->tbs_out_cv);
122 (void) mutex_unlock(&buffers->tbs_mtx);
123 (void) mutex_destroy(&buffers->tbs_mtx);
124 free(buffers);
125 }
126 }
127
128 /*
129 * tlm_buffer_mark_empty
130 *
131 * Mark a buffer empty and clear its flags. No lock is take here:
132 * the buffer should be marked empty before it is released for use
133 * by another thread.
134 */
135 void
tlm_buffer_mark_empty(tlm_buffer_t * buf)136 tlm_buffer_mark_empty(tlm_buffer_t *buf)
137 {
138 if (buf == NULL)
139 return;
140
141 buf->tb_full = buf->tb_eof = buf->tb_eot = FALSE;
142 buf->tb_errno = 0;
143 }
144
145
146 /*
147 * tlm_buffer_advance_in_idx
148 *
149 * Advance the input index of the buffers(round-robin) and return pointer
150 * to the next buffer in the buffer pool.
151 */
152 tlm_buffer_t *
tlm_buffer_advance_in_idx(tlm_buffers_t * bufs)153 tlm_buffer_advance_in_idx(tlm_buffers_t *bufs)
154 {
155 if (bufs == NULL)
156 return (NULL);
157
158 (void) mutex_lock(&bufs->tbs_mtx);
159 if (++bufs->tbs_buffer_in >= TLM_TAPE_BUFFERS)
160 bufs->tbs_buffer_in = 0;
161
162 (void) mutex_unlock(&bufs->tbs_mtx);
163 return (&bufs->tbs_buffer[bufs->tbs_buffer_in]);
164 }
165
166
167 /*
168 * tlm_buffer_advance_out_idx
169 *
170 * Advance the output index of the buffers(round-robin) and return pointer
171 * to the next buffer in the buffer pool.
172 */
173 tlm_buffer_t *
tlm_buffer_advance_out_idx(tlm_buffers_t * bufs)174 tlm_buffer_advance_out_idx(tlm_buffers_t *bufs)
175 {
176 if (bufs == NULL)
177 return (NULL);
178
179 (void) mutex_lock(&bufs->tbs_mtx);
180 if (++bufs->tbs_buffer_out >= TLM_TAPE_BUFFERS)
181 bufs->tbs_buffer_out = 0;
182
183 (void) mutex_unlock(&bufs->tbs_mtx);
184 return (&bufs->tbs_buffer[bufs->tbs_buffer_out]);
185 }
186
187
188 /*
189 * tlm_buffer_in_buf
190 *
191 * Return pointer to the next buffer in the buffer pool.
192 */
193 tlm_buffer_t *
tlm_buffer_in_buf(tlm_buffers_t * bufs,int * idx)194 tlm_buffer_in_buf(tlm_buffers_t *bufs, int *idx)
195 {
196 tlm_buffer_t *ret;
197
198 if (bufs == NULL)
199 return (NULL);
200
201 (void) mutex_lock(&bufs->tbs_mtx);
202 ret = &bufs->tbs_buffer[bufs->tbs_buffer_in];
203 if (idx)
204 *idx = bufs->tbs_buffer_in;
205 (void) mutex_unlock(&bufs->tbs_mtx);
206 return (ret);
207 }
208
209
210 /*
211 * tlm_buffer_out_buf
212 *
213 * Return pointer to the next buffer in the buffer pool.
214 */
215 tlm_buffer_t *
tlm_buffer_out_buf(tlm_buffers_t * bufs,int * idx)216 tlm_buffer_out_buf(tlm_buffers_t *bufs, int *idx)
217 {
218 tlm_buffer_t *ret;
219
220 if (bufs == NULL)
221 return (NULL);
222
223 (void) mutex_lock(&bufs->tbs_mtx);
224 ret = &bufs->tbs_buffer[bufs->tbs_buffer_out];
225 if (idx)
226 *idx = bufs->tbs_buffer_out;
227 (void) mutex_unlock(&bufs->tbs_mtx);
228 return (ret);
229 }
230
231
232 /*
233 * tlm_buffer_release_in_buf
234 *
235 * Another buffer is filled. Wake up the consumer if it's waiting for it.
236 */
237 void
tlm_buffer_release_in_buf(tlm_buffers_t * bufs)238 tlm_buffer_release_in_buf(tlm_buffers_t *bufs)
239 {
240 (void) mutex_lock(&bufs->tbs_mtx);
241 bufs->tbs_flags |= TLM_BUF_IN_READY;
242 (void) cond_signal(&bufs->tbs_in_cv);
243 (void) mutex_unlock(&bufs->tbs_mtx);
244 }
245
246
247 /*
248 * tlm_buffer_release_out_buf
249 *
250 * A buffer is used. Wake up the producer to re-fill a buffer if it's waiting
251 * for the buffer to be used.
252 */
253 void
tlm_buffer_release_out_buf(tlm_buffers_t * bufs)254 tlm_buffer_release_out_buf(tlm_buffers_t *bufs)
255 {
256 (void) mutex_lock(&bufs->tbs_mtx);
257 bufs->tbs_flags |= TLM_BUF_OUT_READY;
258 (void) cond_signal(&bufs->tbs_out_cv);
259 (void) mutex_unlock(&bufs->tbs_mtx);
260 }
261
262 /*
263 * tlm_buffer_in_buf_wait
264 *
265 * Wait for the input buffer to get available.
266 */
267 void
tlm_buffer_in_buf_wait(tlm_buffers_t * bufs)268 tlm_buffer_in_buf_wait(tlm_buffers_t *bufs)
269
270 {
271 (void) mutex_lock(&bufs->tbs_mtx);
272
273 while ((bufs->tbs_flags & TLM_BUF_IN_READY) == 0)
274 (void) cond_wait(&bufs->tbs_in_cv, &bufs->tbs_mtx);
275
276 bufs->tbs_flags &= ~TLM_BUF_IN_READY;
277
278 (void) mutex_unlock(&bufs->tbs_mtx);
279 }
280
281 /*
282 * tlm_buffer_setup_timer
283 *
284 * Set up the time out value.
285 */
286 static inline void
tlm_buffer_setup_timer(timestruc_t * timo,unsigned milli_timo)287 tlm_buffer_setup_timer(timestruc_t *timo, unsigned milli_timo)
288 {
289 if (milli_timo == 0)
290 milli_timo = 1;
291
292 if (milli_timo / 1000)
293 timo->tv_sec = (milli_timo / 1000);
294 else
295 timo->tv_sec = 0;
296 timo->tv_nsec = (milli_timo % 1000) * 1000000L;
297 }
298
299
300 /*
301 * tlm_buffer_in_buf_timed_wait
302 *
303 * Wait for the input buffer to get ready with a time out.
304 */
305 void
tlm_buffer_in_buf_timed_wait(tlm_buffers_t * bufs,unsigned int milli_timo)306 tlm_buffer_in_buf_timed_wait(tlm_buffers_t *bufs, unsigned int milli_timo)
307
308 {
309 timestruc_t timo;
310
311 tlm_buffer_setup_timer(&timo, milli_timo);
312
313 (void) mutex_lock(&bufs->tbs_mtx);
314
315 (void) cond_reltimedwait(&bufs->tbs_in_cv, &bufs->tbs_mtx, &timo);
316
317 /*
318 * TLM_BUF_IN_READY doesn't matter for timedwait but clear
319 * it here so that cond_wait doesn't get the wrong result.
320 */
321 bufs->tbs_flags &= ~TLM_BUF_IN_READY;
322
323 (void) mutex_unlock(&bufs->tbs_mtx);
324 }
325
326
327 /*
328 * tlm_buffer_out_buf_timed_wait
329 *
330 * Wait for the output buffer to get ready with a time out.
331 */
332 void
tlm_buffer_out_buf_timed_wait(tlm_buffers_t * bufs,unsigned int milli_timo)333 tlm_buffer_out_buf_timed_wait(tlm_buffers_t *bufs, unsigned int milli_timo)
334 {
335 timestruc_t timo;
336
337 tlm_buffer_setup_timer(&timo, milli_timo);
338
339 (void) mutex_lock(&bufs->tbs_mtx);
340
341 (void) cond_reltimedwait(&bufs->tbs_out_cv, &bufs->tbs_mtx, &timo);
342
343 /*
344 * TLM_BUF_OUT_READY doesn't matter for timedwait but clear
345 * it here so that cond_wait doesn't get the wrong result.
346 */
347 bufs->tbs_flags &= ~TLM_BUF_OUT_READY;
348
349 (void) mutex_unlock(&bufs->tbs_mtx);
350 }
351
352
353 /*
354 * tlm_cmd_wait
355 *
356 * TLM command synchronization typically use by command
357 * parent threads to wait for launched threads to initialize.
358 */
359 void
tlm_cmd_wait(tlm_cmd_t * cmd,uint32_t event_type)360 tlm_cmd_wait(tlm_cmd_t *cmd, uint32_t event_type)
361 {
362 (void) mutex_lock(&cmd->tc_mtx);
363
364 while ((cmd->tc_flags & event_type) == 0)
365 (void) cond_wait(&cmd->tc_cv, &cmd->tc_mtx);
366
367 cmd->tc_flags &= ~event_type;
368 (void) mutex_unlock(&cmd->tc_mtx);
369 }
370
371
372 /*
373 * tlm_cmd_signal
374 *
375 * TLM command synchronization typically use by launched threads
376 * to unleash the parent thread.
377 */
378 void
tlm_cmd_signal(tlm_cmd_t * cmd,uint32_t event_type)379 tlm_cmd_signal(tlm_cmd_t *cmd, uint32_t event_type)
380 {
381 (void) mutex_lock(&cmd->tc_mtx);
382
383 cmd->tc_flags |= event_type;
384 (void) cond_signal(&cmd->tc_cv);
385
386 (void) mutex_unlock(&cmd->tc_mtx);
387 }
388