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
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include "dynarray.h"
00054 #include "shore-config.h"
00055 #include <errno.h>
00056 #include <sys/mman.h>
00057 #include <algorithm>
00058 #include <cstdlib>
00059 #include <cassert>
00060 #include <cstring>
00061
00062
00063 static size_t const MM_PAGE_SIZE = 8192;
00064
00065 static size_t const MM_MAX_CAPACITY = MM_PAGE_SIZE*1024*1024*1024;
00066
00067 static size_t align_up(size_t bytes, size_t align) {
00068 size_t mask = align - 1;
00069 return (bytes+mask) &~ mask;
00070 }
00071
00072 #if HAVE_DECL_MAP_ALIGN
00073 #define USE_MAP_ALIGN 1
00074 #endif
00075
00076 int dynarray::init(size_t max_size, size_t align) {
00077
00078 max_size = align_up(max_size, MM_PAGE_SIZE);
00079
00080
00081 if(max_size > MM_MAX_CAPACITY)
00082 return EFBIG;
00083 if(MM_PAGE_SIZE > max_size)
00084 return EINVAL;
00085 if((align & -align) != align)
00086 return EINVAL;
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 static int const PROTS = PROT_NONE;
00104 int flags = MAP_NORESERVE | MAP_ANON | MAP_PRIVATE;
00105
00106
00107 align = std::max(align, MM_PAGE_SIZE);
00108 #if USE_MAP_ALIGN
00109 char* align_arg = (char*) align;
00110 size_t align_extra = 0;
00111 flags |= MAP_ALIGN;
00112 #else
00113 char* align_arg = 0;
00114 size_t align_extra = align - MM_PAGE_SIZE;
00115 #endif
00116 union { void* v; uintptr_t n; char* c; }
00117 u={mmap(align_arg, max_size+align_extra, PROTS, flags, -1, 0)};
00118
00119 if(u.v == MAP_FAILED)
00120 return errno;
00121
00122 #if !USE_MAP_ALIGN
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138 #ifdef TEST_ME
00139 std::fprintf(stderr, "start: %p end:%p\n", u.c, u.c+max_size+align_extra);
00140 #endif
00141 long aligned_base = align_up(u.n, align);
00142 if(long extra=aligned_base-u.n) {
00143 #ifdef TEST_ME
00144 std::fprintf(stderr, "chopping off %zx bytes of prefix for start: %zx\n",
00145 extra, aligned_base);
00146 #endif
00147 munmap(u.c, extra);
00148 u.n = aligned_base;
00149 align_extra -= extra;
00150 }
00151 if(align_extra > 0) {
00152 #ifdef TEST_ME
00153 std::fprintf(stderr, "chopping %zx bytes of postfix for end: %p\n", align_extra, u.c+max_size);
00154 #endif
00155 munmap(u.c+max_size, align_extra);
00156 }
00157 #endif
00158
00159 _base = u.c;
00160 _capacity = max_size;
00161 _size = 0;
00162 return 0;
00163 }
00164
00165 int dynarray::init(dynarray const &to_copy, size_t max_size) {
00166 max_size = std::max(max_size, to_copy.capacity());
00167 if(int err=init(max_size))
00168 return err;
00169
00170 std::memmove(_base, to_copy._base, to_copy.size());
00171 return 0;
00172 }
00173
00174 int dynarray::fini() {
00175 if(int err=munmap(_base, _capacity))
00176 return err;
00177
00178 _base = 0;
00179 _size = 0;
00180 _capacity = 0;
00181 return 0;
00182 }
00183
00184 int dynarray::resize(size_t new_size) {
00185
00186 new_size = align_up(new_size, MM_PAGE_SIZE);
00187
00188
00189 if(_size > new_size)
00190 return EINVAL;
00191
00192 static int const PROTS = PROT_READ | PROT_WRITE;
00193 static int const FLAGS = MAP_FIXED | MAP_ANON | MAP_PRIVATE;
00194
00195
00196 void* result = mmap(_base+_size, new_size-_size, PROTS, FLAGS, -1, 0);
00197 if(result == MAP_FAILED)
00198 return errno;
00199
00200 _size = new_size;
00201 return 0;
00202 }
00203
00204 int dynarray::ensure_capacity(size_t min_size) {
00205 min_size = align_up(min_size, MM_PAGE_SIZE);
00206 int err = 0;
00207 if(size() < min_size) {
00208 size_t next_size = std::max(min_size, 2*size());
00209 err = resize(next_size);
00210
00211
00212 if(err == EFBIG)
00213 err = resize(min_size);
00214 }
00215 return err;
00216 }
00217
00218