2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
9 * Copyright (c) 2007, The Storage Networking Industry Association.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
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
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
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.
41 #include <sys/errno.h>
46 #include <tlm_buffers.h>
48 #include "tlm_proto.h"
52 * tlm_allocate_buffers
54 * build a set of buffers
57 tlm_allocate_buffers(boolean_t write
, long xfer_size
)
59 tlm_buffers_t
*buffers
= ndmp_malloc(sizeof (tlm_buffers_t
));
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) {
71 /* Memory allocation failed. Give everything back */
72 for (i
= 0; i
< buf
; i
++)
73 free(buffers
->tbs_buffer
[i
].tb_buffer_data
);
78 buffers
->tbs_buffer
[buf
].tb_buffer_size
= (write
)
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;
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
);
93 buffers
->tbs_data_transfer_size
= xfer_size
;
101 * give all memory back to the OS
104 tlm_release_buffers(tlm_buffers_t
*buffers
)
108 if (buffers
!= NULL
) {
109 tlm_buffer_release_in_buf(buffers
);
110 tlm_buffer_release_out_buf(buffers
);
112 (void) mutex_lock(&buffers
->tbs_mtx
);
114 if (--buffers
->tbs_ref
<= 0) {
115 for (i
= 0; i
< TLM_TAPE_BUFFERS
; i
++)
116 free(buffers
->tbs_buffer
[i
].tb_buffer_data
);
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
);
129 * tlm_buffer_mark_empty
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
136 tlm_buffer_mark_empty(tlm_buffer_t
*buf
)
141 buf
->tb_full
= buf
->tb_eof
= buf
->tb_eot
= FALSE
;
147 * tlm_buffer_advance_in_idx
149 * Advance the input index of the buffers(round-robin) and return pointer
150 * to the next buffer in the buffer pool.
153 tlm_buffer_advance_in_idx(tlm_buffers_t
*bufs
)
158 (void) mutex_lock(&bufs
->tbs_mtx
);
159 if (++bufs
->tbs_buffer_in
>= TLM_TAPE_BUFFERS
)
160 bufs
->tbs_buffer_in
= 0;
162 (void) mutex_unlock(&bufs
->tbs_mtx
);
163 return (&bufs
->tbs_buffer
[bufs
->tbs_buffer_in
]);
168 * tlm_buffer_advance_out_idx
170 * Advance the output index of the buffers(round-robin) and return pointer
171 * to the next buffer in the buffer pool.
174 tlm_buffer_advance_out_idx(tlm_buffers_t
*bufs
)
179 (void) mutex_lock(&bufs
->tbs_mtx
);
180 if (++bufs
->tbs_buffer_out
>= TLM_TAPE_BUFFERS
)
181 bufs
->tbs_buffer_out
= 0;
183 (void) mutex_unlock(&bufs
->tbs_mtx
);
184 return (&bufs
->tbs_buffer
[bufs
->tbs_buffer_out
]);
191 * Return pointer to the next buffer in the buffer pool.
194 tlm_buffer_in_buf(tlm_buffers_t
*bufs
, int *idx
)
201 (void) mutex_lock(&bufs
->tbs_mtx
);
202 ret
= &bufs
->tbs_buffer
[bufs
->tbs_buffer_in
];
204 *idx
= bufs
->tbs_buffer_in
;
205 (void) mutex_unlock(&bufs
->tbs_mtx
);
213 * Return pointer to the next buffer in the buffer pool.
216 tlm_buffer_out_buf(tlm_buffers_t
*bufs
, int *idx
)
223 (void) mutex_lock(&bufs
->tbs_mtx
);
224 ret
= &bufs
->tbs_buffer
[bufs
->tbs_buffer_out
];
226 *idx
= bufs
->tbs_buffer_out
;
227 (void) mutex_unlock(&bufs
->tbs_mtx
);
233 * tlm_buffer_release_in_buf
235 * Another buffer is filled. Wake up the consumer if it's waiting for it.
238 tlm_buffer_release_in_buf(tlm_buffers_t
*bufs
)
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
);
248 * tlm_buffer_release_out_buf
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.
254 tlm_buffer_release_out_buf(tlm_buffers_t
*bufs
)
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
);
263 * tlm_buffer_in_buf_wait
265 * Wait for the input buffer to get available.
268 tlm_buffer_in_buf_wait(tlm_buffers_t
*bufs
)
271 (void) mutex_lock(&bufs
->tbs_mtx
);
273 while ((bufs
->tbs_flags
& TLM_BUF_IN_READY
) == 0)
274 (void) cond_wait(&bufs
->tbs_in_cv
, &bufs
->tbs_mtx
);
276 bufs
->tbs_flags
&= ~TLM_BUF_IN_READY
;
278 (void) mutex_unlock(&bufs
->tbs_mtx
);
282 * tlm_buffer_setup_timer
284 * Set up the time out value.
287 tlm_buffer_setup_timer(timestruc_t
*timo
, unsigned milli_timo
)
292 if (milli_timo
/ 1000)
293 timo
->tv_sec
= (milli_timo
/ 1000);
296 timo
->tv_nsec
= (milli_timo
% 1000) * 1000000L;
301 * tlm_buffer_in_buf_timed_wait
303 * Wait for the input buffer to get ready with a time out.
306 tlm_buffer_in_buf_timed_wait(tlm_buffers_t
*bufs
, unsigned int milli_timo
)
311 tlm_buffer_setup_timer(&timo
, milli_timo
);
313 (void) mutex_lock(&bufs
->tbs_mtx
);
315 (void) cond_reltimedwait(&bufs
->tbs_in_cv
, &bufs
->tbs_mtx
, &timo
);
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.
321 bufs
->tbs_flags
&= ~TLM_BUF_IN_READY
;
323 (void) mutex_unlock(&bufs
->tbs_mtx
);
328 * tlm_buffer_out_buf_timed_wait
330 * Wait for the output buffer to get ready with a time out.
333 tlm_buffer_out_buf_timed_wait(tlm_buffers_t
*bufs
, unsigned int milli_timo
)
337 tlm_buffer_setup_timer(&timo
, milli_timo
);
339 (void) mutex_lock(&bufs
->tbs_mtx
);
341 (void) cond_reltimedwait(&bufs
->tbs_out_cv
, &bufs
->tbs_mtx
, &timo
);
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.
347 bufs
->tbs_flags
&= ~TLM_BUF_OUT_READY
;
349 (void) mutex_unlock(&bufs
->tbs_mtx
);
356 * TLM command synchronization typically use by command
357 * parent threads to wait for launched threads to initialize.
360 tlm_cmd_wait(tlm_cmd_t
*cmd
, uint32_t event_type
)
362 (void) mutex_lock(&cmd
->tc_mtx
);
364 while ((cmd
->tc_flags
& event_type
) == 0)
365 (void) cond_wait(&cmd
->tc_cv
, &cmd
->tc_mtx
);
367 cmd
->tc_flags
&= ~event_type
;
368 (void) mutex_unlock(&cmd
->tc_mtx
);
375 * TLM command synchronization typically use by launched threads
376 * to unleash the parent thread.
379 tlm_cmd_signal(tlm_cmd_t
*cmd
, uint32_t event_type
)
381 (void) mutex_lock(&cmd
->tc_mtx
);
383 cmd
->tc_flags
|= event_type
;
384 (void) cond_signal(&cmd
->tc_cv
);
386 (void) mutex_unlock(&cmd
->tc_mtx
);