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 * 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 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 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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