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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "@(#)shm_best_ops.c 1.16 09/05/26 SMI" 28 29 /* 30 * shared memory operations. They support the attaching and 31 * detaching of shared memory, to reduce the overall address space 32 * usage on a 32 bit system. All this extra work is a waste of 33 * time on a 64 bit system at present. 34 */ 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <limits.h> 38 #include <stdio.h> 39 #include <errno.h> 40 41 #include <diskomizer/log.h> 42 #include "shm_ops.h" 43 #include "list.h" 44 #include <diskomizer/assert.h> 45 46 static struct shm_ops *all_ops[] = {&shm_bestshm_ops, &shm_mmap_ops, NULL}; 47 static int hasfailed; 48 static struct best_shm *head; 49 struct best_shm { 50 void *handle; 51 void *addr; 52 int ref; 53 shm_flags flags; 54 ulong_t len; 55 struct shm_ops *ops; 56 struct best_shm *allnext; 57 struct best_shm *next; 58 struct best_shm *prev; 59 }; 60 struct list_head { 61 struct best_shm *head; 62 struct best_shm *tail; 63 }; 64 static struct list_head free_list, active_list; 65 66 #define PRINT_LIST(LIST_HEAD, NEXT) { \ 67 struct best_shm *x; \ 68 plog(LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, #LIST_HEAD); \ 69 for (x = LIST_HEAD; x != NULL; x = x->NEXT) { \ 70 plog(LOG_DEBUG, "List %s Handle %#lx, Addr %#lx, " \ 71 "ref %d type %s\n", #LIST_HEAD, \ 72 (ulong_t)x->handle, (ulong_t)x->addr, \ 73 x->ref, x->ops->name(x->handle)); \ 74 plog(LOG_DEBUG, "execute %d write %d allow_detach %d " \ 75 "always_detach %d\n", \ 76 x->flags.execute, x->flags.write, \ 77 x->flags.allow_detach, x->flags.always_detach); \ 78 plog(LOG_DEBUG, "x %#lx, next %#lx, prev %#lx, len %ld\n", \ 79 (ulong_t)x, (ulong_t)x->next, (ulong_t)x->prev, \ 80 x->len); \ 81 } \ 82 } 83 static void * 84 my_alloc(size_t nelem, size_t elsize) 85 { 86 void *res; 87 long sbrkval; 88 struct best_shm *q; 89 90 res = calloc(nelem, elsize); 91 if (res == NULL && (sbrkval = (long)sbrk(0)) != -1) { 92 sbrkval += (nelem * elsize) + 8192; 93 for (q = free_list.tail; q != NULL && res == NULL; 94 q = q->prev) { 95 if (q->addr != NULL && q->ref == 0) 96 if ((ulong_t)q->addr <= sbrkval) { 97 if (q->ops->detach(q->handle) != 98 SHM_DETACH_ERR) { 99 q->addr = NULL; 100 res = calloc(nelem, elsize); 101 } 102 } 103 } 104 } 105 for (q = free_list.tail; q != NULL && res == NULL; q = q->prev) { 106 if (q->addr != NULL && q->ref == 0) { 107 if (q->ops->detach(q->handle) != SHM_DETACH_ERR) { 108 q->addr = NULL; 109 res = calloc(nelem, elsize); 110 } 111 } 112 } 113 return (res); 114 } 115 116 void 117 try_init(struct best_shm *x, long a, long b, shm_flags flags) 118 { 119 struct best_shm *q; 120 int i; 121 122 for (i = flags.allow_detach ? 0 : 1; all_ops[i] != NULL; i++) { 123 x->ops = all_ops[i]; 124 flags.always_detach = 1; 125 if ((x->handle = x->ops->init(a, b, flags)) != NULL) { 126 x->addr = x->ops->attach(x->handle); 127 for (q = free_list.tail; x->addr == NULL && q != NULL; 128 q = q->prev) { 129 assert(q->ref == 0); 130 if (q->addr != NULL && q->flags.allow_detach && 131 q->ops->detach(q->handle) != 132 SHM_DETACH_ERR) { 133 q->addr = NULL; 134 x->addr = x->ops->attach(x->handle); 135 } 136 } 137 if (x->addr != NULL) { 138 break; 139 } else { 140 x->ops->destroy(x->handle); 141 } 142 } 143 } 144 } 145 void * 146 best_init(long a, long b, shm_flags flags) 147 { 148 struct best_shm *x; 149 struct best_shm *q; 150 151 x = my_alloc(1, sizeof (struct best_shm)); 152 if (x == NULL) 153 return (NULL); 154 x->flags = flags; 155 156 try_init(x, a, b, flags); 157 for (q = free_list.tail; x->handle == NULL && q != NULL; q = q->prev) { 158 if (q->addr != NULL && q->flags.allow_detach) { 159 assert(q->ref == 0); 160 if (q->ops->detach(q->handle) != SHM_DETACH_ERR) { 161 q->addr = NULL; 162 try_init(x, a, b, flags); 163 } 164 } 165 } 166 if (x->handle == NULL) { 167 free(x); 168 return (NULL); 169 } else { 170 x->allnext = head; 171 head = x; 172 } 173 x->len = a * b; 174 x->ref = 0; 175 LIST_ADD(&free_list, x); 176 return (x); 177 } 178 static ulong_t 179 best_max_size(void) 180 { 181 ulong_t size = 0; 182 int i; 183 184 for (i = 0; all_ops[i] != NULL; i++) { 185 ulong_t tmp = all_ops[i]->max_size(); 186 if (tmp > size) 187 size = tmp; 188 } 189 return (size); 190 } 191 192 /* 193 * The shared memeory is not attached so attach it. If it can't be attached 194 * try detaching other segments until it can be attached or all have been 195 * detached. 196 */ 197 static void * 198 best_do_attach(struct best_shm *x) 199 { 200 struct best_shm *q; 201 202 x->addr = x->ops->attach(x->handle); 203 for (q = free_list.tail; x->addr == NULL && q != NULL; q = q->prev) { 204 shm_det_status status; 205 206 hasfailed = 1; 207 if (q->ref != 0) { 208 PRINT_LIST(head, allnext); 209 210 PRINT_LIST(free_list.head, next); 211 PRINT_LIST(active_list.head, next); 212 exit(1); 213 } 214 if ((errno != EMFILE || q->ops == x->ops)) { 215 if (q->addr != NULL && q->flags.allow_detach && 216 (status = q->ops->detach(q->handle)) != 217 SHM_DETACH_ERR) { 218 q->addr = NULL; 219 if (status == SHM_DETACH_DONE) { 220 x->addr = x->ops->attach(x->handle); 221 } 222 } 223 } 224 } 225 for (q = free_list.tail; x->addr == NULL && q != NULL; q = q->prev) { 226 if (q->addr != NULL && q->flags.allow_detach && 227 q->ops->detach(q->handle) == SHM_DETACH_DONE) { 228 q->addr = NULL; 229 x->addr = x->ops->attach(x->handle); 230 } 231 } 232 if (x->addr != NULL) { 233 if (x->ref == 0) { 234 LIST_REMOVE(&free_list, x); 235 LIST_ADD(&active_list, x); 236 } 237 x->ref++; 238 } else { 239 pperror("Can't attach %s", x->ops->name(x)); 240 PRINT_LIST(head, allnext); 241 PRINT_LIST(free_list.head, next); 242 } 243 return (x->addr); 244 245 } 246 247 static void * 248 best_attach(void * arg) 249 { 250 struct best_shm *x = (struct best_shm *)arg; 251 if (x->addr == NULL) { 252 return (best_do_attach(x)); 253 } else { 254 if (x->ref == 0) { 255 LIST_REMOVE(&free_list, x); 256 LIST_ADD(&active_list, x); 257 } 258 x->ref++; 259 return (x->addr); 260 } 261 } 262 263 static shm_det_status 264 best_move_to_free(struct best_shm *x) 265 { 266 shm_det_status status; 267 268 LIST_REMOVE(&active_list, x); 269 LIST_ADD(&free_list, x); 270 if (x->flags.always_detach) { 271 if ((status = x->ops->detach(x->handle)) != SHM_DETACH_ERR) { 272 x->addr = NULL; 273 return (status); 274 } else { 275 return (SHM_DETACH_ERR); 276 } 277 } 278 return (SHM_DETACH_OK); 279 } 280 shm_det_status 281 best_detach(void *arg) 282 { 283 struct best_shm *x = (struct best_shm *)arg; 284 285 if (--(x->ref) == 0) { 286 return (best_move_to_free(x)); 287 } 288 return (SHM_DETACH_OK); 289 } 290 291 void 292 best_destroy(void *arg) 293 { 294 struct best_shm *x = (struct best_shm *)arg; 295 x->ops->destroy(x->handle); 296 free(x); 297 } 298 static char name[] = "best"; 299 const char * 300 best_name(void *arg) 301 { 302 struct best_shm *x = (struct best_shm *)arg; 303 if (x != NULL) 304 return (x->ops->name(x->handle)); 305 return (&name[0]); 306 } 307 const char * 308 best_longname(void *arg) 309 { 310 struct best_shm *x = (struct best_shm *)arg; 311 if (x != NULL) 312 return (x->ops->longname(x->handle)); 313 return (&name[0]); 314 } 315 static int 316 best_is_short_of_mem(void) 317 { 318 return (hasfailed); 319 } 320 static void 321 best_complete(void *handle) 322 { 323 int i; 324 for (i = 0; all_ops[i] != NULL; i++) { 325 all_ops[i]->complete(handle); 326 } 327 } 328 static void 329 best_fini(void) 330 { 331 int i; 332 for (i = 0; all_ops[i] != NULL; i++) { 333 all_ops[i]->fini(); 334 } 335 } 336 337 struct shm_ops shm_best_ops = { 338 best_name, 339 best_longname, 340 best_init, 341 best_attach, 342 best_detach, 343 best_destroy, 344 best_max_size, 345 best_is_short_of_mem, 346 best_complete, 347 best_fini 348 }; 349