00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #define _XOPEN_SOURCE 600
00030 #define _POSIX_C_SOURCE 200112L
00031
00032
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <errno.h>
00036 #include <limits.h>
00037 #include <sys/types.h>
00038
00039 #include "shmalloc.h"
00040 #include "sharedmem_private.h"
00041
00042
00043
00044
00046 #define BL_SZ(b) ((b)->size & ~SHAREDMEM_FLAGS_MASK)
00047
00048
00049
00050 static void set_error (sharedmem_alloc_t *inst, int error_code,
00051 const char *error_str)
00052 {
00053 _sharedmem_set_error(SHMALLOC_SHAREDMEM(inst), error_code, error_str);
00054 }
00055
00056
00057
00058 static size_t aligned_block_size (size_t size)
00059 {
00060 size_t block_size;
00061
00062 block_size = sizeof(sharedmem_block_t) + size;
00063 block_size += SHAREDMEM_ALIGN - block_size % SHAREDMEM_ALIGN;
00064 return block_size;
00065 }
00066
00067
00068
00069 static inline int block_is_reserved (sharedmem_block_t *block)
00070 {
00071 if (block->size & SHAREDMEM_BLOCK_INUSE)
00072 return 1;
00073 else
00074 return 0;
00075 }
00076
00077
00078
00079 static inline int block_is_free (sharedmem_block_t *block)
00080 {
00081 if (block->size & SHAREDMEM_BLOCK_INUSE)
00082 return 0;
00083 else
00084 return 1;
00085 }
00086
00087
00088
00089 static inline sharedmem_block_t * get_offs_ptr (sharedmem_alloc_t *inst,
00090 long offset)
00091 {
00092 char *base_ptr;
00093
00094 base_ptr = (char *) SHAREDMEM_PTR(SHMALLOC_SHAREDMEM(inst));
00095 return ((sharedmem_block_t *) (base_ptr + offset));
00096 }
00097
00098
00099
00100 static inline long get_data_offs (long offset)
00101 {
00102 return (offset + sizeof(sharedmem_block_t));
00103 }
00104
00105
00106
00107 static long find_free (sharedmem_alloc_t *inst, size_t block_size)
00108 {
00109 long block = 0;
00110 sharedmem_block_t *block_ptr;
00111
00112 while (block >= 0)
00113 {
00114 block_ptr = get_offs_ptr(inst, block);
00115 if (block_is_free(block_ptr))
00116 {
00117 if (BL_SZ(block_ptr) >= block_size)
00118 return block;
00119 }
00120 block = block_ptr->next;
00121 }
00122
00123 return -1;
00124 }
00125
00126
00127
00128 static long get_last_free (sharedmem_alloc_t *inst)
00129 {
00130 long block = 0;
00131 long this;
00132 long next;
00133 sharedmem_block_t *block_ptr;
00134 sharedmem_block_t *next_ptr;
00135
00136 do {
00137 this = block;
00138 block_ptr = get_offs_ptr(inst, block);
00139 block = block_ptr->next;
00140 } while (block >= 0);
00141 if (!block_is_free(block_ptr))
00142 {
00143 next = this + BL_SZ(block_ptr);
00144 next_ptr = get_offs_ptr(inst, next);
00145 next_ptr->size = 0;
00146 next_ptr->next = -1;
00147 block_ptr->next = next;
00148 return next;
00149 }
00150 return this;
00151 }
00152
00153
00154
00155 static long expand_block (sharedmem_alloc_t *inst, long oldblock,
00156 size_t block_size)
00157 {
00158 long block = oldblock;
00159 long next;
00160 long flags;
00161 sharedmem_block_t *block_ptr;
00162 sharedmem_block_t *next_ptr;
00163
00164 block_ptr = get_offs_ptr(inst, block);
00165 next = block_ptr->next;
00166 if (next >= 0)
00167 {
00168 next_ptr = get_offs_ptr(inst, next);
00169 if (block_is_free(next_ptr))
00170 {
00171
00172 if ((BL_SZ(block_ptr) + BL_SZ(next_ptr)) >= block_size)
00173 {
00174 flags = next_ptr->size & SHAREDMEM_FLAGS_MASK;
00175
00176 next_ptr->size = BL_SZ(next_ptr) -
00177 (block_size - BL_SZ(block_ptr));
00178 next_ptr->size |= flags;
00179
00180 if (BL_SZ(next_ptr) == 0)
00181 block_ptr->next = next_ptr->next;
00182
00183 return block;
00184 }
00185 }
00186 }
00187
00188
00189 return -1;
00190 }
00191
00192
00193
00194 static long shrink_block (sharedmem_alloc_t *inst, long block,
00195 size_t block_size)
00196 {
00197 long next;
00198 long flags;
00199 sharedmem_block_t *block_ptr;
00200 sharedmem_block_t *next_ptr;
00201 size_t next_size;
00202
00203 block_ptr = get_offs_ptr(inst, block);
00204
00205 next_size = BL_SZ(block_ptr) - block_size;
00206 next = block + block_size;
00207 next_ptr = get_offs_ptr(inst, next);
00208 memset(next_ptr, 0x00, sizeof(sharedmem_block_t));
00209
00210 next_ptr->next = block_ptr->next;
00211 next_ptr->size = next_size;
00212
00213 flags = block_ptr->size & SHAREDMEM_FLAGS_MASK;
00214 block_ptr->size = block_size;
00215 block_ptr->size |= flags;
00216 block_ptr->next = next;
00217
00218 return block;
00219 }
00220
00221
00222 static int _coalesce_blocks (sharedmem_alloc_t *inst)
00223 {
00224 int retval = 0;
00225 long block;
00226 long next;
00227 sharedmem_block_t *block_ptr;
00228 sharedmem_block_t *next_ptr;
00229
00230 block = 0;
00231 while (block >= 0)
00232 {
00233
00234 block_ptr = get_offs_ptr(inst, block);
00235
00236 if (block_is_free(block_ptr) && block_ptr->next >= 0)
00237 {
00238 next = block_ptr->next;
00239
00240 next_ptr = get_offs_ptr(inst, next);
00241
00242 if (block_is_free(next_ptr))
00243 {
00244
00245 block_ptr->size = BL_SZ(block_ptr) + BL_SZ(next_ptr);
00246 block_ptr->next = next_ptr->next;
00247 memset(next_ptr, 0x00, sizeof(sharedmem_block_t));
00248 retval = 1;
00249 }
00250 }
00251 block = block_ptr->next;
00252 }
00253
00254 return retval;
00255 }
00256
00257
00258
00259 static void coalesce_blocks (sharedmem_alloc_t *inst)
00260 {
00261 while (_coalesce_blocks(inst));
00262 }
00263
00264
00265 static long sharedmem_alloc_nl (sharedmem_alloc_t *inst, size_t size)
00266 {
00267 long block;
00268 long next;
00269 long offset = -1;
00270 size_t block_size;
00271 sharedmem_block_t *block_ptr;
00272 sharedmem_block_t *next_ptr;
00273
00274 block_size = aligned_block_size(size);
00275
00276 block = find_free(inst, block_size);
00277 if (block >= 0)
00278 {
00279
00280 block_ptr = get_offs_ptr(inst, block);
00281
00282 if ((BL_SZ(block_ptr) - block_size) > sizeof(sharedmem_block_t))
00283 {
00284
00285 next = block + block_size;
00286 next_ptr = get_offs_ptr(inst, next);
00287
00288 if (block_ptr->next >= 0)
00289 {
00290
00291 next_ptr->next = block_ptr->next;
00292
00293 block_ptr->next = next;
00294 }
00295 else
00296 {
00297
00298 next_ptr->next = -1;
00299
00300 block_ptr->next = next;
00301 }
00302
00303 next_ptr->size = BL_SZ(block_ptr) - block_size;
00304
00305 block_ptr->size = (block_size | SHAREDMEM_BLOCK_INUSE);
00306 }
00307 else
00308 {
00309 block_ptr->size |= SHAREDMEM_BLOCK_INUSE;
00310 }
00311 offset = get_data_offs(block);
00312 }
00313 else
00314 {
00315 set_error(inst, 0, "sharedmem_alloc(): no space available");
00316 }
00317
00318 return offset;
00319 }
00320
00321
00322 static int sharedmem_free_nl (sharedmem_alloc_t *inst, long offset)
00323 {
00324 long block;
00325 sharedmem_block_t *block_ptr;
00326
00327 block = offset - sizeof(sharedmem_block_t);
00328 if (block < 0)
00329 return -1;
00330
00331 block_ptr = get_offs_ptr(inst, block);
00332 if (block_is_reserved(block_ptr))
00333 {
00334 block_ptr->size ^= SHAREDMEM_BLOCK_INUSE;
00335 coalesce_blocks(inst);
00336 }
00337 else
00338 {
00339 set_error(inst, 0, "sharedmem_free(): double free?");
00340 return -1;
00341 }
00342
00343 return 0;
00344 }
00345
00346
00347
00348
00349
00350 int sharedmem_alloc_create (sharedmem_alloc_t *inst, sharedmem_t *shminst)
00351 {
00352 sharedmem_block_t *block_ptr;
00353
00354 if (inst == NULL || shminst == NULL)
00355 return -1;
00356 memset(inst, 0x00, sizeof(sharedmem_alloc_t));
00357
00358 SHMALLOC_SHAREDMEM(inst) = shminst;
00359 block_ptr = (sharedmem_block_t *) SHAREDMEM_PTR(SHMALLOC_SHAREDMEM(inst));
00360 if (block_ptr == NULL)
00361 {
00362 set_error(inst, 0, "sharedmem_alloc_create(): sharedmem_t * == NULL");
00363 return -1;
00364 }
00365
00366 if (!sharedmem_lock(SHMALLOC_SHAREDMEM(inst)))
00367 return -1;
00368
00369 block_ptr->size = SHAREDMEM_SIZE(SHMALLOC_SHAREDMEM(inst));
00370 block_ptr->next = -1;
00371
00372 if (!sharedmem_unlock(SHMALLOC_SHAREDMEM(inst)))
00373 return -1;
00374
00375 return 0;
00376 }
00377
00378
00379 long sharedmem_alloc (sharedmem_alloc_t *inst, size_t size)
00380 {
00381 long offset = -1;
00382
00383 if (inst == NULL)
00384 return -1;
00385 if (size == 0)
00386 return -1;
00387
00388 if (!sharedmem_lock(SHMALLOC_SHAREDMEM(inst)))
00389 return -1;
00390
00391 offset = sharedmem_alloc_nl(inst, size);
00392
00393 sharedmem_unlock(SHMALLOC_SHAREDMEM(inst));
00394
00395 return offset;
00396 }
00397
00398
00399 long sharedmem_realloc (sharedmem_alloc_t *inst, long old_offset, size_t size)
00400 {
00401 long old;
00402 long block = -1;
00403 long offset = -1;
00404 size_t block_size;
00405 size_t old_size;
00406 size_t copy_size;
00407 sharedmem_block_t *block_ptr;
00408
00409 if (inst == NULL)
00410 return -1;
00411
00412
00413 if (size == 0)
00414 return sharedmem_free(inst, old_offset);
00415
00416 old = old_offset - sizeof(sharedmem_block_t);
00417 if (old < 0)
00418 return -1;
00419
00420 if (!sharedmem_lock(SHMALLOC_SHAREDMEM(inst)))
00421 return -1;
00422
00423 block_ptr = get_offs_ptr(inst, old);
00424 old_size = BL_SZ(block_ptr);
00425
00426 block_size = aligned_block_size(size);
00427
00428 if (block_size == old_size)
00429 {
00430 offset = old_offset;
00431 goto realloc_out;
00432 }
00433 else if (block_size > old_size)
00434 {
00435
00436 block = expand_block(inst, old, block_size);
00437 }
00438 else
00439 {
00440
00441 block = shrink_block(inst, old, block_size);
00442 coalesce_blocks(inst);
00443 }
00444
00445 if (block >= 0)
00446 {
00447
00448 offset = get_data_offs(block);
00449 }
00450 else
00451 {
00452 offset = sharedmem_alloc_nl(inst, size);
00453 if (offset < 0)
00454 {
00455 set_error(inst, 0, "sharedmem_realloc(): no space available");
00456 goto realloc_out;
00457 }
00458 copy_size = (BL_SZ(block_ptr) <= old_size) ?
00459 BL_SZ(block_ptr) : old_size;
00460 copy_size -= sizeof(sharedmem_block_t);
00461 memcpy(sharedmem_alloc_get_ptr(inst, offset),
00462 sharedmem_alloc_get_ptr(inst, old_offset),
00463 copy_size);
00464 sharedmem_free_nl(inst, old_offset);
00465 }
00466
00467 realloc_out:
00468 sharedmem_unlock(SHMALLOC_SHAREDMEM(inst));
00469
00470 return offset;
00471 }
00472
00473
00474 int sharedmem_free (sharedmem_alloc_t *inst, long offset)
00475 {
00476 long res = 0;
00477
00478 if (inst == NULL)
00479 return -1;
00480
00481 if (!sharedmem_lock(SHMALLOC_SHAREDMEM(inst)))
00482 return -1;
00483
00484 res = sharedmem_free_nl(inst, offset);
00485
00486 sharedmem_unlock(SHMALLOC_SHAREDMEM(inst));
00487
00488 return res;
00489 }
00490
00491
00492 void * sharedmem_alloc_get_ptr (sharedmem_alloc_t *inst, long offset)
00493 {
00494 char *base_ptr;
00495
00496 base_ptr = (char *) SHAREDMEM_PTR(SHMALLOC_SHAREDMEM(inst));
00497 return ((void *) (base_ptr + offset));
00498 }
00499
00500
00501 int sharedmem_alloc_grow (sharedmem_alloc_t *inst, size_t new_size)
00502 {
00503 long last;
00504 size_t old_size;
00505 size_t size_diff;
00506 sharedmem_block_t *last_ptr;
00507
00508 if (inst == NULL)
00509 return -1;
00510 if (new_size <= SHAREDMEM_SIZE(SHMALLOC_SHAREDMEM(inst)))
00511 {
00512 set_error(inst, 0, "sharedmem_alloc_grow(): new_size <= old_size");
00513 return -1;
00514 }
00515 old_size = SHAREDMEM_SIZE(SHMALLOC_SHAREDMEM(inst));
00516 sharedmem_resize(SHMALLOC_SHAREDMEM(inst), new_size);
00517 size_diff = SHAREDMEM_SIZE(SHMALLOC_SHAREDMEM(inst)) - old_size;
00518 if (size_diff < sizeof(sharedmem_block_t))
00519 {
00520 set_error(inst, 0,
00521 "sharedmem_alloc_grow(): size_diff < sizeof(sharedmem_block_t)");
00522 return -1;
00523 }
00524
00525 if (!sharedmem_lock(SHMALLOC_SHAREDMEM(inst)))
00526 return -1;
00527
00528 last = get_last_free(inst);
00529 last_ptr = get_offs_ptr(inst, last);
00530 last_ptr->size += size_diff;
00531
00532 sharedmem_unlock(SHMALLOC_SHAREDMEM(inst));
00533
00534 return 0;
00535 }
00536
00537
00538 void sharedmem_alloc_list_allocs (sharedmem_alloc_t *inst)
00539 {
00540 long block = 0;
00541 sharedmem_block_t *block_ptr;
00542
00543 if (inst == NULL)
00544 return;
00545
00546 fprintf(stderr, "sharedmem_alloc_list_allocs()\n");
00547 fprintf(stderr, "-----------------------------\n");
00548 while (block >= 0)
00549 {
00550 block_ptr = get_offs_ptr(inst, block);
00551 if (!block_is_free(block_ptr))
00552 {
00553 fprintf(stderr, "0x%0x: offset = 0x%0x, size = %u\n",
00554 (size_t) block_ptr, (size_t) block, BL_SZ(block_ptr));
00555 }
00556 block = block_ptr->next;
00557 }
00558 fprintf(stderr, "-----------------------------\n");
00559 }
00560
00561
00562 void sharedmem_alloc_list_frees (sharedmem_alloc_t *inst)
00563 {
00564 long block = 0;
00565 sharedmem_block_t *block_ptr;
00566
00567 if (inst == NULL)
00568 return;
00569
00570 fprintf(stderr, "sharedmem_alloc_list_frees()\n");
00571 fprintf(stderr, "----------------------------\n");
00572 while (block >= 0)
00573 {
00574 block_ptr = get_offs_ptr(inst, block);
00575 if (block_is_free(block_ptr))
00576 {
00577 fprintf(stderr, "0x%0x: offset = 0x%0x, size = %u\n",
00578 (size_t) block_ptr, (size_t) block, BL_SZ(block_ptr));
00579 }
00580 block = block_ptr->next;
00581 }
00582 fprintf(stderr, "----------------------------\n");
00583 }