92 uint32_t pages_needed = 0;
93 size_t rounded_size = 0;
98 guint best_index = G_MAXUINT;
99 uint32_t best_length = UINT32_MAX;
101 for(guint
i = 0;
i < a->free_runs->len;
i++)
104 if(
r->length >= pages_needed &&
r->length < best_length)
107 best_length =
r->length;
108 if(best_length == pages_needed)
break;
112 if(best_index == G_MAXUINT)
119 const uint32_t first =
r->start;
122 r->start += pages_needed;
123 r->length -= pages_needed;
127 g_array_remove_index(a->free_runs, best_index);
131 uint8_t *ptr = a->base + (size_t)first * a->page_size;
137 if(
IS_NULL_PTR(VirtualAlloc(ptr, rounded_size, MEM_COMMIT, PAGE_READWRITE)))
139 const DWORD err = GetLastError();
140 fprintf(stderr,
"couldn't commit cache page range (VirtualAlloc error %lu)\n", (
unsigned long)err);
147 *out_size = rounded_size;
165 const uintptr_t base = (uintptr_t)a->base;
166 const uintptr_t addr = (uintptr_t)ptr;
167 if(addr < base || addr >= base + a->size)
169 fprintf(stderr,
"[pixelpipe] arena free: pointer out of range\n");
172 if(((addr - base) % a->page_size) != 0)
174 fprintf(stderr,
"[pixelpipe] arena free: pointer not page-aligned\n");
181 fprintf(stderr,
"[pixelpipe] arena free: invalid size\n");
185 const size_t first_sz = (addr - base) / a->page_size;
186 if(first_sz >= a->num_pages ||
pages > a->num_pages - first_sz)
188 fprintf(stderr,
"[pixelpipe] arena free: range out of bounds\n");
192 const uint32_t first = (uint32_t)first_sz;
194#if !defined(_WIN32) && defined(MADV_FREE)
206 const size_t release_size = (size_t)
pages * a->page_size;
207 if(madvise(ptr, release_size, MADV_FREE))
208 _arena_log(
"[arena] MADV_FREE of %" G_GSIZE_FORMAT
" bytes failed: %s\n",
209 release_size, strerror(errno));
216 while(i < a->free_runs->len &&
226 fprintf(stderr,
"[pixelpipe] arena free: overlap with previous run\n");
230 if(i < a->free_runs->len)
236 fprintf(stderr,
"[pixelpipe] arena free: overlap with next run\n");
242 g_array_insert_val(a->free_runs,
i,
new);
245 if(
i + 1 < a->free_runs->len)
252 g_array_remove_index(a->free_runs,
i + 1);
264 g_array_remove_index(a->free_runs,
i);
272 uint32_t *out_total_free_pages,
273 uint32_t *out_largest_free_run_pages)
275 if(out_total_free_pages) *out_total_free_pages = 0;
276 if(out_largest_free_run_pages) *out_largest_free_run_pages = 0;
281 uint32_t largest = 0;
282 for(guint
i = 0;
i < a->free_runs->len;
i++)
286 if(
r->length > largest) largest =
r->length;
290 if(out_total_free_pages) *out_total_free_pages = total;
291 if(out_largest_free_run_pages) *out_largest_free_run_pages = largest;
304 for(guint
i = 0;
i < a->free_runs->len;
i++)
307 uint8_t *ptr = a->base + (size_t)
r->start * a->page_size;
308 const size_t size = (size_t)
r->length * a->page_size;
313 if(VirtualFree(ptr,
size, MEM_DECOMMIT)) released +=
size;
314#elif defined(__APPLE__) && defined(MADV_FREE)
317 if(!madvise(ptr,
size, MADV_FREE)) released +=
size;
318#elif defined(MADV_DONTNEED)
319 if(!madvise(ptr,
size, MADV_DONTNEED)) released +=
size;
324 _arena_log(
"[arena] trimmed %" G_GSIZE_FORMAT
" MiB of free pages back to the OS\n",
325 released / (1024 * 1024));
359 const size_t page_size = 64 * 1024;
360 const size_t pages = total_size / page_size;
372 a->base = (uint8_t *)VirtualAlloc(NULL, total_size,
377 const DWORD err = GetLastError();
378 fprintf(stderr,
"couldn't alloc map (VirtualAlloc error %lu)\n", (
unsigned long)err);
382 a->base = mmap(NULL, total_size,
383 PROT_READ | PROT_WRITE,
384 MAP_PRIVATE | MAP_ANONYMOUS,
387 if(a->base == MAP_FAILED)
390 fprintf(stderr,
"couldn't alloc map (mmap error %d: %s)\n", errno, strerror(errno));
395 a->size = total_size;
396 a->page_size = page_size;
397 a->num_pages =
pages;
403 VirtualFree(a->base, 0, MEM_RELEASE);
405 munmap(a->base, a->size);
411 fprintf(stderr,
"couldn't alloc free run list\n");
418 .length = a->num_pages
421 g_array_append_val(a->free_runs, full);
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Initialise a mutex. With mutexattr NULL – which is how 54 of the 56 call sites in this tree spell it ...