1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. 24 */ 25 26 /* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /* 32 * 33 * MODULE: dapl_ring_buffer_util.c 34 * 35 * PURPOSE: Ring buffer management 36 * Description: Support and management functions for ring buffers 37 * 38 * $Id: dapl_ring_buffer_util.c,v 1.9 2003/07/08 14:23:35 sjs2 Exp $ 39 */ 40 41 #include "dapl_ring_buffer_util.h" 42 43 /* 44 * dapls_rbuf_alloc 45 * 46 * Given a DAPL_RING_BUFFER, initialize it and provide memory for 47 * the ringbuf itself. A passed in size will be adjusted to the next 48 * largest power of two number to simplify management. 49 * 50 * Input: 51 * rbuf pointer to DAPL_RING_BUFFER 52 * size number of elements to allocate & manage 53 * 54 * Output: 55 * none 56 * 57 * Returns: 58 * DAT_SUCCESS 59 * DAT_INSUFFICIENT_RESOURCES 60 * 61 */ 62 DAT_RETURN 63 dapls_rbuf_alloc( 64 INOUT DAPL_RING_BUFFER *rbuf, 65 IN DAT_COUNT size) 66 { 67 unsigned int rsize; /* real size */ 68 69 /* 70 * The circular buffer must be allocated one too large. 71 * This eliminates any need for a distinct counter, as that 72 * having the two pointers equal always means "empty" -- never "full" 73 */ 74 size++; 75 76 /* Put size on a power of 2 boundary */ 77 rsize = 1; 78 while ((DAT_COUNT)rsize < size) { 79 rsize <<= 1; 80 } 81 82 rbuf->base = (void *) dapl_os_alloc(rsize * sizeof (void *)); 83 if (rbuf->base != NULL) { 84 rbuf->lim = rsize - 1; 85 rbuf->head = 0; 86 rbuf->tail = 0; 87 dapl_os_lock_init(&rbuf->lock); 88 } else { 89 return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY); 90 } 91 92 return (DAT_SUCCESS); 93 } 94 95 96 /* 97 * dapls_rbuf_realloc 98 * 99 * Resizes an empty DAPL_RING_BUFFER. This function is not thread safe; 100 * adding or removing elements from a ring buffer while resizing 101 * will have indeterminate results. 102 * 103 * Input: 104 * rbuf pointer to DAPL_RING_BUFFER 105 * size number of elements to allocate & manage 106 * 107 * Output: 108 * none 109 * 110 * Returns: 111 * DAT_SUCCESS 112 * DAT_INVALID_STATE 113 * DAT_INSUFFICIENT_RESOURCES 114 * 115 */ 116 DAT_RETURN 117 dapls_rbuf_realloc( 118 INOUT DAPL_RING_BUFFER *rbuf, 119 IN DAT_COUNT size) 120 { 121 int rsize; /* real size */ 122 DAT_RETURN dat_status; 123 124 dat_status = DAT_SUCCESS; 125 126 /* if the ring buffer is not empty */ 127 if (rbuf->head != rbuf->tail) { 128 dat_status = DAT_ERROR(DAT_INVALID_STATE, 0); 129 goto bail; 130 } 131 132 /* Put size on a power of 2 boundary */ 133 rsize = 1; 134 while (rsize < size) { 135 rsize <<= 1; 136 } 137 138 rbuf->base = (void *)dapl_os_realloc(rbuf->base, 139 rsize * sizeof (void *)); 140 if (NULL == rbuf->base) { 141 dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, 142 DAT_RESOURCE_MEMORY); 143 goto bail; 144 } 145 146 rbuf->lim = rsize - 1; 147 148 bail: 149 return (dat_status); 150 } 151 152 153 /* 154 * dapls_rbuf_destroy 155 * 156 * Release the buffer and reset pointers to a DAPL_RING_BUFFER 157 * 158 * Input: 159 * rbuf pointer to DAPL_RING_BUFFER 160 * 161 * Output: 162 * none 163 * 164 * Returns: 165 * none 166 * 167 */ 168 void 169 dapls_rbuf_destroy( 170 IN DAPL_RING_BUFFER *rbuf) 171 { 172 if ((NULL == rbuf) || 173 (NULL == rbuf->base)) { 174 return; 175 } 176 177 dapl_os_lock_destroy(&rbuf->lock); 178 dapl_os_free(rbuf->base, (rbuf->lim + 1) * sizeof (void *)); 179 rbuf->base = NULL; 180 rbuf->lim = 0; 181 } 182 183 /* 184 * dapls_rbuf_add 185 * 186 * Add an entry to the ring buffer 187 * 188 * Input: 189 * rbuf pointer to DAPL_RING_BUFFER 190 * entry entry to add 191 * 192 * Output: 193 * none 194 * 195 * Returns: 196 * DAT_SUCCESS 197 * DAT_INSUFFICIENT_RESOURCES (queue full) 198 * 199 */ 200 DAT_RETURN 201 dapls_rbuf_add( 202 IN DAPL_RING_BUFFER *rbuf, 203 IN void *entry) 204 { 205 DAPL_ATOMIC pos; 206 207 dapl_os_lock(&rbuf->lock); 208 pos = rbuf->head; 209 if (((pos + 1) & rbuf->lim) != rbuf->tail) { 210 rbuf->base[pos] = entry; 211 rbuf->head = (pos + 1) & rbuf->lim; 212 dapl_os_unlock(&rbuf->lock); 213 return (DAT_SUCCESS); 214 } 215 216 dapl_os_unlock(&rbuf->lock); 217 return (DAT_ERROR(DAT_INSUFFICIENT_RESOURCES, DAT_RESOURCE_MEMORY)); 218 } 219 220 221 /* 222 * dapls_rbuf_remove 223 * 224 * Remove an entry from the ring buffer 225 * 226 * Input: 227 * rbuf pointer to DAPL_RING_BUFFER 228 * 229 * Output: 230 * entry entry removed from the ring buffer 231 * 232 * Returns: 233 * a pointer to a buffer entry 234 */ 235 void * 236 dapls_rbuf_remove( 237 IN DAPL_RING_BUFFER *rbuf) 238 { 239 DAPL_ATOMIC pos; 240 241 dapl_os_lock(&rbuf->lock); 242 if (rbuf->head != rbuf->tail) { 243 pos = rbuf->tail; 244 rbuf->tail = (pos + 1) & rbuf->lim; 245 dapl_os_unlock(&rbuf->lock); 246 return (rbuf->base[pos]); 247 } 248 249 dapl_os_unlock(&rbuf->lock); 250 return (NULL); 251 } 252 253 254 /* 255 * dapli_rbuf_count 256 * 257 * Return the number of entries in use in the ring buffer 258 * 259 * Input: 260 * rbuf pointer to DAPL_RING_BUFFER 261 * 262 * Output: 263 * none 264 * 265 * Returns: 266 * count of entries 267 * 268 */ 269 DAT_COUNT 270 dapls_rbuf_count( 271 IN DAPL_RING_BUFFER *rbuf) 272 { 273 int head; 274 int tail; 275 276 dapl_os_lock(&rbuf->lock); 277 head = rbuf->head; 278 tail = rbuf->tail; 279 dapl_os_unlock(&rbuf->lock); 280 if (head == tail) 281 return (0); 282 if (head > tail) 283 return (head - tail); 284 /* add 1 to lim as it is a mask, number of entries - 1 */ 285 return ((rbuf->lim + 1 - tail + head)); 286 } 287