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 #undef TEST_ME
00077
00078 int dynarray::init(size_t max_size, size_t align) {
00079
00080 max_size = align_up(max_size, MM_PAGE_SIZE);
00081
00082
00083 if(max_size > MM_MAX_CAPACITY)
00084 return EFBIG;
00085 if(MM_PAGE_SIZE > max_size)
00086 return EINVAL;
00087 if((align & -align) != align)
00088 return EINVAL;
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 static int const PROTS = PROT_NONE;
00106 int flags = MAP_NORESERVE | MAP_ANON | MAP_PRIVATE;
00107
00108
00109 align = std::max(align, MM_PAGE_SIZE);
00110 #if USE_MAP_ALIGN
00111 char* align_arg = (char*) align;
00112 size_t align_extra = 0;
00113 flags |= MAP_ALIGN;
00114 #else
00115 char* align_arg = 0;
00116 size_t align_extra = align - MM_PAGE_SIZE;
00117 #endif
00118 #ifdef TEST_ME
00119 std::fprintf(stderr,
00120 "thread %p dynarray::init(%p): mmap:%p %u\n",
00121 (void *)pthread_self(),
00122 this,
00123 align_arg,
00124 unsigned(max_size + align_extra));
00125 #endif
00126 union { void* v; uintptr_t n; char* c; }
00127 u={mmap(align_arg, max_size+align_extra, PROTS, flags, -1, 0)};
00128
00129 if(u.v == MAP_FAILED)
00130 return errno;
00131
00132 #if !USE_MAP_ALIGN
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148 long aligned_base = align_up(u.n, align);
00149 if(long extra=aligned_base-u.n) {
00150 #ifdef TEST_ME
00151 std::fprintf(stderr, "chopping off %zx bytes of prefix for start: %zx\n",
00152 extra, aligned_base);
00153 std::fprintf(stderr, "dynarray::init: munmap:%p %u\n", u.c, unsigned( extra));
00154 #endif
00155 munmap(u.c, extra);
00156 u.n = aligned_base;
00157 align_extra -= extra;
00158 }
00159 if(align_extra > 0) {
00160 #ifdef TEST_ME
00161 std::fprintf(stderr, "chopping %zx bytes of postfix for end: %p\n", align_extra, u.c+max_size);
00162 std::fprintf(stderr, "dynarray::init: munmap:%p %u\n", u.c + max_size, unsigned(align_extra));
00163 #endif
00164 munmap(u.c+max_size, align_extra);
00165 }
00166 #endif
00167
00168 _base = u.c;
00169 _capacity = max_size;
00170 _size = 0;
00171
00172 #ifdef TEST_ME
00173 std::fprintf(stderr,
00174 "thread %p dynarray::init(%p) _base: %p size requested %u (%u KB) end:%p capacity %u _size %u\n",
00175 (void *)pthread_self(), this,
00176 _base,
00177 unsigned(max_size + align_extra),
00178 (unsigned(max_size + align_extra)/1024),
00179 _base+max_size+align_extra,
00180 unsigned(_capacity),
00181 unsigned(_size)
00182 );
00183 #endif
00184 return 0;
00185 }
00186
00187
00188 int dynarray::fini()
00189 {
00190 #ifdef TEST_ME
00191 std::fprintf(stderr, "dynarray::fini: munmap:%p %u\n", _base,unsigned(_capacity));
00192 #endif
00193 if(int err=munmap(_base, _capacity))
00194 return err;
00195
00196 _base = 0;
00197 _size = 0;
00198 _capacity = 0;
00199 return 0;
00200 }
00201
00202
00203 int dynarray::resize(size_t new_size) {
00204
00205 new_size = align_up(new_size, MM_PAGE_SIZE);
00206
00207
00208 if(_size > new_size)
00209 return EINVAL;
00210
00211 if(new_size > _capacity) {
00212
00213
00214
00215 return EFBIG;
00216 }
00217
00218 static int const PROTS = PROT_READ | PROT_WRITE;
00219 static int const FLAGS = MAP_FIXED | MAP_ANON | MAP_PRIVATE;
00220
00221
00222 void* result = mmap(_base+_size, new_size-_size, PROTS, FLAGS, -1, 0);
00223 if(result == MAP_FAILED) return errno;
00224 if(result != _base+_size) {
00225
00226 return EFBIG;
00227 }
00228
00229 _size = new_size;
00230 return 0;
00231 }
00232
00233 int dynarray::ensure_capacity(size_t min_size) {
00234 #ifdef TEST_ME
00235 std::fprintf(stderr,
00236 "thread %p dynarray(%p)::ensure_capacity(min_size %u) from size()=%u\n",
00237 (void *)pthread_self(), this,
00238 unsigned(min_size), unsigned(size())
00239 );
00240 #endif
00241
00242 min_size = align_up(min_size, MM_PAGE_SIZE);
00243
00244 #ifdef TEST_ME
00245 std::fprintf(stderr,
00246 "thread %p dynarray(%p)::ensure_capacity(aligned-up min_size %u)\n",
00247 (void *)pthread_self(), this,
00248 unsigned(min_size)
00249 );
00250 #endif
00251 int err = 0;
00252 if(size() < min_size) {
00253 size_t next_size = std::max(min_size, 2*size());
00254 err = resize(next_size);
00255
00256 if(err == EFBIG) {
00257
00258 next_size = std::max(min_size, size());
00259 err = resize(next_size);
00260 }
00261 }
00262 return err;
00263 }
00264
00265