source: tags/arb-6.0/GDE/RAxML/ll_alloc.c

Last change on this file was 10409, checked in by aboeckma, 11 years ago

Updated raxml to current version

  • Property svn:executable set to *
File size: 105.5 KB
Line 
1/*
2 *   Copyright (C) 2009, 2010, 2011 Lockless Inc., Steven Von Fuerst.
3 *
4 * This library is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Implement a lockfree allocator based upon lockless queues
20 * that communicate between processors, and btrees to hold the
21 * unallocated memory.
22 */
23#ifndef _GNU_SOURCE
24#define _GNU_SOURCE
25#endif
26
27#include "compiler.h"
28#include "ll_asm.h"
29#include "ll_list.h"
30#include <stdlib.h>
31#include <stdint.h>
32#include <string.h>
33#include <stdarg.h>
34
35#ifndef WINDOWS
36#include <sys/mman.h>
37#include <unistd.h>
38#include <sys/syscall.h>
39#include <linux/futex.h>
40#endif /* !WINDOWS */
41
42#include <unistd.h>
43#include <sys/stat.h>
44#include <sys/types.h>
45#include <fcntl.h>
46#include <errno.h>
47#include <stdio.h>
48#include <assert.h>
49// #include <malloc.h>
50#define USE_PREFIX 1
51
52#ifdef USE_DLL
53#define PREFIX(X)   llalloc##X
54#else
55#ifdef USE_PREFIX
56#define PREFIX(X)   llalloc##X
57#else
58#define PREFIX(X)   X
59#endif
60#endif
61
62
63void *PREFIX(memalign)(size_t align, size_t size);
64void *PREFIX(malloc)(size_t size);
65void *PREFIX(realloc)(void *p, size_t size);
66int PREFIX(posix_memalign)(void **p, size_t align, size_t size);
67void *PREFIX(calloc)(size_t n, size_t size);
68void PREFIX(free)(void *p);
69
70static size_t malloc_usable_size(void *p);
71
72/* Debugging */
73//#define DEBUG_ALLOC
74
75/* Extra checking */
76//#define DEBUG_ALLOC_SLOW
77
78/* Memory leak debugging */
79//#define DEBUG_LEAK
80//#define DEBUG_LEAK_DISP               0
81
82/* For windows and valgrind */
83//#define EMU_SBRK
84//#define EMU_SBRK_VG
85
86/* Turn off slab usage - useful for debugging btree and small alloc code */
87//#define DEBUG_NO_SLAB
88
89/* Turn on home-made profiler */
90//#define DEBUG_PROFILE
91
92#ifdef DEBUG_PROFILE
93#include "prof.h"
94#else
95#define DECL_PROF_FUNC int __attribute((unused)) profile_dummy
96#endif
97
98
99#ifndef WINDOWS
100#define PAGESIZE                4096UL
101#else
102#define PAGESIZE                ((size_t) 65536)
103#endif
104
105/* Seperator between allocations */
106#define SEPSIZE                 16
107#define PTRSIZE                 8
108
109#define HEADERSIZE              32
110
111#define ADDR_SIZE               27
112
113#define SLABSIZE                ((uintptr_t) (1 << 17))
114//#define SLABBMAX              ((SLABSIZE / 8) - 2)
115#define SLABBMAX                64      /* About 4M per thread */
116
117/* Slab sizes 0 to 512 bytes in steps of 16 */
118#define NUM_SB                  33
119#define SB_MAX                  ((NUM_SB - 1) * 16)
120
121/* Maximum size of medium allocations */
122#define BTMALLOC                ((1L << ADDR_SIZE) - HEADERSIZE)
123
124#define TOP_SIZE                (-(PAGESIZE * 2))
125
126/* Minimum size to allocate at a time */
127#define MINALLOC                (1L << 21)
128
129/* 64 queues */
130#define NUM_QS                  64
131#define QS_MAX                  (NUM_QS * 16 - SEPSIZE)
132
133/* Only check four fast bins */
134#define FAST_MASK               0x0fULL
135
136/* Clear the fast lists at least this often on free() */
137#define FREE_FAST               ((1 << 16) - 1)
138
139/* The biggest size that can reasonably be stored in the fast lists */
140#ifdef __x86_64__
141#define FAST_64_BIN             67108863
142#else
143#define FAST_64_BIN             3669975
144#endif
145
146
147#ifdef __x86_64__
148#define MYSIZE_TO_PTR(T, N) ((dlist *) (((char *) T) + offsetof(atls, qs) + N - SEPSIZE))
149#else
150#define MYSIZE_TO_PTR(T, N) ((dlist *) (((char *) T) + offsetof(atls, qs) + N/2 - PTRSIZE))
151#endif
152
153/* Fast-lists */
154#define NUM_FL                  64
155
156/* btree size */
157#define BT_MAX                  16
158
159/* 64bit mask type */
160typedef unsigned long long u64b;
161
162/* Pre declare */
163typedef struct btree btree;
164
165typedef struct sep sep;
166struct sep
167{
168        btree *left;
169
170#ifndef __x86_64__
171        int pad;
172#endif
173
174        __extension__ union
175        {
176                __extension__ struct
177                {
178                        unsigned bs_offset;
179                        unsigned size;
180                };
181                uintptr_t prev;
182        };
183};
184
185struct btree
186{
187        /* Seperator */
188        sep s;
189
190        __extension__ union
191        {
192                slist list;
193                dlist list2;
194                void *data;
195
196                __extension__ struct
197                {
198                        btree *parent;
199                        unsigned bsize[BT_MAX + 1];
200                        char prev[BT_MAX + 1];
201                        btree *ptr[BT_MAX];
202                };
203        };
204#ifndef __x86_64__
205        unsigned pad;
206#endif
207};
208
209#ifdef WINDOWS
210/* For documentation purposes only */
211struct mallinfo
212{
213        /* Total space allocated with sbrk in all threads */
214        int arena;
215
216        /* Number of ordinary (non-slab and non-mmap) allocations */
217        int ordblks;
218
219        /* Number of blocks in this threads slab */
220        int smblks;
221
222        /* Number of mmaped chunks in our thread */
223        int hblks;
224
225        /* Number of btree nodes for our thread */
226        int hblkhd;
227
228        /* Total (possibly partially) used slab blocks */
229        int usmblks;
230
231        /* Total number of free slab blocks */
232        int fsmblks;
233
234        /* Total allocated space for this thread including overhead */
235        int uordblks;
236
237        /* Total free space for this thread in ordinary mmap region */
238        int fordblks;
239
240        /* zero */
241        int keepcost;
242};
243#endif
244
245
246/* Seperator bitflags */
247#define FLG_UNUSED      0x01
248#define FLG_LUNUSED     0x02
249#define FLG_LSIZE8      0x04
250#define FLG_SIZE8       0x08
251
252static int b_leaf(btree *b);
253
254#define SEP_INDEX(b, loc, v) (((unsigned char *) &((b)->bsize[loc]))[v])
255
256/* Index into the zeroth int in bsize[] */
257#define b_start(b) SEP_INDEX(b, 0, 0)
258#define b_pindex(b) SEP_INDEX(b, 0, 1)
259#define b_mask(b) (*(unsigned short*) &SEP_INDEX(b, 0, 2))
260
261#define b_next(b, loc) SEP_INDEX(b, loc, 0)
262#define b_prev(b, loc) (b->prev[loc])
263#define b_last(b) b_prev(b, 0)
264#define b_ptr(b, loc) (b->ptr[(loc) - 1])
265
266typedef union mealloc mealloc;
267union mealloc
268{
269        __extension__ struct
270        {
271                slist **tail;
272                dlist m_list;
273        };
274
275        __extension__ struct
276        {
277                char pad[16];
278                btree b;
279        };
280
281        /* Prevent compiler warning "no named members" */
282        void *dummy;
283};
284
285typedef struct sbheader sbheader;
286struct sbheader
287{
288        __extension__ union
289        {
290                __extension__ struct
291                {
292                        slist **tail;
293
294                        dlist list;
295
296                        uintptr_t max;
297
298                        unsigned size;
299
300                };
301
302                /* First cache line is mostly read-only */
303                char pad[64];
304        };
305
306        /* Second cache line is read-write */
307        uintptr_t first;
308
309        unsigned used;
310
311#ifndef __x86_64__
312        u64b dummy;     /* padding to get right alignment */
313#endif
314
315        /* This needs to be 16 byte aligned */
316        void *data;
317};
318
319/* 64k block of pointers to free blocks */
320typedef struct freesb freesb;
321struct freesb
322{
323        freesb *next;
324        unsigned count;
325
326        sbheader *blocks[SLABBMAX];
327};
328
329typedef struct atls atls;
330struct atls
331{
332        slist fl[NUM_FL];
333        u64b f_mask;
334
335#ifndef __x86_64__
336        unsigned dummy; /* padding to get right q8 alignment */
337#endif
338
339        /* Note that qs[0] is a miss-aligned btree pointer! */
340        dlist qs[NUM_QS];
341
342        __extension__ union
343        {
344                __extension__ struct
345                {
346                        /* Overlap with the seperator in bheap */
347                        slist btree_freenode;
348                        unsigned b_hgt;
349                        unsigned b_cnt;
350                };
351
352                btree bheap;
353        };
354
355        u64b q_mask;
356
357        /* Partially full slabs */
358        dlist slab[NUM_SB];
359
360        dlist slab_full;
361
362        freesb *slab_chunk;
363
364        size_t percpu_hash;
365
366        size_t a_alloced;
367        size_t s_wanted;
368
369        slist *head;
370
371        dlist bl;
372
373#ifdef DEBUG_LEAK
374        int leak_fd;
375#endif
376
377        /* Hazard list */
378        dlist h_list;
379        void *hazard;
380
381        /* Deleted list */
382        atls *d_list;
383
384        int fcount;
385
386        char callocable;
387
388        char dummy3[59];
389
390        /* Off by itself to reduce false sharing */
391        slist *tail;
392};
393
394#ifdef USE_DLL
395#define PREFIX(X)       llalloc##X
396#else
397#ifdef USE_PREFIX
398#define PREFIX(X)       llalloc##X
399#else
400#define PREFIX(X)       X
401#endif
402#endif
403
404#ifndef DEBUG_ALLOC
405#define always_inline inline __attribute__((always_inline))
406#else
407#define always_inline
408#endif
409
410#ifdef WINDOWS
411
412void llmutex_lock(void *l);
413void llmutex_unlock(void *l);
414int llmutex_trylock(void *l);
415
416typedef void * mutex_t;
417#define mutex_lock llmutex_lock
418#define mutex_unlock llmutex_unlock
419#define mutex_trylock llmutex_trylock
420#define MUTEX_INITIALIZER {0}
421
422#ifndef EMU_SBRK
423#define EMU_SBRK
424#endif
425
426#define set_enomem() _set_errno(ENOMEM)
427
428/* Other functions that need prototypes */
429//#if defined( USE_DLL ) || defined( USE_PREFIX )
430// #ifdef USE_PREFIX
431// void PREFIX(free)(void *p);
432// void *PREFIX(malloc)(size_t size);
433// void *PREFIX(calloc)(size_t size, size_t n);
434// void *PREFIX(realloc)(void *p, size_t size);
435// size_t PREFIX(_msize)(void *p);
436// void *PREFIX(_expand)(void *p, size_t size);
437//
438// /* Hack - indirect calls to crt functions */
439// int (* __callnewh)(size_t);
440// int (* __newmode)(void);
441// #endif /* USE_DLL */
442
443
444void PREFIX(free)(void *p);
445void *PREFIX(malloc)(size_t size);
446void *PREFIX(calloc)(size_t size, size_t n);
447void *PREFIX(realloc)(void *p, size_t size);
448size_t PREFIX(_msize)(void *p);
449void *PREFIX(_expand)(void *p, size_t size);
450
451
452
453void cfree(void *p);
454void *memalign(size_t align, size_t size);
455int posix_memalign(void **p, size_t align, size_t size);
456void *valloc(size_t size);
457void *pvalloc(size_t size);
458struct mallinfo mallinfo(void);
459int malloc_trim(size_t pad);
460int mallopt(int param, int val);
461void *PREFIX(_calloc_impl)(size_t n, size_t size, int *errno_tmp);
462void PREFIX(_free_nolock)(void *p);
463void *PREFIX(_realloc_nolock)(void *p, size_t size);
464void *PREFIX(_calloc_nolock)(size_t n, size_t size);
465size_t PREFIX(_msize_nolock)(void *p);
466static size_t malloc_usable_size(void *p);
467
468void __tlregdtor(void (*)(void *));
469
470#else /* WINDOWS */
471
472static int sys_futex(void *addr1, int op, int val1, struct timespec *timeout, void *addr2, int val3)
473{
474        return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
475}
476
477#define cmpxchg(P, O, N) __sync_val_compare_and_swap((P), (O), (N))
478
479typedef union mutex_t mutex_t;
480
481union mutex_t
482{
483        unsigned u;
484        struct
485        {
486                unsigned char locked;
487                unsigned char contended;
488        } b;
489};
490
491static void mutex_init(mutex_t *m)
492{
493        m->u = 0;
494}
495
496static void mutex_lock(mutex_t *m)
497{
498        int i;
499
500        /* Try to grab lock */
501        for (i = 0; i < 100; i++)
502        {
503                if (!xchg_8(&m->b.locked, 1)) return;
504
505                cpu_relax();
506        }
507
508        /* Have to sleep */
509        while (xchg_32(&m->u, 257) & 1)
510        {
511                sys_futex(m, FUTEX_WAIT_PRIVATE, 257, NULL, NULL, 0);
512        }
513}
514
515static void mutex_unlock(mutex_t *m)
516{
517        DECL_PROF_FUNC;
518
519        int i;
520
521        /* Locked and not contended */
522        if ((m->u == 1) && (cmpxchg(&m->u, 1, 0) == 1)) return;
523
524        /* Unlock */
525        m->b.locked = 0;
526
527        barrier();
528
529        /* Spin and hope someone takes the lock */
530        for (i = 0; i < 200; i++)
531        {
532                if (m->b.locked) return;
533
534                cpu_relax();
535        }
536
537        /* We need to wake someone up */
538        m->b.contended = 0;
539
540        sys_futex(m, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0);
541}
542
543static int mutex_trylock(mutex_t *m)
544{
545        unsigned c;
546
547        if (m->b.locked) return EBUSY;
548        c = xchg_8(&m->b.locked, 1);
549        if (!c) return 0;
550        return EBUSY;
551}
552
553#define MUTEX_INITIALIZER {0}
554
555
556// static void malloc_stats_aux(int show_nodes);
557
558static gcc_used char dummy1[64];
559static pthread_once_t init_once = PTHREAD_ONCE_INIT;
560static pthread_key_t death_key;
561
562/*
563 * If pthread isn't linked in,
564 * have weak replacements for the single-threaded case
565 */
566#pragma weak pthread_atfork
567#pragma weak pthread_key_create
568#pragma weak pthread_setspecific
569#pragma weak pthread_once
570
571#define set_enomem() (errno = ENOMEM)
572
573#endif /* WINDOWS */
574
575typedef union percpu_list percpu_list;
576union percpu_list
577{
578        __extension__ struct
579        {
580                mutex_t m;
581                freesb *list;
582        };
583        char pad[64];
584};
585
586/* Global thread hazard list */
587static cache_align mutex_t h_lock = MUTEX_INITIALIZER;
588static dlist h_list = DLIST_INIT(h_list);
589
590static cache_align mutex_t d_lock = MUTEX_INITIALIZER;
591static atls *d_list = NULL;
592
593/* List of freed slab blocks */
594static cache_align percpu_list *pc_slab;
595static size_t cpu_total;
596
597/* sbrk information */
598static cache_align mutex_t sb_lock = MUTEX_INITIALIZER;
599static cache_align uintptr_t sbrk_start = 0;
600static uintptr_t sbrk_size = 0;
601static int sbrk_oom = 0;
602static unsigned sltotal[NUM_SB];
603
604#ifdef DEBUG_LEAK
605#define LEAK_MAX                1024
606typedef struct bigallocs bigallocs;
607struct bigallocs
608{
609        void *p;
610        size_t size;
611};
612
613static bigallocs big_leak[LEAK_MAX] = {{NULL, 0}};
614static mutex_t l_lock = MUTEX_INITIALIZER;
615
616#endif
617
618/* Hack */
619#define BUILD_ASSERT(C) do {switch (0){case 0:; case (C):;}} while (0)
620
621/* Pre-declares */
622static always_inline void *split_node(atls *tl, btree *b, size_t t_size, size_t size);
623static void merge_node(atls *tl, void *p);
624static int init_sldata(void);
625static void slab_free(atls *tl, void *p);
626static void local_free(atls *tl, void *p);
627static void *local_alloc(atls *tl, size_t size);
628static void *slab_alloc_safe(atls *tl, size_t size);
629static always_inline void *fast_alloc(atls *tl, size_t size);
630static void *slow_alloc(atls *tl, size_t size);
631static void atls_merge(atls *tl1, atls *tl2);
632static void test_all(atls *tl);
633static void *zalloc(atls *tl, size_t size);
634void **independent_calloc(size_t n, size_t size, void **chunks);
635void **independent_comalloc(size_t n, size_t *sizes, void **chunks);
636
637static inline btree *small_next(btree *b)
638{
639        return b->data;
640}
641
642static inline void set_small_next(btree *b, btree *next)
643{
644        b->data = next;
645}
646
647#ifdef __x86_64__
648static inline btree *small_prev(btree *b)
649{
650        return (btree *) (b->s.prev & ~15);
651}
652
653static inline void set_small_prev(btree *b, btree *prev)
654{
655        uintptr_t p = b->s.prev & 15;
656        b->s.prev = p + (uintptr_t) prev;
657}
658#else
659static inline btree *small_prev(btree *b)
660{
661        return (btree *) b->s.size;
662}
663
664static inline void set_small_prev(btree *b, btree *prev)
665{
666        b->s.size = (unsigned) prev;
667}
668
669#endif
670
671static inline void *shift(void *p, size_t s)
672{
673        return &(((char *)p)[s]);
674}
675
676/* Unfortunately, TLS support with mingw is totally broken... so we need to emulate it */
677#ifdef WINDOWS
678static DWORD tls_index = TLS_OUT_OF_INDEXES;
679static atls *get_tls(void)
680{
681        if (tls_index == TLS_OUT_OF_INDEXES) return NULL;
682
683        return TlsGetValue(tls_index);
684}
685
686static void set_tls(atls *tls)
687{
688        TlsSetValue(tls_index, tls);
689}
690#else
691static __thread__ atls *tls = NULL;
692#define get_tls() tls
693#define set_tls(T) (tls = (T))
694#endif
695
696static size_t cpu_num(void)
697{
698#ifdef WINDOWS                 
699        SYSTEM_INFO info;
700
701        GetSystemInfo(&info);
702        return info.dwNumberOfProcessors;
703#else
704#ifdef SYS_MACOSX
705        int num;
706        size_t len = sizeof(num);
707        if (sysctlbyname("hw.ncpu", &num, &len, NULL, 0)) num = 1;
708        return num;
709#else
710        return sysconf(_SC_NPROCESSORS_ONLN);
711#endif  /* SYS_MACOSX */
712#endif  /* WINDOWS */
713}
714
715/*
716 * Emulate sbrk()
717 * Assumes we are called under a lock */
718#ifdef EMU_SBRK
719
720#ifdef EMU_SBRK_VG
721#define SBRK_SIZE (1ULL << 30)
722#else /* EMU_SBRK_VG */
723
724#ifdef __x86_64__
725
726/* Default to 32GiB of sbrk space */
727#define SBRK_SIZE (1ULL << 37)
728#else /* __x86_64__ */
729
730/* Default to 1GiB of sbrk space */
731#define SBRK_SIZE (1ULL << 30)
732#endif /* __x86_64__ */
733#endif /* EMU_SBRK_VG */
734
735
736static void *sbrk_mmap_base = NULL;
737static void *sbrk_mmap_end = 0;
738static void init_sbrk(void)
739{
740        DECL_PROF_FUNC;
741
742        size_t size = SBRK_SIZE;
743
744        while (1)
745        {
746#ifndef WINDOWS
747                sbrk_mmap_base = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);
748#else
749                /* Allocate address space - but no memory */
750                sbrk_mmap_base = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_READWRITE);
751#endif
752                if (sbrk_mmap_base == MAP_FAILED)
753                {
754                        sbrk_mmap_base = NULL;
755                        size = size / 2;
756                        if (size < 65536) return;
757                }
758                else
759                {
760                        sbrk_mmap_end = shift(sbrk_mmap_base, size);
761
762                        return;
763                }
764        }
765}
766
767static void *emu_sbrk(size_t size)
768{
769        DECL_PROF_FUNC;
770
771        void *out;
772
773        /* Hack - initialize if required */
774        if (!size) init_sbrk();
775        if (!sbrk_mmap_base) return MAP_FAILED;
776
777        out = sbrk_mmap_base;
778        sbrk_mmap_base = shift(sbrk_mmap_base, size);
779        if (sbrk_mmap_base >= sbrk_mmap_end)
780        {
781                sbrk_mmap_base = out;
782
783                return MAP_FAILED;
784        }
785
786#ifdef WINDOWS
787        /* Enable memory */
788        VirtualAlloc(out, size, MEM_COMMIT, PAGE_READWRITE);
789#endif
790
791        return out;
792}
793
794#define sbrk(S) emu_sbrk(S)
795#endif
796
797static inline int is_slab(void *p)
798{
799        return ((uintptr_t) p - sbrk_start < sbrk_size);
800}
801
802static inline void *page_start(void *p)
803{
804        return (void *) (-PAGESIZE & (uintptr_t) p);
805}
806
807static inline size_t page_align(size_t s)
808{
809        return -PAGESIZE & (s + PAGESIZE - 1);
810}
811
812static inline size_t sep_align(size_t s)
813{
814        /*
815         * We want to align on 16byte boundaries
816         *
817         * 16 -> 16
818         * 24 -> 16
819         * 25 -> 32
820         * 32 -> 32
821         */
822        /*
823         * Then we want to include the extra 8 bytes of last ptr that are free.
824         * Finally, we want to include the following sep data.
825         */
826        /*
827         *      0 -> 16
828         *  8 -> 16
829         *  9 -> 32
830         * 16 -> 32
831         * 24 -> 32
832         * 25 -> 48
833         * 32 -> 48
834         * 40 -> 48
835         */
836
837        return (s + 7 + 16) & ~15;
838}
839
840static inline int un_used(btree *b)
841{
842        return (b->s.bs_offset & FLG_UNUSED);
843}
844
845static inline int left_unused(btree *b)
846{
847        return b->s.bs_offset & FLG_LUNUSED;
848}
849
850static inline void set_unused(btree *b, btree *br)
851{
852        br->s.bs_offset |= FLG_LUNUSED;
853        br->s.left = b;
854
855        b->s.bs_offset |= FLG_UNUSED;
856}
857
858static inline void set_used(btree *b, size_t size)
859{
860        btree *br = shift(b, size);
861        br->s.bs_offset &= ~FLG_LUNUSED;
862
863#ifdef DEBUG_ALLOC_SLOW
864        if (size != b->s.size) errx(1, "size missmatch\n");
865#endif
866
867        b->s.bs_offset &= ~FLG_UNUSED;
868}
869
870static inline void set_size8(btree *b)
871{
872        btree *br = shift(b, 16);
873        br->s.bs_offset |= FLG_LSIZE8;
874        b->s.bs_offset |= FLG_SIZE8;
875}
876
877static inline void unset_size8(btree *b)
878{
879        btree *br = shift(b, 16);
880        br->s.bs_offset &= ~FLG_LSIZE8;
881        b->s.bs_offset &= ~FLG_SIZE8;
882        b->s.size = 16;
883        b->s.bs_offset &= 15;
884        b->s.bs_offset += (br->s.bs_offset & ~15) - 16;
885}
886
887#ifdef __x86_64__
888static inline btree *get_q8(atls *tl)
889{
890        /* Mega hack - align so that we return a btree object pointer to the correct memory locations */
891        return shift(&tl->qs[0], -(uintptr_t)8);
892}
893#else
894static inline btree *get_q8(atls *tl)
895{
896        /* Mega hack - align so that we return a btree object pointer to the correct memory locations */
897        return shift(&tl->qs[0], -(uintptr_t)12);
898}
899#endif
900
901static inline btree *read_left(btree *b)
902{
903        if (!left_unused(b)) return NULL;
904        if (b->s.bs_offset & FLG_LSIZE8) return shift(b, -(uintptr_t)16);
905        return b->s.left;
906}
907
908static inline mealloc *read_bs(btree *b)
909{
910        uintptr_t s = b->s.bs_offset & ~15;
911
912#ifdef DEBUG_ALLOC_SLOW
913        void *v = shift(b, -s);
914        if ((PAGESIZE - 1) & (uintptr_t) v) errx(1, "mealloc misaligned\n");
915#endif
916
917        return (mealloc *) shift(b, -s);
918}
919
920static void btree_init(btree *b)
921{
922        /* Init header */
923        //b_start(b) = 0;
924        b_mask(b) = -1;
925        //b_pindex(b) = 0;
926        //b_last(b) = 0;
927}
928
929static inline void set_sep(btree *b, int size, btree *bo)
930{
931        unsigned offset = bo->s.bs_offset & ~15;
932
933        /* Store split block offset + size + used indicators */
934        b->s.bs_offset = offset + ((uintptr_t) b - (uintptr_t) bo);
935        b->s.size = size;
936}
937
938#ifdef DEBUG_ALLOC
939static void check_sep(btree *b)
940{
941        btree *br = shift(b, b->s.size);
942
943        if (((uintptr_t) b) & 15) errx(1, "btree misaligned\n");
944
945        if (is_slab(&b->data)) errx(1, "btree slab overlap\n");
946
947        /* Test unused bit */
948        if (un_used(b))
949        {
950                if (b->s.bs_offset & FLG_SIZE8)
951                {
952                        br = shift(b, 16);
953
954                        if (!(br->s.bs_offset & FLG_LSIZE8)) errx(1, "size8 bit missmatch\n");
955                }
956                else
957                {
958                        if (b->s.size & 15) errx(1, "mysize misaligned\n");
959
960                        if ((b->s.size == 16) || (br->s.bs_offset & FLG_LSIZE8)) errx(1, "size8 bit missmatch\n");
961                        if (read_left(br) != b) errx(1, "left pointer wrong\n");
962                }
963
964                if (!left_unused(br)) errx(1, "Unused flag conflict\n");
965        }
966        else
967        {
968                if (b->s.size & 15) errx(1, "mysize misaligned\n");
969                if (left_unused(br)) errx(1, "Unused flag conflict\n");
970        }
971}
972#else
973#define check_sep(B) ((void) sizeof(B))
974#endif
975
976#ifndef WINDOWS
977static __attribute__((format (gnu_printf, 2, 3))) void leak_print(atls *tl, const char *format, ...)
978{
979        char buf[1024];
980
981        va_list ap;
982
983        va_start(ap, format);
984        vsnprintf(buf, 1024, format, ap);
985        va_end(ap);
986
987#ifdef DEBUG_LEAK
988        /* Need tls and leak_fd initialized */
989        if (tl)
990        {
991                if (tl->leak_fd == -1)
992                {
993                        char buf[1024];
994                        int pid = getpid();
995                        int tid = syscall(SYS_gettid);
996
997                        snprintf(buf, 1024, "/tmp/leak-%d:%d.txt", pid, tid);
998
999                        tl->leak_fd = open(buf, O_WRONLY | O_CREAT | O_APPEND,  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1000                }
1001
1002                if (tl->leak_fd != -1)
1003                {
1004                        int len = strlen(buf);
1005                        char *c = buf;
1006
1007                        while (len)
1008                        {
1009                                int out = write(tl->leak_fd, c, len);
1010
1011                                /* Interrupted - try again */
1012                                if (out == -1) continue;
1013
1014                                /* Device is full - stop writing */
1015                                if (!out) return;
1016
1017                                len -= out;
1018                                c += out;
1019                        }
1020                }
1021        }
1022#else
1023        /* Shut up compiler warning */
1024        (void) tl;
1025
1026        /* Otherwise output to stderr */
1027        fprintf(stderr, "%s", buf);
1028
1029#endif
1030}
1031#else
1032#define leak_print(...)
1033#define malloc_stats_aux(...)
1034#endif
1035
1036#ifdef DEBUG_LEAK
1037static void big_alloced(void *p, size_t size)
1038{
1039        int i;
1040
1041        mutex_lock(&l_lock);
1042        for (i = 0; i < LEAK_MAX; i++)
1043        {
1044                if (big_leak[i].p) continue;
1045
1046                big_leak[i].p = p;
1047                big_leak[i].size = size;
1048                mutex_unlock(&l_lock);
1049                leak_print(get_tls(), "Big alloc %p %llu\n", p, (unsigned long long) size);
1050                return;
1051        }
1052        mutex_unlock(&l_lock);
1053
1054        errx(1, "debug leak oom, increase LEAK_MAX\n");
1055}
1056
1057static void big_freed(void *p, size_t size)
1058{
1059        int i;
1060
1061        mutex_lock(&l_lock);
1062        for (i = 0; i < LEAK_MAX; i++)
1063        {
1064                if (big_leak[i].p != p) continue;
1065
1066                if (big_leak[i].size != size) errx(1, "big alloc size missmatch\n");
1067                big_leak[i].p = NULL;
1068                mutex_unlock(&l_lock);
1069                leak_print(get_tls(), "Big free %p %llu\n", p, (unsigned long long) size);
1070                return;
1071        }
1072        mutex_unlock(&l_lock);
1073
1074        errx(1, "freeing unknown large block %p\n", p);
1075}
1076
1077static size_t big_block_size(void *p)
1078{
1079        int i;
1080
1081        mutex_lock(&l_lock);
1082        for (i = 0; i < LEAK_MAX; i++)
1083        {
1084                if (big_leak[i].p != p) continue;
1085                mutex_unlock(&l_lock);
1086                return big_leak[i].size;
1087        }
1088
1089        mutex_unlock(&l_lock);
1090
1091        errx(1, "freeing unknown large block %p\n", p);
1092}
1093
1094static void test_leak_aux(void)
1095{
1096        atls *tl = get_tls();
1097        if (!tl) return;
1098        malloc_stats_aux(3);
1099        leak_print(tl, "Done\n");
1100        close(tl->leak_fd);
1101}
1102
1103static void test_leak(void)
1104{
1105        static int count = 0;
1106
1107        /* Display turned off? */
1108        if (!DEBUG_LEAK_DISP) return;
1109
1110        /* Don't bother to be thread safe - it doesn't matter much */
1111        if (count++ == DEBUG_LEAK_DISP)
1112        {
1113                count = 0;
1114                malloc_stats_aux(3);
1115        }
1116}
1117
1118
1119#else
1120#define big_alloced(p, size) ((void) (sizeof(p) + sizeof(size)))
1121#define big_freed(p, size) ((void)(sizeof(p) + sizeof(size)))
1122#define test_leak_aux()
1123#define test_leak()
1124#define big_block_size(p) (sizeof(p) * 0)
1125#endif
1126
1127
1128/* Big allocations */
1129static void *big_alloc_aux(size_t size)
1130{
1131        DECL_PROF_FUNC;
1132
1133        /* Get memory */
1134#ifndef WINDOWS
1135        void *p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
1136#else
1137        void *p = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
1138#endif
1139
1140        /* Out of memory */
1141        if (p == MAP_FAILED) return NULL;
1142
1143        big_alloced(p, size);
1144
1145        /* Done */
1146        return p;
1147}
1148
1149#ifdef WINDOWS
1150int handle_oom(int aize);
1151#else
1152#define handle_oom(S)   ((errno = ENOMEM), 0)
1153#endif
1154
1155
1156static noinline void *big_alloc(atls *tl, size_t size)
1157{
1158        DECL_PROF_FUNC;
1159
1160        size_t psize;
1161
1162        size_t *p;
1163
1164        /* This arguement prevents register problems in the fast path */
1165        (void) tl;
1166
1167        if (size > TOP_SIZE) goto nomem;
1168
1169        /* Get real size to allocate */
1170        psize = page_align(size + SEPSIZE);
1171
1172        p = big_alloc_aux(psize);
1173
1174        if (p)
1175        {
1176                *p = psize;
1177                return shift(p, SEPSIZE);
1178        }
1179
1180nomem:
1181
1182        if (handle_oom(size)) return big_alloc(tl, size);
1183
1184        return NULL;
1185}
1186
1187#ifdef WINDOWS
1188static noinline void big_free_aux(size_t *p)
1189{
1190        DECL_PROF_FUNC;
1191
1192        big_freed(p, *p);
1193
1194        VirtualFree(p, 0, MEM_RELEASE);
1195}
1196#else
1197static inline void big_free_aux(size_t *p)
1198{
1199        big_freed(p, *p);
1200
1201        munmap(p, *p);
1202}
1203#endif
1204
1205
1206#ifdef DEBUG_ALLOC_SLOW
1207static void test_queue(atls *tl)
1208{
1209        slist *q;
1210
1211        btree *b;
1212
1213        /* Scan incoming queue, looking for corruption */
1214        for (q = tl->head; q; q = q->next)
1215        {
1216                /* Ignore slab nodes */
1217                if (is_slab(q)) continue;
1218
1219                if (((uintptr_t) q) & 15) errx(1, "incoming queue corrupted\n");
1220
1221                b = CONTAINER(btree, data, q);
1222
1223                if (un_used(b)) errx(1, "queue element marked as unused\n");
1224        }
1225}
1226#else
1227#define test_queue(T) ((void) sizeof(T))
1228#endif
1229
1230#ifdef __x86_64__
1231/* Magic code that converts size to entry in fast-list array */
1232static always_inline size_t size2fl(ssize_t size)
1233{
1234        size_t n = (size / 32);
1235
1236        /* Make sure we don't overflow */
1237        if (size == 16) return 0;
1238        if (size > FAST_64_BIN) return NUM_FL - 1;
1239
1240        n = n * n * n;
1241
1242        return flsq(n);
1243}
1244#else
1245/* Magic code that converts size to entry in fast-list array */
1246static inline size_t size2fl(ssize_t size)
1247{
1248        size_t n;
1249
1250        /* 32 bit version uses old floating point instructions */
1251        union di
1252        {
1253                double d;
1254                unsigned u2[2];
1255        } di;
1256
1257        di.d = size + 40;
1258
1259        n = (di.u2[1] >> 18) - 4115;
1260
1261        /* Make sure we don't overflow */
1262        if (n >= NUM_FL) n = NUM_FL - 1;
1263
1264        return n;
1265}
1266#endif
1267
1268
1269/* Add to previous list - but don't set flag */
1270static always_inline void fast_add(atls *tl, btree *b, size_t n)
1271{
1272        slist_add(&tl->fl[n], &b->list);
1273        tl->f_mask |= 1ULL << n;
1274}
1275
1276/* Add to free lists */
1277static always_inline void fast_free(atls *tl, btree *b, size_t ms)
1278{
1279        size_t n = size2fl(ms);
1280
1281#ifdef DEBUG_ALLOC_SLOW
1282        if (un_used(b)) errx(1, "fast_free() needs used node\n");
1283        if (b->s.size != ms) errx(1, "fast_free size wrong\n");
1284#endif
1285
1286        fast_add(tl, b, n);
1287}
1288
1289static int scan_queue(atls *tl, slist **qh, size_t wanted)
1290{
1291        DECL_PROF_FUNC;
1292
1293        slist *q, *qn, *qp = NULL;
1294
1295        btree *b;
1296
1297        size_t msize;
1298        int flag = 0;
1299
1300        /* Size wanted */
1301        tl->s_wanted = wanted;
1302
1303        /* Scan incoming queue, freeing as we go */
1304        for (q = *qh; q; q = qn)
1305        {
1306#ifdef DEBUG_ALLOC_SLOW
1307                if (!is_slab(q))
1308                {
1309                        if (((uintptr_t) q) & 15) errx(1, "incoming queue corrupted\n");
1310                }
1311#endif
1312
1313                qn = q->next;
1314                qp = q;
1315                if (qn)
1316                {
1317                        if (is_slab(q))
1318                        {
1319                                slab_free(tl, q);
1320                        }
1321                        else
1322                        {
1323                                merge_node(tl, q);
1324                        }
1325
1326                        flag = 1;
1327                }
1328        }
1329
1330        *qh = qp;
1331
1332        /* Reset size wanted */
1333        tl->s_wanted = 0;
1334
1335        /*
1336         * Make sure the last node isn't taking up too much room.
1337         * Not that a slab node could only take up a max of SB_MAX bytes.
1338         * (They aren't splittable anyway)
1339         */
1340        if (is_slab(qp)) return flag;
1341
1342        b = CONTAINER(btree, data, qp);
1343
1344        msize = b->s.size;
1345
1346        /* Don't split if too small */
1347        if (msize <= (1 << 16)) return flag;
1348
1349        /* Make the head node take up less room.  Also, size 32 is faster than 16. */
1350        split_node(tl, b, msize, 32);
1351
1352        return 1;
1353}
1354
1355
1356#ifdef DEBUG_ALLOC_SLOW
1357
1358static void test_node(atls *tl, btree *b)
1359{
1360        mealloc *m = read_bs(b);
1361
1362        if (tl != get_tls()) errx(1, "tls incorrect\n");
1363        if (m->tail != &tl->tail) errx(1, "node owner wrong\n");
1364}
1365
1366/* Test fast list constraints */
1367static void test_fast_lists(atls *tl)
1368{
1369        int i, j;
1370
1371        //if (tl->fl[63].next) errx(1, "fast list overflow\n");
1372
1373        for (i = 0; i < NUM_FL; i++)
1374        {
1375                slist *p = &tl->fl[i];
1376                slist *f;
1377
1378                scan_slist(p, f)
1379                {
1380                        btree *b = CONTAINER(btree, list, f);
1381
1382                        /* Are we a slab node? */
1383                        if (is_slab(&b->data))
1384                        {
1385                                errx(1, "Slab node on fast list\n");
1386                        }
1387
1388                        test_node(tl, b);
1389
1390                        if (un_used(b)) errx(1, "Unused element in fast list\n");
1391                        check_sep(b);
1392
1393                        j = size2fl(b->s.size);
1394                        if ((i != j) && (i != j - 1)) errx(1, "Fast element in wrong bin\n");
1395
1396
1397                        if (!(((uintptr_t) b ^ (uintptr_t) tl) & ~(PAGESIZE - 1))) errx(1, "tls on fast list!\n");
1398                        //if (f == tl->head) errx(1, "queue head in fast list\n");
1399
1400                        if (f->next == f) errx(1, "fast list loop\n");
1401                }
1402        }
1403}
1404#else
1405#define test_fast_lists(T) ((void) sizeof(T))
1406#endif
1407
1408/* Clear fast-lists */
1409static void clear_fast(atls *tl)
1410{
1411        DECL_PROF_FUNC;
1412
1413        u64b mask = tl->f_mask;
1414
1415        /* Anything to do? */
1416        while (mask)
1417        {
1418                size_t n = ffsq(mask);
1419
1420                slist *p = &tl->fl[n];
1421
1422                /* Get mask bit */
1423                mask &= -mask;
1424
1425                /* Convert to a mask */
1426                mask = ~mask;
1427
1428                /* Properly free everything in the list */
1429                while (p->next)
1430                {
1431                        merge_node(tl, slist_rem(p));
1432                }
1433
1434                /* Clear bottom bit */
1435                tl->f_mask &= mask;
1436                mask = tl->f_mask;
1437        }
1438}
1439
1440/* Hack - same as clear_fast() but free nodes from tl2 into tl1 */
1441static void fast_merge(atls *tl1, atls *tl2)
1442{
1443        size_t n;
1444        slist *p = tl2->fl;
1445
1446        /* Anything to do? */
1447        while (tl2->f_mask)
1448        {
1449                n = ffsq(tl2->f_mask);
1450                p = &tl2->fl[n];
1451
1452                /* Turn off bit in f_mask, as nothing will be left there */
1453                tl2->f_mask &= tl2->f_mask - 1;
1454
1455                /* Properly free everything in the list */
1456                while (p->next)
1457                {
1458                        void *l = slist_rem(p);
1459
1460                        merge_node(tl1, l);
1461                }
1462        }
1463}
1464
1465static noinline int reap_dead(atls *tl)
1466{
1467        DECL_PROF_FUNC;
1468
1469        dlist *d;
1470
1471        atls *tl2, *tl3;
1472
1473        /* Check without taking mutex */
1474        if (!d_list) return 0;
1475
1476        /* Try to get dead thread */
1477        if (mutex_trylock(&d_lock)) return 0;
1478
1479        if (!d_list)
1480        {
1481                /* Nothing there */
1482                mutex_unlock(&d_lock);
1483                return 0;
1484        }
1485
1486        /* Grab dead thread */
1487        tl2 = d_list;
1488        d_list = tl2->d_list;
1489        mutex_unlock(&d_lock);
1490
1491        mutex_lock(&h_lock);
1492
1493        /* Remove from hazard list */
1494        dlist_del(&tl2->h_list);
1495
1496        /* Set flag so that memless free works */
1497        tl2->h_list.next = NULL;
1498
1499        /* Merge data + update tail pointers */
1500        atls_merge(tl, tl2);
1501
1502        /* Wait for all threads to not point to dead thread */
1503        scan_list(&h_list, d)
1504        {
1505                tl3 = list_entry(atls, h_list, d);
1506
1507                while (tl3->hazard == &tl2->tail) cpu_relax();
1508        }
1509
1510        mutex_unlock(&h_lock);
1511
1512        /* Scan all final pending */
1513        scan_queue(tl, &tl2->head, 0);
1514
1515        /* Free head */
1516        local_free(tl, tl2->head);
1517
1518        /* Finally free tls data for dead thread */
1519#ifdef WINDOWS         
1520        VirtualFree(page_start(tl2), 0, MEM_RELEASE);
1521#else
1522        munmap(page_start(tl2), PAGESIZE);
1523#endif
1524
1525        test_all(tl);
1526
1527        /* Try to free up memory */
1528        return 1;
1529}
1530
1531static void prepend_queue(slist *p, atls *tl, slist ***bs)
1532{
1533        DECL_PROF_FUNC;
1534
1535        slist *tail;
1536
1537        slist **btail = *bs;
1538        slist **btold;
1539
1540        do
1541        {
1542                btold = btail;
1543
1544                /* Make sure we write to the hazard pointer */
1545                xchg_ptr(&tl->hazard, btail);
1546
1547                /* Has it changed while we were writing to our hazard pointer? */
1548                btail = *bs;
1549        }
1550        while (btold != btail);
1551
1552        p->next = NULL;
1553        tail = xchg_ptr(btail, p);
1554        tail->next = p;
1555
1556        barrier();
1557
1558        tl->hazard = NULL;
1559}
1560
1561static void destroy_tls(void *dummy)
1562{
1563        DECL_PROF_FUNC;
1564
1565        atls *tl = get_tls();
1566
1567        (void) dummy;
1568
1569        test_all(tl);
1570
1571        test_leak_aux();
1572
1573        /*
1574         * Make sure that any recursion via signals or other
1575         * pthread_key destructors will reset this handler.
1576         */
1577#ifdef WINDOWS
1578        set_tls((atls *) 1);
1579#else
1580        set_tls(NULL);
1581#endif
1582
1583        /* The above line isn't allowed to be moved inside the lock due to possible signals */
1584        barrier();
1585
1586        /* Add to dead list */
1587        mutex_lock(&d_lock);
1588        tl->d_list = d_list;
1589        d_list = tl;
1590        mutex_unlock(&d_lock);
1591}
1592
1593
1594/* Convert a pointer into a 32bit random number */
1595static unsigned rnd_ptr(void *p)
1596{
1597        u64b rnd_seed = (uintptr_t) p;
1598        rnd_seed *= 7319936632422683443ULL;
1599        rnd_seed ^= rnd_seed >> 32;
1600        rnd_seed *= 7319936632422683443ULL;
1601        rnd_seed ^= rnd_seed >> 32;
1602
1603        /* Truncate to 32 bits */
1604        return rnd_seed;
1605}
1606
1607/*
1608 * Pick a random offset from p into a region of size total
1609 * to fit an object of size size.
1610 *
1611 * Return a pointer to the object
1612 */
1613static void *rnd_offset(void *p, size_t total, size_t size)
1614{
1615        u64b slack_space = total - size;
1616
1617        unsigned rng = rnd_ptr(p);
1618
1619        unsigned offset = (slack_space * rng) >> 32;
1620
1621        /* Keep 16-byte alignment */
1622        offset &= ~15;
1623
1624        return shift(p, offset);
1625}
1626
1627static atls *init_atls(atls *tl)
1628{
1629        int i;
1630
1631        mealloc *m;
1632        btree *b, *br;
1633
1634        btree *q8;
1635
1636        /* Init lists */
1637        dlist_init(&tl->bl);
1638
1639        /* queue 0 is taken by size 8 small-list */
1640        for (i = 1; i < NUM_QS; i++)
1641        {
1642                dlist_init(&tl->qs[i]);
1643        }
1644
1645        /* Init small list */
1646        q8 = get_q8(tl);
1647
1648#ifdef DEBUG_ALLOC_SLOW
1649        /* Btree needs to be correctly aligned */
1650        if (((uintptr_t) q8) & 15) errx(1, "q8 misaligned\n");
1651#endif
1652
1653        set_small_next(q8, q8);
1654        set_small_prev(q8, q8);
1655
1656        /* Init slabs */
1657        for (i = 0; i < NUM_SB; i++)
1658        {
1659                dlist_init(&tl->slab[i]);
1660        }
1661        dlist_init(&tl->slab_full);
1662
1663        tl->percpu_hash = rnd_ptr(tl);
1664
1665        /* Init btree */
1666        btree_init(&tl->bheap);
1667
1668        /* Need a maximum of 2 nodes at this point */
1669        tl->b_hgt = 2;
1670
1671#ifdef DEBUG_LEAK
1672        tl->leak_fd = -1;
1673#endif
1674
1675        /* Grab initial allocation */
1676        m = big_alloc_aux(PAGESIZE);
1677        if (!m)
1678        {
1679                set_tls(NULL);
1680#ifdef WINDOWS
1681                VirtualFree(page_start(tl), 0, MEM_RELEASE);
1682#else
1683                munmap(page_start(tl), PAGESIZE);
1684#endif
1685                return NULL;
1686        }
1687
1688        /* Keep track of total allocations */
1689        tl->a_alloced = PAGESIZE;
1690
1691        /* Fill in header */
1692        dlist_add(&tl->bl, &m->m_list);
1693
1694        m->tail = &tl->tail;
1695
1696        b = &m->b;
1697
1698        /* Create left seperator */
1699        b->s.size = PAGESIZE - HEADERSIZE;
1700        b->s.bs_offset = 16;
1701
1702        /* Position of right seperator */
1703        br = shift(b, b->s.size);
1704
1705        /* Create right seperator */
1706        br->s.bs_offset = PAGESIZE - SEPSIZE;
1707        split_node(tl, b, b->s.size, SEPSIZE);
1708
1709        /* Make queue */
1710        tl->head = (void *) &b->data;
1711        tl->tail = tl->head;
1712        tl->head->next = NULL;
1713
1714        /* Add to hazard list */
1715        mutex_lock(&h_lock);
1716        dlist_add(&h_list, &tl->h_list);
1717        mutex_unlock(&h_lock);
1718
1719        return tl;
1720}
1721
1722#ifndef WINDOWS
1723
1724static void prepare_fork(void)
1725{
1726        size_t i;
1727
1728        /* Stablize slab */
1729        for (i = 0; i < cpu_total; i++)
1730        {
1731                mutex_lock(&pc_slab[i].m);
1732        }
1733
1734        /* Stablize hazard list */
1735        mutex_lock(&h_lock);
1736
1737        /* Stabilize dead list */
1738        mutex_lock(&d_lock);
1739
1740        /* Stablize sbrk */
1741        mutex_lock(&sb_lock);
1742}
1743
1744static void parent_fork(void)
1745{
1746        size_t i;
1747
1748        /* Done with sbrk */
1749        mutex_unlock(&sb_lock);
1750
1751        /* Done with dead list */
1752        mutex_unlock(&d_lock);
1753
1754        /* Done with hazard list */
1755        mutex_unlock(&h_lock);
1756
1757        /* Done with slab */
1758        for (i = 0; i < cpu_total; i++)
1759        {
1760                mutex_unlock(&pc_slab[i].m);
1761        }
1762}
1763
1764static void child_fork(void)
1765{
1766        size_t i;
1767
1768        /* Clean up sb_lock in child */
1769        mutex_init(&sb_lock);
1770
1771        /* Clean up d_lock in child */
1772        mutex_init(&d_lock);
1773
1774        /* Clean up h_lock in child */
1775        mutex_init(&h_lock);
1776
1777        /* Clean up slab locks in child */
1778        for (i = 0; i < cpu_total; i++)
1779        {
1780                mutex_unlock(&pc_slab[i].m);
1781        }
1782
1783        /*
1784         * Wipe hazard list as the other threads no longer exist
1785         * This leaks memory, but we can't help it,
1786         * as the other threads may be concurrently modifying internal
1787         * data structures now.
1788         */
1789        dlist_init(&h_list);
1790
1791        /* We are the only member */
1792        dlist_add(&h_list, &tls->h_list);
1793}
1794
1795/*
1796 * Initialize things.
1797 * Unfortunately, we don't have a failure return value so we must die instead.
1798 */
1799static void init_handler(void)
1800{
1801        int res;
1802
1803        void *v;
1804
1805        /* Init sbrk information */
1806        v = sbrk(0);
1807        sbrk_start = (uintptr_t) v;
1808
1809        /* Add a fork handler */
1810        if (pthread_atfork)
1811        {
1812                res = pthread_atfork(prepare_fork, parent_fork, child_fork);
1813                if (res) errx(1, "pthread_atfork failed\n");
1814        }
1815
1816        /* Create thread death key */
1817        if (pthread_key_create)
1818        {
1819                res = pthread_key_create(&death_key, destroy_tls);
1820                if (res) errx(1, "pthread_key_create() failed\n");
1821        }
1822
1823        if (init_sldata())
1824        {
1825                errx(1, "Failed to allocate enough memory to initialize slab\n");
1826        }
1827
1828#ifdef DEBUG_LEAK
1829        atexit(test_leak_aux);
1830#endif
1831}
1832
1833static atls *init_tls(void)
1834{
1835        DECL_PROF_FUNC;
1836
1837        atls *tl;
1838
1839        /* Can we use a dead thread's tls data? */
1840        if (d_list)
1841        {
1842                mutex_lock(&d_lock);
1843
1844                if (d_list)
1845                {
1846                        /* Grab from death list */
1847                        tl = d_list;
1848                        d_list = tl->d_list;
1849                        mutex_unlock(&d_lock);
1850
1851                        set_tls(tl);
1852
1853                        /* Init my thread destructor */
1854                        if (pthread_setspecific) pthread_setspecific(death_key, tl);
1855
1856                        test_all(tl);
1857
1858                        /* Done */
1859                        return tl;
1860                }
1861                mutex_unlock(&d_lock);
1862        }
1863
1864        /* Hack - use a full page for it */
1865        tl = mmap(NULL, PAGESIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
1866
1867        /* Out of memory */
1868        if (tl == MAP_FAILED) goto nomem;
1869
1870        /* Randomly cache colour the tls data */
1871        tl = rnd_offset(tl, PAGESIZE, sizeof(atls));
1872
1873        /* Save pointer for later memory calls */
1874        set_tls(tl);
1875
1876        /* Make sure that we can always allocate two btree nodes from within itself */
1877        BUILD_ASSERT(NUM_QS * 8 + 16 >= sizeof(btree) * 2);
1878
1879        /* Make sure atls isn't too big */
1880        BUILD_ASSERT(sizeof(atls) <= PAGESIZE);
1881
1882        /* Make sure btree nodes fit in the slab */
1883        BUILD_ASSERT(sizeof(btree) <= SB_MAX);
1884
1885        /* Hack - we should use the rest of the space to init the heap... */
1886        tl = init_atls(tl);
1887        if (!tl) goto nomem;
1888
1889        /*
1890         * Init handler.
1891         * Note that this can allocate memory, so needs to be done last
1892         */
1893        if (pthread_once)
1894        {
1895                pthread_once(&init_once, init_handler);
1896        }
1897        else
1898        {
1899                /* Since there are no threads... */
1900                if (!sbrk_start) init_handler();
1901        }
1902
1903        /* Init my thread destructor */
1904        if (pthread_setspecific) pthread_setspecific(death_key, tl);
1905
1906        test_all(tl);
1907
1908        return tl;
1909
1910nomem:
1911        set_enomem();
1912        return NULL;
1913}
1914#else /* WINDOWS */
1915
1916
1917#ifdef USE_DLL
1918
1919typedef struct patch patch;
1920struct patch
1921{
1922        const char *name;
1923        void *func;
1924};
1925
1926
1927#define PATCH_FUNC(X)\
1928        {#X, (void *) ((uintptr_t) llalloc##X)}
1929
1930static patch patch_list[] =
1931{
1932        PATCH_FUNC(free),
1933        PATCH_FUNC(malloc),
1934        PATCH_FUNC(calloc),
1935        PATCH_FUNC(realloc),
1936        PATCH_FUNC(_msize),
1937        PATCH_FUNC(_expand),
1938        PATCH_FUNC(_free_nolock),
1939        PATCH_FUNC(_realloc_nolock),
1940        PATCH_FUNC(_calloc_nolock),
1941        PATCH_FUNC(_msize_nolock),
1942        {NULL, NULL}
1943};
1944
1945#define JMP_OP  0xE9
1946#define CALL_OP 0xE8
1947#define JMP_OFFSET(P1, P2)      (((uintptr_t)(P1)) - ((uintptr_t)(P2)) - 5)
1948
1949/* Follow a call to its target */
1950static void *follow_call(void *p)
1951{
1952        int target;
1953
1954        /* Are we pointing to a jump? */
1955        if ((*(unsigned char *)p) != CALL_OP) return NULL;
1956
1957        target = *(int *) shift(p, 1);
1958
1959        return (void *) shift(p, (uintptr_t) target + 5);
1960}
1961
1962/* Find a jump in a dumb manner */
1963static void *find_call(void *p)
1964{
1965        while ((*(unsigned char *) p) != CALL_OP)
1966        {
1967                p = shift(p, 1);
1968        }
1969
1970        return p;
1971}
1972
1973static void patch_function(void *func, void *my_func)
1974{
1975        MEMORY_BASIC_INFORMATION mbi;
1976
1977        /* Make code read/write */
1978        VirtualQuery(func, &mbi, sizeof(mbi));
1979        VirtualProtect(mbi.BaseAddress, mbi.RegionSize,
1980                                                PAGE_EXECUTE_READWRITE, &mbi.Protect);
1981
1982        /* Patch in a jmp to our routine */
1983        *(unsigned char *) func = JMP_OP;
1984        *(unsigned *) shift(func, 1) = JMP_OFFSET(my_func, func);
1985
1986        /* Reset code permissions */
1987        VirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &mbi.Protect);
1988}
1989
1990static void *init_crt_funcs(void)
1991{
1992        FARPROC func_f;
1993        patch *p;
1994        void *f;
1995
1996        HMODULE library = GetModuleHandle("MSVCR90.DLL");
1997        if (!library) return NULL;
1998
1999        func_f = GetProcAddress(library, "_callnewh");
2000        if (!func_f) return NULL;
2001        __callnewh = (typeof(__callnewh)) func_f;
2002
2003        func_f = GetProcAddress(library, "?_query_new_mode@@YAHXZ");
2004        if (!func_f) return NULL;
2005        __newmode = (typeof(__newmode)) func_f;
2006
2007        for (p = patch_list; p->name; p++)
2008        {
2009                func_f = GetProcAddress(library, p->name);
2010                if (!func_f) continue;
2011
2012                patch_function((void *) (uintptr_t) func_f, p->func);
2013        }
2014
2015        func_f = GetProcAddress(library, "calloc");
2016        f = (void *) (uintptr_t) func_f;
2017
2018        /* Not here... don't crash */
2019        if (!f) goto out;
2020
2021        /* Get pointer to _calloc_impl() */
2022        f = find_call(f);
2023        f = follow_call(f);
2024
2025        /* Finally patch _calloc_impl */
2026        patch_function(f, (void *) (uintptr_t) llalloc_calloc_impl);
2027
2028out:
2029
2030        /* Success */
2031        return (void*) 1;
2032}
2033
2034
2035#endif
2036
2037void lldebug_hook(void);
2038static atls *init_tls(void)
2039{
2040        DECL_PROF_FUNC;
2041
2042        atls *tl;
2043
2044        static void *init = (void *) 1;
2045        void *first = xchg_ptr(&init, NULL);
2046
2047        if (!first)
2048        {
2049                /* We've already died - use free_nomem() */
2050                if (get_tls() == (atls *) 1) return NULL;
2051
2052                /* Can we use a dead thread's tls data? */
2053                if (d_list)
2054                {
2055                        mutex_lock(&d_lock);
2056
2057                        if (d_list)
2058                        {
2059                                /* Grab from death list */
2060                                tl = d_list;
2061                                d_list = tl->d_list;
2062                                mutex_unlock(&d_lock);
2063
2064                                set_tls(tl);
2065
2066                                test_all(tl);
2067
2068                                /* Undocumented crt function */
2069                                __tlregdtor(destroy_tls);
2070
2071                                /* Done */
2072                                return tl;
2073                        }
2074                        mutex_unlock(&d_lock);
2075                }
2076        }
2077        else
2078        {
2079                void *v = sbrk(0);
2080
2081                /* Init slab */
2082                if (init_sldata())
2083                {
2084                        init = (void *) 1;
2085                        return NULL;
2086                }
2087
2088                tls_index = TlsAlloc();
2089                if (tls_index == TLS_OUT_OF_INDEXES)
2090                {
2091                        /* We can't handle this */
2092                        init = (void *) 1;
2093                        return NULL;
2094                }
2095
2096#ifdef USE_DLL
2097                /* Initialize function pointers */
2098                if (!init_crt_funcs())
2099                {
2100                        /* Doesn't work... fail and bail out of dll init */
2101                        init = (void *) 1;
2102                        return NULL;
2103                }
2104#endif
2105                /* Init sbrk information */
2106                sbrk_start = (uintptr_t) v;
2107        }
2108
2109        /* Hack - use a full page for it */
2110        tl = VirtualAlloc(NULL, PAGESIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
2111
2112        /* Out of memory */
2113        if (!tl) goto nomem;
2114
2115        /* Randomly cache colour the tls data */
2116        tl = rnd_offset(tl, PAGESIZE, sizeof(atls));
2117
2118        /* Save pointer for later memory calls */
2119        set_tls(tl);
2120
2121        /* Make sure that we can always allocate two btree nodes from within itself */
2122        //BUILD_BUG(NUM_QS * 8 + 16 >= sizeof(btree) * 2);
2123
2124        /* Hack - we should use the rest of the space to init the heap... */
2125        tl = init_atls(tl);
2126        if (!tl) goto nomem;
2127
2128        /* Undocumented crt function */
2129        __tlregdtor(destroy_tls);
2130
2131        test_all(tl);
2132
2133        return tl;
2134
2135nomem:
2136        /* Try again if possible */
2137        if (handle_oom(PAGESIZE * 2)) return init_tls();
2138
2139        return NULL;
2140}
2141
2142#ifdef USE_DLL
2143BOOL DllMain(HINSTANCE h, DWORD reason, LPVOID reserved);
2144BOOL DllMain(HINSTANCE h, DWORD reason, LPVOID reserved)
2145{
2146        /* Silence compiler warnings */
2147        (void) h;
2148        (void) reserved;
2149
2150        /* Init the memory allocator */
2151        if ((reason == DLL_PROCESS_ATTACH) || (reason == DLL_THREAD_ATTACH))
2152        {
2153                if (!init_tls()) return 0;
2154        }
2155#ifdef DEBUG_PROFILE
2156        else if(reason == DLL_PROCESS_DETACH)
2157        {
2158                ll_print_prof();
2159        }
2160#endif
2161
2162        return 1;
2163}
2164#endif /* USE_DLL */
2165
2166#endif /* WINDOWS */
2167
2168#ifdef DEBUG_ALLOC_SLOW
2169
2170/* Get node previous to loc in b */
2171static void test_btree_linked(btree *b, int loc)
2172{
2173        int i, j = 0;
2174
2175        if (b_leaf(b)) errx(1, "No previous!\n");
2176
2177        for (i = b_start(b); i != loc; i = b_next(b, i))
2178        {
2179                j++;
2180
2181                if (j > BT_MAX) errx(1, "Btree node loop!\n");
2182        }
2183}
2184
2185static void test_in_btree(atls *tl, btree *b)
2186{
2187        btree *bp;
2188
2189        if (!b_leaf(b)) errx(1, "Unused btree object that is not a leaf\n");
2190
2191        while (b->parent)
2192        {
2193                bp = b->parent;
2194
2195                if (b_ptr(bp, b_pindex(b)) != b) errx(1, "Parent doesn't own %p\n", (void *) b);
2196                if (!bp->bsize[b_pindex(b)]) errx(1, "Parent link broken\n");
2197
2198                test_btree_linked(bp, b_pindex(b));
2199
2200                b = bp;
2201        }
2202
2203        if (&tl->bheap != b) errx(1, "Heap doesn't own %p\n", (void *) b);
2204}
2205
2206#ifdef UNUSED_FUNC
2207static int is_fast_node(atls *tl, btree *b)
2208{
2209        size_t bin = size2fl(b->s.size);
2210        slist *f;
2211
2212        scan_slist(&tl->fl[bin], f)
2213        {
2214                /* Found it? */
2215                if (f == &b->list) return 1;
2216        }
2217
2218        /* Didn't find it */
2219        return 0;
2220}
2221#endif /* UNUSED_FUNC */
2222
2223static void test_blocks(atls *tl)
2224{
2225        mealloc *m;
2226        dlist *d;
2227
2228        btree *b;
2229
2230        size_t size;
2231
2232        if (tl->bl.next->prev != &tl->bl) errx(1, "Block list corrupt\n");
2233
2234        /* Scan blocks */
2235        scan_list(&tl->bl, d)
2236        {
2237                m = list_entry(mealloc, m_list, d);
2238
2239                if (d->next->prev != d) errx(1, "Block list corrupt\n");
2240
2241                /* Scan seps for this block */
2242                for (b = &m->b;; b = shift(b, size))
2243                {
2244                        if (b < &m->b) errx(1, "Node before block start!\n");
2245
2246                        if (b->s.bs_offset & FLG_SIZE8)
2247                        {
2248                                size = 16;
2249                        }
2250                        else
2251                        {
2252                                size = b->s.size;
2253
2254                                if (!size) break;
2255
2256                                if (shift(b, -(uintptr_t)(b->s.bs_offset & ~15)) != m) errx(1, "Block back link broken\n");
2257
2258                                if (read_bs(b) != m) errx(1, "Block start corrupted\n");
2259                        }
2260
2261                        check_sep(b);
2262
2263                        if ((size > QS_MAX) && un_used(b)) test_in_btree(tl, b);
2264                }
2265        }
2266}
2267#else
2268#define test_blocks(T) ((void) sizeof(T))
2269#endif
2270
2271/* Medium allocations */
2272
2273#ifdef DEBUG_ALLOC_SLOW
2274
2275static unsigned test_btree_aux(atls *tl, btree *b, unsigned lsize)
2276{
2277        btree *bn;
2278        int n = b_start(b);
2279        int i = 0;
2280        unsigned ssize = lsize;
2281
2282        unsigned short msk = -1;
2283
2284        /* Size of node can be incorrect if splitting not possible */
2285        if (n && b->parent && !is_slab(b) && (b->s.size < sizeof(btree)))
2286        {
2287                errx(1, "Btree nodesize wrong\n");
2288        }
2289
2290        while (n)
2291        {
2292                bn = b_ptr(b, n);
2293
2294                i++;
2295
2296                if (bn->parent != b) errx(1, "Btree parent incorrect\n");
2297                if (b_pindex(bn) != n) errx(1, "Btree p_index incorrect\n");
2298
2299                if (b_mask(b) & (1 << (n - 1))) errx(1, "Used btree node marked free\n");
2300                msk -= (1 << (n - 1));
2301
2302                /* Scan lower */
2303                ssize = test_btree_aux(tl, bn, ssize);
2304
2305                if (b->bsize[n] < ssize) errx(1, "Btree size misordered\n");
2306                ssize = b->bsize[n] & ~0xff;
2307
2308                if (b_leaf(bn))
2309                {
2310                        if (bn->s.size*16 != ssize) errx(1, "Btree leaf size wrong\n");
2311
2312                        if (!un_used(bn)) errx(1, "Btree leaf marked used!\n");
2313                }
2314                else if (!is_slab(bn) && un_used(bn)) errx(1, "Btree node marked unused!\n");
2315
2316                if (b_prev(b, b_next(b, n)) != n) errx(1, "prev link broken\n");
2317
2318                n = b_next(b, n);
2319
2320                if (i > BT_MAX) errx(1, "Btree node loop!\n");
2321        }
2322
2323        /* Leaf node? */
2324        if (!i) return ssize;
2325
2326        if (msk != b_mask(b)) errx(1, "Btree free mask missmatch\n");
2327
2328        if (b->parent && (i <= 3)) errx(1, "Btree has too few children\n");
2329
2330        return ssize & ~0xff;
2331}
2332
2333static void test_btree(atls *tl)
2334{
2335        if ((tl->b_hgt > 100) || (tl->b_cnt > 100)) errx(1, "btree height corrupt\n");
2336
2337        test_btree_aux(tl, &tl->bheap, 0);
2338}
2339#else
2340#define test_btree(T) ((void) sizeof(T))
2341#endif
2342
2343static char btree_count(btree *b)
2344{
2345        int x = b_mask(b);
2346
2347        /* See Wikipedia for this algorithm for popcount */
2348        int m1 = 0x5555;
2349        int m2 = 0x3333;
2350        int m4 = 0x0f0f;
2351
2352        /* Put counts into pairs of bits */
2353        x -= (x >> 1) & m1;
2354
2355        /* 4 bit counts */
2356        x = (x & m2) + ((x >> 2) & m2);
2357
2358        /* Make 8bit counts */
2359        x = (x + (x >> 4)) & m4;
2360
2361        return 16 - (x + (x >> 8));
2362}
2363
2364static inline int btree_alloc(btree *b)
2365{
2366        int loc = ffsu(b_mask(b));
2367
2368        b_mask(b) &= ~(1 << loc);
2369
2370        return loc + 1;
2371}
2372
2373static inline void btree_free(btree *b, int loc)
2374{
2375        b_mask(b) |= 1 << (loc - 1);
2376}
2377
2378static int b_leaf(btree *b)
2379{
2380        /* Check to see if there are no children */
2381        return !b_start(b);
2382}
2383
2384static inline unsigned btree_ssize(btree *b, int loc)
2385{
2386        return b->bsize[loc] & ~0xff;
2387}
2388
2389static inline void btree_update_daughter(btree *bp, btree *b, int loc)
2390{
2391        b_ptr(bp, loc) = b;
2392        b->parent = bp;
2393        b_pindex(b) = loc;
2394}
2395
2396
2397/* Update my parent with my new size */
2398static void btree_update_psize(btree *b, unsigned ssize)
2399{
2400        int bpi = b_pindex(b);
2401        btree *bp;
2402
2403        /* Update parent size value */
2404        for (bp = b->parent; bp; bp = bp->parent)
2405        {
2406                bp->bsize[bpi] &= 0xff;
2407                bp->bsize[bpi] += ssize;
2408
2409                /* Are we done with the chain of updates? */
2410                if (b_next(bp, bpi)) break;
2411
2412                bpi = b_pindex(bp);
2413        }
2414}
2415
2416/* Forward declare */
2417static void btree_node_del(atls *tl, btree *b, int loc);
2418
2419static void btree_merge_aux(atls *tl, btree *bl, btree *br)
2420{
2421        int i, j, k;
2422
2423        int ip, pi;
2424
2425        int next;
2426
2427        unsigned ssize;
2428
2429        btree *bp;
2430
2431        int bcl, bcr;
2432
2433#ifdef DEBUG_ALLOC_SLOW
2434        if (!bl->parent || !br->parent) errx(1, "Trying to merge heap top\n");
2435        if (bl->parent != br->parent) errx(1, "Trying to merge two nodes with different parents\n");
2436#endif
2437
2438        bcl = btree_count(bl);
2439        bcr = btree_count(br);
2440
2441        /* Move some from neighbour to me */
2442        if (bcr + bcl > BT_MAX)
2443        {
2444                if (bcr > bcl)
2445                {
2446                        /* Silence compiler warning */
2447                        next = 0;
2448
2449                        /* Move some nodes from br to bl */
2450                        ip = b_last(bl);
2451
2452                        for (j = bcr / 3, k = b_start(br); j; k = next, j--)
2453                        {
2454                                next = b_next(br, k);
2455                                i = btree_alloc(bl);
2456
2457                                /* Add in new node */
2458                                bl->bsize[i] = br->bsize[k];
2459                                b_next(bl, ip) = i;
2460                                b_prev(bl, i) = ip;
2461                                btree_update_daughter(bl, b_ptr(br, k), i);
2462                                ip = i;
2463
2464                                /* Remove old node */
2465                                btree_free(br, k);
2466                        }
2467                        b_next(bl, ip) = 0;
2468                        ssize = bl->bsize[ip];
2469                        b_last(bl) = ip;
2470
2471                        b_start(br) = next;
2472                        b_prev(br, next) = 0;
2473
2474                        /* Notify parent of my new size */
2475                        btree_update_psize(bl, ssize);
2476
2477                        return;
2478                }
2479
2480                /* Scan 2/3rds of the way through bl */
2481                for (j = bcl / 3, ip = b_last(bl); j; ip = b_prev(bl, ip), j--);
2482
2483                k = b_start(br);
2484                ssize = btree_ssize(bl, ip);
2485                j = b_next(bl, ip);
2486                b_next(bl, ip) = 0;
2487                b_last(bl) = ip;
2488
2489                /* Copy remainder to br, deleting as we go */
2490                for (ip = 0; j; j = next)
2491                {
2492                        next = b_next(bl, j);
2493                        i = btree_alloc(br);
2494
2495                        /* Add in new node */
2496                        br->bsize[i] = bl->bsize[j];
2497                        b_next(br, ip) = i;
2498                        b_prev(br, i) = ip;
2499                        ip = i;
2500                        btree_update_daughter(br, b_ptr(bl, j), i);
2501
2502                        /* Remove old node */
2503                        btree_free(bl, j);
2504                }
2505
2506                /* link to remainder of nodes in br */
2507                b_next(br, ip) = k;
2508                b_prev(br, k) = ip;
2509
2510                /* Notify parent of my new size */
2511                btree_update_psize(bl, ssize);
2512
2513                return;
2514        }
2515
2516        /* merge bl into br and delete bl */
2517        ip = 0;
2518        k = b_start(br);
2519        for (j = b_start(bl); j; j = b_next(bl, j))
2520        {
2521                i = btree_alloc(br);
2522
2523                /* Add in new node */
2524                br->bsize[i] = bl->bsize[j];
2525                b_next(br, ip) = i;
2526                b_prev(br, i) = ip;
2527                ip = i;
2528
2529                btree_update_daughter(br, b_ptr(bl, j), i);
2530        }
2531
2532#ifdef DEBUG_ALLOC_SLOW
2533        if (!ip) errx(1, "Empty left node?\n");
2534#endif
2535
2536        b_next(br, ip) = k;
2537        b_prev(br, k) = ip;
2538
2539        /* Save these so we can delete */
2540        bp = bl->parent;
2541        pi = b_pindex(bl);
2542
2543        /* Delete this node when done */
2544        local_free(tl, &bl->data);
2545
2546        /* Delete bl */
2547        btree_node_del(tl, bp, pi);
2548
2549        /* Tail recursion */
2550}
2551
2552static noinline void btree_node_del_aux(atls *tl, btree *b, btree *bp)
2553{
2554        size_t prev, next;
2555
2556        int pi = b_pindex(b);
2557
2558        int i;
2559
2560#ifdef DEBUG_ALLOC_SLOW
2561        if (!pi) errx(1, "Corrupted leaf\n");
2562#endif
2563
2564        /* Rebalance if possible */
2565        next = b_next(bp, pi);
2566        if (next)
2567        {
2568                /* Merge with next node */
2569                btree_merge_aux(tl, b, b_ptr(bp, next));
2570
2571                return;
2572        }
2573
2574        prev = b_prev(bp, pi);
2575        if (prev)
2576        {
2577                /* Merge with previous node */
2578                btree_merge_aux(tl, b_ptr(bp, prev), b);
2579
2580                return;
2581        }
2582
2583        /* Just me here? */
2584#ifdef DEBUG_ALLOC_SLOW
2585        if (bp != &tl->bheap) errx(1, "Invalid node count\n");
2586#endif
2587
2588        /* Move my data to the top of the btree */
2589        b_start(bp) = b_start(b);
2590        b_last(bp) = b_last(b);
2591        b_mask(bp) = b_mask(b);
2592
2593        /* Init alloced list */
2594        for (i = b_start(b); i; i = b_next(b, i))
2595        {
2596                bp->bsize[i] = b->bsize[i];
2597                bp->prev[i] = b->prev[i];
2598                btree_update_daughter(bp, b_ptr(b, i), i);
2599        }
2600
2601        /* Btree is shorter */
2602        tl->b_hgt--;
2603
2604        /* Delete this node when done */
2605        local_free(tl, &b->data);
2606
2607        /* Prevent having too many spare nodes which can cause fragmentation */
2608        if (tl->b_hgt < tl->b_cnt)
2609        {
2610                /* Pop off the extra node */
2611                void *st = slist_rem(&tl->btree_freenode);
2612                b = list_entry(btree, data, st);
2613
2614                /* Delete it */
2615                local_free(tl, &b->data);
2616                tl->b_cnt--;
2617        }
2618}
2619
2620/* Delete node at location loc */
2621static void btree_node_del(atls *tl, btree *b, int loc)
2622{
2623        size_t prev = b_prev(b, loc);
2624        size_t next = b_next(b, loc);
2625
2626        btree *bp = b->parent;
2627
2628        b_next(b, prev) = next;
2629        b_prev(b, next) = prev;
2630
2631        /* Add to free list */
2632        btree_free(b, loc);
2633
2634        /* If top - am done */
2635        if (!bp) return;
2636
2637        /* Was last? */
2638        if (!next)
2639        {
2640                /* Update parent size (we know there must be at least one other node) */
2641                btree_update_psize(b, btree_ssize(b, prev));
2642        }
2643
2644        /* Still not empty enough btree_count(b) > 3) (faster than popcount) */
2645        if (b_next(b, b_next(b, b_next(b, b_start(b))))) return;
2646
2647        btree_node_del_aux(tl, b, bp);
2648}
2649
2650static inline btree *btree_search(atls *tl, unsigned ssize)
2651{
2652        btree *b = &tl->bheap;
2653        size_t i = b_start(b);
2654
2655        while (i)
2656        {
2657                /* Scan level below? */
2658                if (b->bsize[i] < ssize)
2659                {
2660                        i = b_next(b, i);
2661                }
2662                else
2663                {
2664                        b = b_ptr(b, i);
2665                        i = b_start(b);
2666                }
2667        }
2668
2669        return b;
2670}
2671
2672/* Return node of size ssize if possible */
2673static btree *btree_remove(atls *tl, unsigned ssize)
2674{
2675        btree *b = btree_search(tl, ssize);
2676
2677        /* Nothing? */
2678        if (b == &tl->bheap) return NULL;
2679
2680        /* Disconnect it */
2681        btree_node_del(tl, b->parent, b_pindex(b));
2682
2683        return b;
2684}
2685
2686/* Find space for node of size ssize */
2687static btree *btree_find(atls *tl, unsigned ssize, int *ipv)
2688{
2689        btree *b = btree_search(tl, ssize);
2690        btree *bp = &tl->bheap;
2691
2692        if (b != bp)
2693        {
2694                bp = b->parent;
2695                *ipv = b_prev(bp, b_pindex(b));
2696                return bp;
2697        }
2698
2699        /* Nothing in btree? */
2700        if (b_leaf(b)) return bp;
2701
2702        /* We are larger than anything */
2703        do
2704        {
2705                /* Scan level below */
2706                b = b_ptr(b, (int) b_last(b));
2707        }
2708        while (!b_leaf(b));
2709
2710        *ipv = b_pindex(b);
2711
2712        return b->parent;
2713}
2714
2715/* Cleanup - make sure we have enough temp nodes */
2716static noinline void btree_cleanup(atls *tl)
2717{
2718        /* First try to use slab allocations to prevent fragmentation */
2719        while (tl->b_hgt > tl->b_cnt)
2720        {
2721                slist *s = slab_alloc_safe(tl, sizeof(btree) - SEPSIZE);
2722
2723                /* Fall back to in-btree allocations */
2724                if (!s) goto use_btree;
2725
2726                slist_add(&tl->btree_freenode, s);
2727                tl->b_cnt++;
2728        }
2729
2730        return;
2731
2732use_btree:
2733
2734        /* In-btree allocation by manual memory manipulation */
2735        while (tl->b_hgt > tl->b_cnt)
2736        {
2737                size_t num, msize;
2738
2739                unsigned i;
2740
2741                btree *br;
2742
2743                unsigned offset;
2744
2745                /* Get smallest allocation in btree */
2746                btree *b = btree_remove(tl, 0);
2747
2748                msize = b->s.size;
2749
2750                /* How many nodes can fit? */
2751                num = msize / sizeof(btree);
2752
2753                /* As many as required */
2754                if (num > tl->b_hgt - tl->b_cnt) num = tl->b_hgt - tl->b_cnt;
2755
2756                /* Prevent recursion by always adding at least one node */
2757                if (num < 1) num = 1;
2758
2759                /* We are using this */
2760                set_used(b, msize);
2761                offset = b->s.bs_offset & ~15;
2762
2763                for (i = 0; i < num; i++)
2764                {
2765                        br = shift(b, sizeof(btree));
2766                        b->s.size = sizeof(btree);
2767                        offset += sizeof(btree);
2768                        if (i != num - 1) br->s.bs_offset = offset;
2769                        msize -= sizeof(btree);
2770
2771                        slist_add(&tl->btree_freenode, &b->list);
2772                        b = br;
2773                }
2774
2775                tl->b_cnt += num;
2776
2777                /* Any room left? */
2778                if (!msize) continue;
2779
2780                /* Free remaining fragment */
2781                b->s.size = msize;
2782                b->s.bs_offset = offset;
2783                fast_free(tl, b, msize);
2784        }
2785}
2786
2787static void btree_node_insert(atls *tl, btree *b, int loc, unsigned ssize, btree *node);
2788
2789/* Split myself */
2790static noinline void btree_node_insert_aux(atls *tl, btree *b, int loc, unsigned ssize, btree *node)
2791{
2792        btree *tmp, *tmp2, *bp;
2793
2794        unsigned bsize = 0, tsize;
2795
2796        int i, j, bn;
2797
2798        void *st;
2799
2800        size_t new;
2801        int inserted = 0;
2802        size_t next;
2803
2804        /* New node */
2805        st = slist_rem(&tl->btree_freenode);
2806        tmp = list_entry(btree, data, st);
2807        tl->b_cnt--;
2808
2809        /* Clear it */
2810        memset(&tmp->data, 0, offsetof(btree, prev) - SEPSIZE);
2811
2812#if 0
2813        /* Hack - get daughter testing to work */
2814        tmp->parent = (btree *) 1;
2815#endif
2816
2817        /* Special case - insert at start? */
2818        if (!loc)
2819        {
2820                /* Insert at the beginning */
2821                tmp->bsize[1] = ssize + 2;
2822                tmp->prev[1] = 0;
2823                btree_update_daughter(tmp, node, 1);
2824                inserted = 1;
2825
2826                /* Copy things below median here */
2827                for (i = 2, j = b_start(b); i <= BT_MAX/2; i++, j = bn)
2828                {
2829                        bn = b_next(b, j);
2830
2831                        tmp->bsize[i] = btree_ssize(b, j) + i + 1;
2832                        tmp->prev[i] = i - 1;
2833                        btree_update_daughter(tmp, b_ptr(b, j), i);
2834
2835                        btree_free(b, j);
2836                }
2837        }
2838        else
2839        {
2840                /* Copy things below median here */
2841                for (i = 1, j = b_start(b); i <= BT_MAX/2; i++, j = bn)
2842                {
2843                        bn = b_next(b, j);
2844
2845                        tmp->bsize[i] = btree_ssize(b, j) + i + 1;
2846                        tmp->prev[i] = i - 1;
2847                        btree_update_daughter(tmp, b_ptr(b, j), i);
2848
2849                        btree_free(b, j);
2850
2851                        /* Need to insert new node? */
2852                        if (j == loc)
2853                        {
2854                                i++;
2855                                tmp->bsize[i] = ssize + i + 1;
2856                                tmp->prev[i] = i - 1;
2857                                btree_update_daughter(tmp, node, i);
2858                                inserted = 1;
2859                        }
2860                }
2861        }
2862        b_start(b) = j;
2863        b_prev(b, j) = 0;
2864
2865        /* Finish initialization of new node */
2866        b_start(tmp) = 1;
2867        b_last(tmp) = i - 1;
2868        b_next(tmp, i - 1) = 0;
2869        tsize = tmp->bsize[i - 1];
2870        b_mask(tmp) = -(1 << (i - 1));
2871
2872        /* Need to insert in remainder? */
2873        if (!inserted)
2874        {
2875                next = b_next(b, loc);
2876
2877                /* We have space - add it */
2878                new = btree_alloc(b);
2879
2880                b->bsize[new] = ssize + next;
2881                b_prev(b, next) = new;
2882                b_next(b, loc) = new;
2883                b_prev(b, new) = loc;
2884
2885                /* Am I last?  Need to update parents */
2886                if (!next) btree_update_psize(b, ssize);
2887
2888                btree_update_daughter(b, node, new);
2889        }
2890
2891        bp = b->parent;
2892        if (bp)
2893        {
2894                /* Get node previous to myself above */
2895                size_t ip = b_prev(bp, b_pindex(b));
2896
2897                /* Easy - just insert into the parent, tail recurse */
2898                btree_node_insert(tl, bp, ip, tsize, tmp);
2899
2900                return;
2901        }
2902
2903        /* I'm the top node */
2904
2905        /* New node */
2906        st = slist_rem(&tl->btree_freenode);
2907        tmp2 = list_entry(btree, data, st);
2908        tl->b_cnt--;
2909
2910        /* btree is taller */
2911        tl->b_hgt++;
2912
2913        /* Copy b into this -shouldn't need this, use allocated root instead */
2914        memcpy(&tmp2->data, &b->data, sizeof(btree) - SEPSIZE);
2915
2916        for (i = b_start(b); i; i = b_next(b, i))
2917        {
2918                b_ptr(b, i)->parent = tmp2;
2919                bsize = b->bsize[i];
2920        }
2921
2922        /* Init b */
2923        b->bsize[1] = tsize + 2;
2924        b->bsize[2] = bsize & ~0xff;
2925        b_ptr(b, 1) = tmp;
2926        b_ptr(b, 2) = tmp2;
2927        b_prev(b, 0) = 2;
2928        b_prev(b, 1) = 0;
2929        b_prev(b, 2) = 1;
2930        b_start(b) = 1;
2931        b_mask(b) = -4;
2932        b->parent = NULL;
2933
2934        /* Make links */
2935        tmp->parent = b;
2936        tmp2->parent = b;
2937        b_pindex(tmp) = 1;
2938        b_pindex(tmp2) = 2;
2939}
2940
2941static void btree_node_insert(atls *tl, btree *b, int loc, unsigned ssize, btree *node)
2942{
2943        size_t new;
2944        size_t next;
2945
2946#ifdef DEBUG_ALLOC_SLOW
2947        if (ssize & 0xff) errx(1, "ssize not clean\n");
2948#endif
2949
2950        if (!b_mask(b))
2951        {
2952                btree_node_insert_aux(tl, b, loc, ssize, node);
2953
2954                return;
2955        }
2956
2957        /* We have space - add it */
2958        new = btree_alloc(b);
2959
2960        next = b_next(b, loc);
2961        b->bsize[new] = ssize + next;
2962        b_prev(b, next) = new;
2963        b_next(b, loc) = new;
2964        b_prev(b, new) = loc;
2965
2966        /* Am I last?  Need to update parents */
2967        if (!next) btree_update_psize(b, ssize);
2968
2969        btree_update_daughter(b, node, new);
2970}
2971
2972static void btree_insert(atls *tl, btree *n, size_t size)
2973{
2974        int ip = 0;
2975
2976        /* Convert to internal size (upper 24bits of 32bit bsize) */
2977        unsigned ssize = size * 16;
2978
2979        /* First find where to put it, splitting to make room */
2980        btree *b = btree_find(tl, ssize, &ip);
2981
2982#ifdef DEBUG_ALLOC_SLOW
2983        if (!un_used(n)) errx(1, "inserting a used node\n");
2984        if (size != n->s.size) errx(1, "size missmatch\n");
2985#endif
2986
2987        /* Make a leaf node */
2988        //b_start(n) = 0;
2989
2990        /* Hack - do the above more efficiently */
2991        n->bsize[0] = 0;
2992
2993        /* Insert it */
2994        btree_node_insert(tl, b, ip, ssize, n);
2995
2996        btree_cleanup(tl);
2997}
2998
2999static noinline btree *btree_get(atls *tl, unsigned size)
3000{
3001        DECL_PROF_FUNC;
3002
3003        unsigned ssize = size * 16;
3004        btree *b;
3005
3006        b = btree_remove(tl, ssize);
3007
3008        if (b)
3009        {
3010                /* Do not try to merge with me - I'm already taken! */
3011                set_used(b, b->s.size);
3012        }
3013
3014        return b;
3015}
3016
3017/* Dumb nlogn merge.  Avoids recursion though */
3018static void btree_merge(atls *tl1, atls *tl2)
3019{
3020        btree *b;
3021
3022        slist *s, *sn;
3023
3024        while ((b = btree_remove(tl2, 0)))
3025        {
3026                btree_insert(tl1, b, b->s.size);
3027        }
3028
3029        /* Update allocated size */
3030        tl1->a_alloced += tl2->a_alloced;
3031
3032        /* Free the old extra btree nodes */
3033        scan_slist_safe(&tl2->btree_freenode, s, sn)
3034        {
3035                b = list_entry(btree, data, s);
3036
3037                /* Delete it */
3038                local_free(tl1, &b->data);
3039        }
3040
3041        tl2->b_cnt = 0;
3042}
3043
3044/* Count number of nodes + leaves in the btree recursively */
3045static int count_btree(btree *b)
3046{
3047        int i, count = 1;
3048
3049        for (i = b_start(b); i; i = b_next(b, i))
3050        {
3051                count += count_btree(b_ptr(b, i));
3052        }
3053
3054        return count;
3055}
3056
3057static int count_btree_space(btree *b)
3058{
3059        int i, count = 0;
3060
3061        if (b_leaf(b)) return b->s.size - PTRSIZE;
3062
3063        for (i = b_start(b); i; i = b_next(b, i))
3064        {
3065                count += count_btree_space(b_ptr(b, i));
3066        }
3067
3068        return count;
3069}
3070
3071
3072#ifdef DEBUG_ALLOC_SLOW
3073
3074/* Check double list constraints */
3075static void test_double_lists(atls *tl)
3076{
3077        btree *b;
3078        dlist *d, *dn;
3079
3080        unsigned i;
3081
3082        for (i = 1; i < NUM_QS; i++)
3083        {
3084                if (tl->qs[i].next->prev != &tl->qs[i]) errx(1, "First double link broken\n");
3085
3086                scan_list_safe(&tl->qs[i], d, dn)
3087                {
3088                        b = list_entry(btree, list, d);
3089                        check_sep(b);
3090
3091                        if (!un_used(b)) errx(1, "False used\n");
3092                        if (b->s.size != (i+1)*16) errx(1, "Wrong sized double link\n");
3093                        if (b->s.bs_offset & FLG_SIZE8) errx(1, "flag size wrong\n");
3094
3095                        if (dn->prev != d) errx(1, "Back-link broken\n");
3096                }
3097        }
3098
3099        if (tl->q_mask & (1ULL << 63)) errx(1, "double list last bit set\n");
3100}
3101
3102#else
3103#define test_double_lists(T) ((void) sizeof(T))
3104#endif
3105
3106
3107#ifdef DEBUG_ALLOC_SLOW
3108/* Test small list constraints */
3109static void test_small_list(atls *tl)
3110{
3111        btree *b, *bn;
3112
3113        btree *q8 = get_q8(tl);
3114
3115        if (small_prev(small_next(q8)) != q8) errx(1, "First link broken\n");
3116
3117        for (b = small_next(q8); b != q8; b = bn)
3118        {
3119                check_sep(b);
3120                bn = small_next(b);
3121
3122                if (!(b->s.bs_offset & FLG_SIZE8)) errx(1, "Wrong sized small link\n");
3123                if (!un_used(b)) errx(1, "False used\n");
3124                if (small_prev(bn) != b) errx(1, "Back-link broken\n");
3125        }
3126}
3127#else
3128#define test_small_list(T) ((void) sizeof(T))
3129#endif
3130
3131/* Add to end of small list */
3132static void small_insert(atls *tl, btree *b)
3133{
3134        btree *q8 = get_q8(tl);
3135        btree *qp;
3136
3137        /* Set flag */
3138        set_size8(b);
3139
3140        qp = small_prev(q8);
3141
3142        set_small_prev(b, qp);
3143        set_small_next(qp, b);
3144
3145        set_small_next(b, q8);
3146        set_small_prev(q8, b);
3147}
3148
3149static void small_remove(btree *b)
3150{
3151        btree *qn = small_next(b);
3152        btree *qp = small_prev(b);
3153
3154        set_small_next(qp, qn);
3155        set_small_prev(qn, qp);
3156
3157        /* Clear flag */
3158        unset_size8(b);
3159}
3160
3161static btree *small_del_first(atls *tl)
3162{
3163        btree *q8 = get_q8(tl);
3164        btree *b = small_next(q8);
3165        btree *qn = small_next(b);
3166
3167        /* List is empty */
3168        if (b == q8) return NULL;
3169
3170        /* Dequeue b */
3171        set_small_next(q8, qn);
3172        set_small_prev(qn, q8);
3173
3174        /* Clear flag */
3175        unset_size8(b);
3176
3177        return b;
3178}
3179
3180static void small_merge(atls *tl1, atls *tl2)
3181{
3182        btree *q81 = get_q8(tl1);
3183        btree *q82 = get_q8(tl2);
3184
3185        btree *q1p = small_prev(q81);
3186        btree *q2n = small_next(q82);
3187        btree *q2p = small_prev(q82);
3188
3189        /* Don't need to do anything if adding an empty list */
3190        if (q2n == q82) return;
3191
3192        set_small_next(q1p, q2n);
3193        set_small_prev(q2n, q1p);
3194
3195        set_small_prev(q81, q2p);
3196        set_small_next(q2p, q81);
3197}
3198
3199/* Slab implementation */
3200
3201static sbheader *slab_start(void *p)
3202{
3203        return (sbheader *) (-SLABSIZE & (uintptr_t) p);
3204}
3205
3206#ifdef DEBUG_ALLOC_SLOW
3207
3208static void test_slab(atls *tl)
3209{
3210        int i;
3211
3212        dlist *d, *dn;
3213
3214        for (i = 0; i < NUM_SB; i++)
3215        {
3216                scan_list_safe(&tl->slab[i], d, dn)
3217                {
3218                        if (dn->prev != d) errx(1, "Back-link broken\n");
3219                }
3220        }
3221
3222        scan_list_safe(&tl->slab_full, d, dn)
3223        {
3224                if (dn->prev != d) errx(1, "Back-link broken\n");
3225        }
3226}
3227#else
3228#define test_slab(T) ((void) sizeof(T))
3229#endif
3230
3231
3232static freesb *slab_alloc_chunk(atls *tl)
3233{
3234        DECL_PROF_FUNC;
3235
3236        freesb *fsb;
3237
3238        size_t alloc_amount = SLABSIZE * (SLABBMAX + 1);
3239        size_t sbrk_end;
3240
3241        unsigned i;
3242        unsigned alloced = SLABBMAX;
3243
3244        /* Handle oom more efficiently */
3245        if (sbrk_oom) return NULL;
3246
3247        /* Make sure percpu value isn't too big */
3248        if (tl->percpu_hash > cpu_total)
3249        {
3250                tl->percpu_hash %= cpu_total;
3251        }
3252
3253        /* Find an unlocked list with something in it */
3254        for (i = tl->percpu_hash; i < cpu_total; i++)
3255        {
3256                if (pc_slab[i].list && !mutex_trylock(&pc_slab[i].m))
3257                {
3258                        if (pc_slab[i].list)
3259                        {
3260                                fsb = pc_slab[i].list;
3261                                pc_slab[i].list = fsb->next;
3262
3263                                mutex_unlock(&pc_slab[i].m);
3264#ifdef WINDOWS
3265                                /* Reallow use of pages */
3266                                for (i = 0; i < fsb->count; i++)
3267                                {
3268                                        VirtualAlloc(fsb->blocks[i], SLABSIZE, MEM_COMMIT, PAGE_READWRITE);
3269                                }
3270#endif
3271
3272                                return fsb;
3273                        }
3274
3275                        mutex_unlock(&pc_slab[i].m);
3276                }
3277        }
3278
3279        for (i = 0; i < tl->percpu_hash; i++)
3280        {
3281                if (pc_slab[i].list && !mutex_trylock(&pc_slab[i].m))
3282                {
3283                        if (pc_slab[i].list)
3284                        {
3285                                fsb = pc_slab[i].list;
3286                                pc_slab[i].list = fsb->next;
3287
3288                                mutex_unlock(&pc_slab[i].m);
3289#ifdef WINDOWS
3290                                /* Reallow use of pages */
3291                                for (i = 0; i < fsb->count; i++)
3292                                {
3293                                        VirtualAlloc(fsb->blocks[i], SLABSIZE, MEM_COMMIT, PAGE_READWRITE);
3294                                }
3295#endif
3296
3297                                return fsb;
3298                        }
3299
3300                        mutex_unlock(&pc_slab[i].m);
3301                }
3302        }
3303
3304        mutex_lock(&sb_lock);
3305
3306        sbrk_end = sbrk_start + sbrk_size;
3307
3308        /* Try to realign with SLABSIZE boundaries */
3309        if (sbrk_end & (SLABSIZE - 1))
3310        {
3311                alloc_amount += SLABSIZE - (sbrk_end & (SLABSIZE - 1));
3312        }
3313
3314        fsb = sbrk(alloc_amount);
3315
3316        if (fsb == MAP_FAILED)
3317        {
3318                /* Too much to allocate - fall back on mmap */
3319                sbrk_oom = 1;
3320                mutex_unlock(&sb_lock);
3321
3322                return NULL;
3323        }
3324
3325        /* Update sbrk information */
3326        sbrk_size = alloc_amount + (uintptr_t) fsb - sbrk_start;
3327
3328        mutex_unlock(&sb_lock);
3329
3330        /* Are we improperly aligned? */
3331        if ((SLABSIZE - 1) & (uintptr_t) fsb)
3332        {
3333                /* Realign myself (wastes memory) */
3334                freesb *fsb_new = (freesb *) slab_start(shift(fsb, SLABSIZE - 1));
3335
3336                /* Did we shift too much? */
3337                if ((uintptr_t) fsb_new - (uintptr_t) fsb > alloc_amount - SLABSIZE * (SLABBMAX + 1))
3338                {
3339                        alloced--;
3340                }
3341
3342                fsb = fsb_new;
3343        }
3344
3345        /* Fill in details */
3346        for (i = 0; i < alloced; i++)
3347        {
3348                fsb->blocks[i] = shift(fsb, SLABSIZE * (i + 1));
3349        }
3350        fsb->count = alloced;
3351
3352        return fsb;
3353}
3354
3355static noinline void slab_free_chunk(atls *tl, freesb *fsb)
3356{
3357        DECL_PROF_FUNC;
3358
3359        unsigned i;
3360
3361        /* Mark memory as unused */
3362        for (i = 0; i < fsb->count; i++)
3363        {
3364#ifdef WINDOWS
3365                VirtualFree(fsb->blocks[i], SLABSIZE, MEM_DECOMMIT);
3366#else
3367                madvise(fsb->blocks[i], SLABSIZE, MADV_DONTNEED);
3368#endif
3369        }
3370
3371        /* Make sure percpu value isn't too big */
3372        if (tl->percpu_hash > cpu_total)
3373        {
3374                tl->percpu_hash %= cpu_total;
3375        }
3376
3377        /* First trylock everything, to find something that works */
3378        for (i = tl->percpu_hash; i < cpu_total; i++)
3379        {
3380                if (!mutex_trylock(&pc_slab[i].m))
3381                {
3382                        tl->percpu_hash = i;
3383                        goto success;
3384                }
3385        }
3386
3387        for (i = 0; i < tl->percpu_hash; i++)
3388        {
3389                if (!mutex_trylock(&pc_slab[i].m))
3390                {
3391                        tl->percpu_hash = i;
3392                        goto success;
3393                }
3394        }
3395
3396        /* Failure - too much contention, just use our current value */
3397        i = tl->percpu_hash;
3398        mutex_lock(&pc_slab[i].m);
3399
3400success:
3401        tl->percpu_hash = i;
3402        fsb->next = pc_slab[i].list;
3403        pc_slab[i].list = fsb;
3404        mutex_unlock(&pc_slab[i].m);
3405}
3406
3407
3408static sbheader *slab_alloc_block(atls *tl)
3409{
3410        freesb *fsb;
3411        sbheader *sb;
3412
3413        /* Make sure we have empty blocks */
3414        if (!tl->slab_chunk)
3415        {
3416                tl->slab_chunk = slab_alloc_chunk(tl);
3417                if (!tl->slab_chunk) return NULL;
3418        }
3419
3420        fsb = tl->slab_chunk;
3421
3422        if (!fsb->count)
3423        {
3424                sb = (sbheader *) fsb;
3425
3426                tl->slab_chunk = NULL;
3427
3428                /* Prevent reuse of this overwritten block */
3429                sb->size = 0;
3430
3431                return sb;
3432        }
3433
3434        fsb->count--;
3435        sb = fsb->blocks[fsb->count];
3436
3437        return sb;
3438}
3439
3440static void slab_free_block(atls *tl, sbheader *sb)
3441{
3442        freesb *ofsb = tl->slab_chunk;
3443        freesb *fsb = (freesb *) sb;
3444
3445        if (ofsb)
3446        {
3447                if (ofsb->count < SLABBMAX - 1)
3448                {
3449                        ofsb->blocks[ofsb->count] = sb;
3450                        ofsb->count++;
3451                        return;
3452                }
3453
3454                /* Simplest case - no chunk yet */
3455                fsb->count = 0;
3456                tl->slab_chunk = fsb;
3457
3458                slab_free_chunk(tl, ofsb);
3459
3460                return;
3461        }
3462
3463        /* Simplest case - no chunk yet */
3464        fsb->count = 0;
3465        tl->slab_chunk = fsb;
3466}
3467
3468static int init_sldata(void)
3469{
3470        unsigned i;
3471
3472        /* Init total number of cpus */
3473        cpu_total = cpu_num();
3474
3475        /* Init per-cpu free slab lists */
3476        pc_slab = big_alloc_aux(page_align(cpu_total * 64));
3477        if (!pc_slab) return 1;
3478
3479        /*
3480         * Initialized mutexes have state zero, and initialized lists are NULL
3481         * so we don't have to do anything to pc_slab to finish initializing it.
3482         */
3483
3484        /* Calculate slab total sizes so we avoid a division later */
3485        for (i = 1; i < NUM_SB; i++)
3486        {
3487                unsigned size = i * 16;
3488
3489                /* total size taken by all blocks */
3490                sltotal[i] = ((SLABSIZE - offsetof(sbheader, data))/size) * size;
3491        }
3492
3493        return 0;
3494}
3495
3496static sbheader *slab_create(atls *tl, dlist *slab, unsigned size)
3497{
3498        DECL_PROF_FUNC;
3499
3500        unsigned index = size/16;
3501        unsigned total = sltotal[index];
3502
3503        uintptr_t offset;
3504
3505        sbheader *sb = slab_alloc_block(tl);
3506        if (!sb) return NULL;
3507
3508        /* Normalize size */
3509        size = index * 16;
3510
3511        /* Fill in details */
3512        sb->tail = &tl->tail;
3513
3514        dlist_add(slab, &sb->list);
3515
3516        /* Already initialized? */
3517        if (sb->size == size) return sb;
3518
3519        sb->used = 0;
3520        sb->size = size;
3521
3522        /* Calculate offset */
3523        if ((size == 64) || (size == 256))
3524        {
3525                /* Make cacheline-aligned */
3526                offset = (uintptr_t) sb + 128 + 1;
3527        }
3528        else
3529        {
3530                void *tmp;
3531
3532                /* Start of region */
3533                offset = (-16 & (uintptr_t) &sb->data);
3534
3535                /* Randomize offset */
3536                tmp = rnd_offset((void *) offset, (uintptr_t) sb + SLABSIZE - (uintptr_t) offset, total);
3537
3538                offset = (uintptr_t) tmp + 1;
3539        }
3540
3541#ifdef DEBUG_ALLOC
3542        if (offset - 1 + total - (uintptr_t) sb > SLABSIZE) errx(1, "slab overflow\n");
3543#endif
3544
3545        sb->first = offset;
3546        sb->max = (uintptr_t) sb + SLABSIZE - sb->size;
3547
3548        return sb;
3549}
3550
3551static void slab_free(atls *tl, void *p)
3552{
3553        DECL_PROF_FUNC;
3554
3555        sbheader *sb = slab_start(p);
3556
3557        /* Do I own this? */
3558        if (unlikely(sb->tail != &tl->tail))
3559        {
3560                /* Hack wrt mealloc */
3561                prepend_queue(p, tl, &sb->tail);
3562
3563                return;
3564        }
3565
3566        /* Add to this slab's free list */
3567        *(uintptr_t *)p = sb->first;
3568        sb->first = (uintptr_t) p;
3569
3570        sb->used--;
3571        if (!sb->used)
3572        {
3573                /* If I am the only one in the partial list, don't bother to delete */
3574                if (sb->list.next == sb->list.prev) return;
3575
3576                dlist_del(&sb->list);
3577
3578                /* Free it */
3579                slab_free_block(tl, sb);
3580        }
3581}
3582
3583static void *slab_alloc(atls *tl, size_t size);
3584static noinline void *slab_alloc_nolist(size_t size, dlist *slab, atls *tl)
3585{
3586        DECL_PROF_FUNC;
3587
3588        void *res;
3589
3590        /* Out of line zero-check */
3591        if (!size)
3592        {
3593                size++;
3594        }
3595        else
3596        {
3597                /* Scan queue if we have nothing left */
3598                if (!tl->slab_chunk)
3599                {
3600                        scan_queue(tl, &tl->head, 0);
3601                }
3602
3603                /* Still nothing? */
3604                if (dlist_empty(slab))
3605                {
3606                        if (!slab_create(tl, slab, size + 15))
3607                        {
3608                                goto again;
3609                        }
3610                }
3611        }
3612
3613        /* We have something to use */
3614        res = slab_alloc(tl, size);
3615        if (res) return res;
3616
3617again:
3618
3619        size = sep_align(size);
3620        return local_alloc(tl, size);
3621}
3622
3623static void *slab_alloc_aux(atls *tl, dlist *slab)
3624{
3625        DECL_PROF_FUNC;
3626
3627        /* Get sbheader */
3628        sbheader *sb = list_entry(sbheader, list, slab->next);
3629
3630        uintptr_t p = sb->first;
3631
3632        sb->used++;
3633
3634        if (!(p & 1))
3635        {
3636                sb->first = *(uintptr_t *) (void *) p;
3637
3638                if (!sb->first) goto done;
3639        }
3640        else
3641        {
3642                p--;
3643                sb->first += sb->size;
3644                if (sb->first > sb->max)
3645                {
3646                        sb->first = 0;
3647
3648                        goto done;
3649                }
3650        }
3651
3652        return (void *) p;
3653
3654done:
3655        /* Move to full list */
3656        dlist_del(&sb->list);
3657        dlist_add(&tl->slab_full, &sb->list);
3658
3659        return (void *) p;
3660}
3661
3662static void *slab_alloc(atls *tl, size_t size)
3663{
3664        dlist *slab;
3665
3666        size_t nsize = size + 15;
3667
3668#ifdef DEBUG_NO_SLAB
3669        size = sep_align(size);
3670        return local_alloc(tl, size);
3671#endif
3672
3673        /* Get slab */
3674#ifdef __x86_64__
3675        slab = shift(&tl->slab[0], nsize & ~15);
3676#else
3677        slab = shift(&tl->slab[0], (nsize & ~15) / 2);
3678#endif
3679
3680        if (dlist_empty(slab)) return slab_alloc_nolist(size, slab, tl);
3681
3682        return slab_alloc_aux(tl, slab);
3683}
3684
3685/* Same as above, but fail if we can't quickly allocate */
3686static void *slab_alloc_safe(atls *tl, size_t size)
3687{
3688        dlist *slab;
3689
3690#ifdef DEBUG_NO_SLAB
3691        return NULL;
3692#endif
3693
3694        size += 15;
3695
3696        /* Get slab */
3697#ifdef __x86_64__
3698        slab = shift(&tl->slab[0], size & ~15);
3699#else
3700        slab = shift(&tl->slab[0], (size & ~15) / 2);
3701#endif
3702
3703        /* Fail if we can't quickly allocate (don't call scan_queue) */
3704        if (dlist_empty(slab) && !slab_create(tl, slab, size)) return NULL;
3705
3706        return slab_alloc_aux(tl, slab);
3707}
3708
3709static noinline void *slab_zalloc(atls *tl, size_t size)
3710{
3711        void *p = slab_alloc(tl, size);
3712        if (p) return memset(p, 0, size);
3713
3714        size = sep_align(size);
3715
3716        p = fast_alloc(tl, size);
3717        if (!p)
3718        {
3719                tl->callocable = 0;
3720                p = slow_alloc(tl, size);
3721
3722                /* No need to memset? */
3723                if (!p || tl->callocable)
3724                {
3725                        return p;
3726                }
3727        }
3728
3729        /* Success */
3730        return memset(p, 0, size - 8);
3731}
3732
3733static void slab_merge(atls *tl1, atls *tl2)
3734{
3735        int i;
3736        dlist *d, *dn;
3737
3738        /* Merge partial slabs */
3739        for (i = 0; i < NUM_SB; i++)
3740        {
3741                /* Update all the tail pointers */
3742                scan_list_safe(&tl2->slab[i], d, dn)
3743                {
3744                        sbheader *sb = list_entry(sbheader, list, d);
3745                        sb->tail = &tl1->tail;
3746
3747                        /* There may be one empty slab in this slot */
3748                        if (!sb->used)
3749                        {
3750                                /* Move to full list */
3751                                dlist_del(&sb->list);
3752                                dlist_add(&tl1->slab_full, &sb->list);
3753                        }
3754                }
3755
3756                dlist_merge(&tl1->slab[i], &tl2->slab[i]);
3757        }
3758
3759        /* Merge full and empty slabs */
3760
3761        /* Update all the tail pointers */
3762        scan_list(&tl2->slab_full, d)
3763        {
3764                sbheader *sb = list_entry(sbheader, list, d);
3765                sb->tail = &tl1->tail;
3766        }
3767
3768        dlist_merge(&tl1->slab_full, &tl2->slab_full);
3769
3770        /* Get rid of empty pages */
3771        if (tl2->slab_chunk) slab_free_chunk(tl1, tl2->slab_chunk);
3772}
3773
3774static void local_free(atls *tl, void *p)
3775{
3776        if (is_slab(p))
3777        {
3778                slab_free(tl, p);
3779        }
3780        else
3781        {
3782                btree *b = CONTAINER(btree, data, p);
3783                fast_free(tl, b, b->s.size);
3784        }
3785}
3786
3787static void *local_alloc(atls *tl, size_t size)
3788{
3789        DECL_PROF_FUNC;
3790
3791        void *p = fast_alloc(tl, size);
3792        if (p) return p;
3793
3794        return slow_alloc(tl, size);
3795}
3796
3797static void test_all(atls *tl)
3798{
3799        test_fast_lists(tl);
3800        test_double_lists(tl);
3801        test_small_list(tl);
3802        test_btree(tl);
3803        test_queue(tl);
3804        test_slab(tl);
3805        test_blocks(tl);
3806}
3807
3808static void block_list_merge(atls *tl1, atls *tl2)
3809{
3810        mealloc *m;
3811        dlist *d;
3812
3813        /* Scan block list, and update all tail pointers */
3814        scan_list(&tl2->bl, d)
3815        {
3816                m = list_entry(mealloc, m_list, d);
3817                m->tail = &tl1->tail;
3818        }
3819
3820        dlist_merge(&tl1->bl, &tl2->bl);
3821}
3822
3823static void atls_merge(atls *tl1, atls *tl2)
3824{
3825        int i;
3826
3827        /* Merge block lists so others know about us */
3828        block_list_merge(tl1, tl2);
3829
3830        /* Then merge the btrees */
3831        btree_merge(tl1, tl2);
3832
3833        /* Merge the fast lists */
3834        fast_merge(tl1, tl2);
3835
3836        /* Merge the slabs */
3837        slab_merge(tl1, tl2);
3838
3839        /* Then the double links */
3840        for (i = 1; i < NUM_QS; i++)
3841        {
3842                dlist_merge(&tl1->qs[i], &tl2->qs[i]);
3843        }
3844
3845        /* Finally the small list */
3846        small_merge(tl1, tl2);
3847
3848        test_all(tl1);
3849}
3850
3851static btree *split_node_rhs(atls *tl, btree *b, size_t t_size, size_t msize)
3852{
3853        size_t r_size = t_size - msize;
3854
3855        btree *bm = shift(b, msize);
3856
3857#ifdef DEBUG_ALLOC_SLOW
3858        if (t_size != b->s.size) errx(1, "size missmatch\n");
3859        if (msize > t_size) errx(1, "too big to fit in split\n");
3860        check_sep(b);
3861#endif
3862
3863        /* Too large to split profitably? */
3864        if (!r_size) return b;
3865
3866        /* Update local size */
3867        b->s.size = msize;
3868
3869        /* Create middle seperator */
3870        set_sep(bm, r_size, b);
3871
3872        check_sep(bm);
3873
3874        /* Make sure to try to use remainder */
3875        fast_free(tl, b, msize);
3876
3877        /* Paranoia */
3878        check_sep(b);
3879        check_sep(bm);
3880
3881        /* Used for when right node is used */
3882        return bm;
3883}
3884
3885static always_inline void *split_node(atls *tl, btree *b, size_t t_size, size_t msize)
3886{
3887        size_t r_size = t_size - msize;
3888
3889        btree *bm = shift(b, msize);
3890
3891#ifdef DEBUG_ALLOC_SLOW
3892        if (t_size != b->s.size) errx(1, "size missmatch\n");
3893        if (msize > t_size) errx(1, "too big to fit in split\n");
3894        check_sep(b);
3895#endif
3896
3897        /* Too large to split profitably? */
3898        if (r_size * 4 < msize)
3899        {
3900                /* Used this whole */
3901                return &b->data;
3902        }
3903
3904        /* Update local size */
3905        b->s.size = msize;
3906
3907        /* Create middle seperator */
3908        set_sep(bm, r_size, b);
3909
3910        check_sep(bm);
3911
3912        /* Make sure to try to use remainder */
3913        fast_free(tl, bm, r_size);
3914
3915        /* Paranoia */
3916        check_sep(b);
3917        check_sep(bm);
3918
3919        return &b->data;
3920}
3921
3922static void node_insert(atls *tl, btree *b)
3923{
3924        size_t size = b->s.size;
3925
3926        if (size > QS_MAX)
3927        {
3928                /* Insert new segment into btree */
3929                btree_insert(tl, b, size);
3930
3931                return;
3932        }
3933
3934        if (size == 16)
3935        {
3936                small_insert(tl, b);
3937
3938                return;
3939        }
3940
3941        dlist_add(MYSIZE_TO_PTR(tl, size), &b->list2);
3942        tl->q_mask |= 1ULL << ((size - 8) / 16);
3943}
3944
3945/* Complete merge */
3946static void merge_node_aux(atls *tl, btree *bl)
3947{
3948        DECL_PROF_FUNC;
3949
3950        size_t msize = bl->s.size;
3951
3952        /* Are we the only element in the allocation? */
3953        btree *br = shift(bl, msize);
3954
3955        mealloc *m;
3956
3957        /* Is block empty? */
3958        if ((bl->s.bs_offset >= HEADERSIZE) || br->s.size || (msize * 4 > tl->a_alloced)) goto save;
3959
3960        /* Save a block, if it is big enough to use for a pending allocation */
3961        if (tl->s_wanted && (tl->s_wanted <= bl->s.size))
3962        {
3963                /* No longer wanted */
3964                tl->s_wanted = 0;
3965
3966                goto save;
3967        }
3968
3969        /* Get header */
3970        m = page_start(bl);
3971
3972        /* Remove from the list */
3973        dlist_del(&m->m_list);
3974
3975        /* Size of block */
3976        msize = m->b.s.size + HEADERSIZE;
3977
3978#ifdef DEBUG_ALLOC_SLOW
3979        if (msize & (PAGESIZE - 1)) errx(1, "big block size incorrect\n");
3980#endif
3981
3982        tl->a_alloced -= msize;
3983
3984        big_freed(m, msize);
3985
3986#ifndef WINDOWS
3987        munmap(m, msize);
3988#else
3989        VirtualFree(m, 0, MEM_RELEASE);
3990#endif
3991        return;
3992
3993save:
3994        /* element is unallocated */
3995        set_unused(bl, br);
3996
3997        /* Insert into correct data structure */
3998        node_insert(tl, bl);
3999}
4000
4001/* Merge a node with unallocated neighbours + insert into free list */
4002static void merge_node(atls *tl, void *p)
4003{
4004        DECL_PROF_FUNC;
4005
4006        btree *b = CONTAINER(btree, data, p);
4007        btree *bl = b, *br = shift(b, b->s.size);
4008
4009        size_t tsize;
4010
4011#ifdef DEBUG_ALLOC_SLOW
4012        if (un_used(b)) errx(1, "merging unused node");
4013#endif
4014
4015        /* Test right */
4016        if (un_used(br))
4017        {
4018                if (br->s.bs_offset & FLG_SIZE8)
4019                {
4020                        small_remove(br);
4021                        tsize = 16;
4022                }
4023                else
4024                {
4025                        tsize = br->s.size;
4026
4027                        if (tsize > QS_MAX)
4028                        {
4029                                btree_node_del(tl, br->parent, b_pindex(br));
4030                        }
4031                        else
4032                        {
4033                                dlist_del(&br->list2);
4034                        }
4035                }
4036
4037                /* Fixup sizes */
4038                b->s.size += tsize;
4039        }
4040
4041        /* Test left */
4042        if (left_unused(b))
4043        {
4044                if (b->s.bs_offset & FLG_LSIZE8)
4045                {
4046                        bl = shift(b, -(uintptr_t)16);
4047
4048                        small_remove(bl);
4049                }
4050                else
4051                {
4052                        bl = b->s.left;
4053
4054                        if (bl->s.size > QS_MAX)
4055                        {
4056                                btree_node_del(tl, bl->parent, b_pindex(bl));
4057                        }
4058                        else
4059                        {
4060                                dlist_del(&bl->list2);
4061                        }
4062                }
4063
4064                /* Fixup sizes */
4065                bl->s.size += b->s.size;
4066        }
4067
4068        merge_node_aux(tl, bl);
4069}
4070
4071#ifdef __x86_64__
4072
4073#define SAVE_REG(N, V)\
4074        asm volatile ("movq %0, %%xmm" #N "\n\t" :: "mr" (V))
4075
4076#define RESTORE_REG(N, V)\
4077        asm volatile ("movq %%xmm" #N ", %0\n\t" : "=r" (V))
4078
4079static always_inline void *fast_alloc(atls *tl, size_t size)
4080{
4081        DECL_PROF_FUNC;
4082
4083        size_t n;
4084        u64b mask, tmask;
4085        slist *p;
4086
4087        btree *b;
4088        size_t rsize;
4089
4090        if (unlikely(size > FAST_64_BIN)) return NULL;
4091
4092        n = size2fl(size);
4093        mask = FAST_MASK << n;
4094        tmask = tl->f_mask & mask;
4095
4096        /* Anything to do? */
4097        while (tmask)
4098        {
4099                n = ffsq(tmask);
4100                p = &tl->fl[n];
4101
4102                SAVE_REG(0, tmask);
4103
4104                while (p->next)
4105                {
4106                        slist *s = slist_rem(p);
4107                        b = CONTAINER(btree, list, s);
4108
4109                        rsize = b->s.size;
4110
4111                        check_sep(b);
4112
4113                        /* Found a match? */
4114                        if (likely(rsize >= size)) return &b->data;
4115
4116                        RESTORE_REG(0, tmask);
4117
4118                        /* Move to lower bin */
4119                        //fast_add(tl, b, n - 1);
4120
4121                        /* Inlined version of the above so %rbx isn't used */
4122                        slist_add(&p[-1], &b->list);
4123                        tmask = tmask / 2;
4124                        tl->f_mask |= tmask & (-tmask);
4125                }
4126
4127                RESTORE_REG(0, tmask);
4128
4129                /*
4130                 * Turn off least significant bit in tmask, as nothing is left there
4131                 */
4132                mask = (tmask - 1) | ~tmask;
4133                tmask &= mask;
4134                tl->f_mask &= mask;
4135        }
4136
4137        return NULL;
4138}
4139
4140static void *slow_alloc_aux(atls *tl, size_t size)
4141{
4142        DECL_PROF_FUNC;
4143
4144        size_t n;
4145        u64b mask, tmask;
4146
4147        btree *b;
4148        dlist *d;
4149        size_t rsize;
4150
4151        /* Special case empty allocations */
4152        if (size == 16)
4153        {
4154                b = small_del_first(tl);
4155                if (b)
4156                {
4157                        set_used(b, 16);
4158
4159                        return &b->data;
4160                }
4161
4162                n = 1;
4163        }
4164        else
4165        {
4166                n = (size / 16) - 1;
4167        }
4168
4169        mask = (~0ULL) << n;
4170        tmask = tl->q_mask & mask;
4171
4172        /* Are there nodes big enough in the queues? */
4173        while (tmask)
4174        {
4175                /* Ignore if bit unset */
4176                n = ffsq(tmask);
4177                d = &tl->qs[n];
4178
4179                /* Found something? */
4180                if (d->next != d)
4181                {
4182                        b = list_entry(btree, list2, d->next);
4183
4184                        /* Paranoia */
4185                        check_sep(b);
4186
4187                        dlist_del(&b->list2);
4188
4189                        rsize = (n + 1) * 16;
4190                        set_used(b, rsize);
4191                        return split_node(tl, b, rsize, size);
4192                }
4193
4194                /*
4195                 * Turn off least significant bit in tmask, as nothing is left there
4196                 */
4197                mask = (tmask - 1) | ~tmask;
4198                tmask &= mask;
4199                tl->q_mask &= mask;
4200        }
4201
4202        return NULL;
4203}
4204
4205#else
4206
4207/* Versions optimized for 32bit */
4208static always_inline void *fast_alloc(atls *tl, size_t size)
4209{
4210        size_t n = size2fl(size);
4211
4212        unsigned tmask;
4213
4214        slist *p;
4215
4216        btree *b;
4217        size_t rsize;
4218
4219        if (n < 32)
4220        {
4221                tmask = tl->f_mask & (FAST_MASK << n);
4222
4223                /* Anything to do? */
4224                while (tmask)
4225                {
4226                        n = ffsu(tmask);
4227                        p = &tl->fl[n];
4228
4229                        while (p->next)
4230                        {
4231                                slist *s = slist_rem(p);
4232                                b = CONTAINER(btree, list, s);
4233
4234                                rsize = b->s.size;
4235
4236                                check_sep(b);
4237
4238                                /* Found a match? */
4239                                if (likely(rsize >= size)) return &b->data;
4240
4241                                /* Move to lower bin */
4242                                fast_add(tl, b, n - 1);
4243                        }
4244
4245                        /*
4246                         * Turn off least significant bit in tmask, as nothing is left there
4247                         */
4248                        tmask &= tmask - 1;
4249                        tl->f_mask &= ~(1ULL << n);
4250                }
4251
4252                tmask = (tl->f_mask >> 32) & (FAST_MASK >> (32 - n));
4253        }
4254        else
4255        {
4256                tmask = (tl->f_mask >> 32) & (FAST_MASK << (n - 32));
4257        }
4258
4259        if (unlikely(size >= FAST_64_BIN)) return NULL;
4260
4261        /* Anything to do? */
4262        while (tmask)
4263        {
4264                n = ffsu(tmask) + 32;
4265                p = &tl->fl[n];
4266
4267                while (p->next)
4268                {
4269                        slist *s = slist_rem(p);
4270                        b = CONTAINER(btree, list, s);
4271
4272                        rsize = b->s.size;
4273
4274                        check_sep(b);
4275
4276                        /* Found a match */
4277                        if (likely(rsize >= size)) return &b->data;
4278
4279                        /* Move to lower bin */
4280                        fast_add(tl, b, n - 1);
4281                }
4282
4283                /*
4284                 * Turn off least significant bit in tmask, as nothing is left there
4285                 */
4286                tmask &= tmask - 1;
4287                tl->f_mask &= ~(1ULL << n);
4288        }
4289
4290        return NULL;
4291}
4292
4293static void *slow_alloc_aux(atls *tl, size_t size)
4294{
4295        size_t n;
4296        unsigned tmask;
4297
4298        btree *b;
4299        dlist *d;
4300        size_t rsize;
4301
4302        /* Special case empty allocations */
4303        if (size == 16)
4304        {
4305                b = small_del_first(tl);
4306                if (b)
4307                {
4308                        set_used(b, 16);
4309                        return &b->data;
4310                }
4311
4312                n = 1;
4313        }
4314        else
4315        {
4316                n = (size / 16) - 1;
4317        }
4318
4319        if (n < 32)
4320        {
4321                tmask = tl->q_mask & (~0 << n);
4322
4323                /* Are there nodes big enough in the queues? */
4324                while (tmask)
4325                {
4326                        /* Ignore if bit unset */
4327                        n = ffsu(tmask);
4328                        d = &tl->qs[n];
4329
4330                        /* Found something? */
4331                        if (d->next != d)
4332                        {
4333                                b = list_entry(btree, list, d->next);
4334
4335                                /* Paranoia */
4336                                check_sep(b);
4337
4338                                dlist_del(&b->list2);
4339
4340                                rsize = (n + 1) * 16;
4341                                set_used(b, rsize);
4342
4343                                return split_node(tl, b, rsize, size);
4344                        }
4345
4346                        /*
4347                         * Turn off least significant bit in tmask, as nothing is left there
4348                         */
4349                        tmask &= tmask - 1;
4350                        tl->q_mask &= ~(1ULL << n);
4351                }
4352
4353                tmask = tl->q_mask >> 32;
4354        }
4355        else
4356        {
4357                tmask = (tl->q_mask >> 32) & (~0 << (n - 32));
4358        }
4359
4360        /* Are there nodes big enough in the queues? */
4361        while (tmask)
4362        {
4363                /* Ignore if bit unset */
4364                n = ffsu(tmask) + 32;
4365                d = &tl->qs[n];
4366
4367                /* Found something? */
4368                if (d->next != d)
4369                {
4370                        b = list_entry(btree, list, d->next);
4371
4372                        /* Paranoia */
4373                        check_sep(b);
4374
4375                        dlist_del(&b->list2);
4376
4377                        rsize = (n + 1) * 16;
4378                        set_used(b, rsize);
4379
4380                        return split_node(tl, b, rsize, size);
4381                }
4382
4383                /*
4384                 * Turn off least significant bit in tmask, as nothing is left there
4385                 */
4386                tmask &= tmask - 1;
4387                tl->q_mask &= ~(1ULL << n);
4388        }
4389
4390        /* Failed */
4391        return NULL;
4392}
4393
4394#endif
4395
4396static void *block_alloc_aux(atls *tl, size_t size)
4397{
4398        DECL_PROF_FUNC;
4399
4400        btree *b, *br;
4401        mealloc *ma;
4402        size_t rsize, tasize;
4403
4404        /* Make overhead 1/4th of total allocated after this allocation */
4405        tasize = size + (size + tl->a_alloced) / 3;
4406        tasize = page_align(tasize);
4407
4408        /* Clip to BTMALLOC */
4409        if (tasize > BTMALLOC) tasize = BTMALLOC;
4410
4411        /* Must be more than MINALLOC */
4412        if (tasize < MINALLOC) tasize = MINALLOC;
4413
4414        ma = big_alloc_aux(tasize);
4415
4416        if (!ma)
4417        {
4418                /* Try with smaller alloc */
4419                tasize = page_align(size + HEADERSIZE);
4420
4421                ma = big_alloc_aux(tasize);
4422
4423                if (!ma)
4424                {
4425                        /* Try again if new handler works */
4426                        if (handle_oom(size)) return slow_alloc(tl, size);
4427
4428                        return NULL;
4429                }
4430        }
4431
4432        rsize = tasize - HEADERSIZE;
4433
4434        /* Keep track of total allocations */
4435        tl->a_alloced += tasize;
4436
4437        /* Fill in header */
4438        dlist_add(&tl->bl, &ma->m_list);
4439
4440        ma->tail = &tl->tail;
4441
4442        b = &ma->b;
4443
4444        /* Create left seperator */
4445        b->s.size = rsize;
4446        b->s.bs_offset = 16;
4447
4448        /* Position of right seperator */
4449        br = shift(b, rsize);
4450
4451        /* Create right seperator */
4452        br->s.bs_offset = tasize - SEPSIZE;
4453
4454        tl->callocable = 1;
4455
4456        return split_node(tl, b, rsize, size);
4457}
4458
4459static void *block_alloc(atls *tl, size_t size)
4460{
4461        DECL_PROF_FUNC;
4462
4463        btree *b;
4464        void *p;
4465
4466        if (size >= BTMALLOC)
4467        {
4468                tl->callocable = 1;
4469                return big_alloc(tl, size);
4470        }
4471
4472        if (size <= QS_MAX)
4473        {
4474                p = slow_alloc_aux(tl, size);
4475                if (p) return p;
4476
4477                /* Clear fast lists */
4478                clear_fast(tl);
4479
4480                p = slow_alloc_aux(tl, size);
4481                if (p) return p;
4482        }
4483        else
4484        {
4485                /* Clear fast lists */
4486                clear_fast(tl);
4487        }
4488
4489        /* Try to alloc on the btree */
4490        b = btree_get(tl, size);
4491        if (b) return split_node(tl, b, b->s.size, size);
4492
4493        /* Try to grab space from a dead thread */
4494        if (reap_dead(tl)) return local_alloc(tl, size);
4495
4496        /* We need more space, so try to free memory. */
4497        if (scan_queue(tl, &tl->head, size)) return local_alloc(tl, size);
4498
4499#ifdef DEBUG_LEAK
4500        leak_print(tl, "Trying to allocate %llu (%p) but cannot\n", (unsigned long long) size, (void *) size);
4501        malloc_stats_aux(3);
4502#endif
4503
4504        /* Failure - make a big alloc, and add to the btree */
4505        return block_alloc_aux(tl, size);
4506}
4507
4508
4509static void *slow_alloc(atls *tl, size_t size)
4510{
4511        DECL_PROF_FUNC;
4512
4513        /* Fast allocation failed - try normal data structures */
4514        if (size <= QS_MAX)
4515        {
4516                void *res = slow_alloc_aux(tl, size);
4517                if (res) return res;
4518        }
4519
4520        return block_alloc(tl, size);
4521}
4522
4523/* Free with no memory usage */
4524static void free_nomem(void *p)
4525{
4526        DECL_PROF_FUNC;
4527
4528        btree *b = CONTAINER(btree, data, p);
4529
4530        mealloc *m;
4531
4532        slist *v, *tail;
4533
4534#ifdef DEBUG_ALLOC     
4535        /* Check for double-free errors */
4536        if (un_used(b)) errx(1, "Double free with %p\n", p);
4537#endif
4538
4539        /* Get block start */
4540        m = read_bs(b);
4541
4542        /* Treat node as a list now */
4543        v = &b->list;
4544
4545        v->next = NULL;
4546
4547        /*
4548         * Prevent other threads from dying because we have no hazard pointer
4549         * This protects the dereference of m->tail
4550         */
4551        mutex_lock(&h_lock);
4552
4553        /* Prepend the data */
4554        tail = xchg_ptr(m->tail, v);
4555
4556        /* Done */
4557        mutex_unlock(&h_lock);
4558
4559        tail->next = v;
4560}
4561
4562static noinline void free_aux(void *p)
4563{
4564        DECL_PROF_FUNC;
4565
4566        atls *tl = init_tls();
4567        if (!tl)
4568        {
4569                free_nomem(p);
4570                return;
4571        }
4572
4573        PREFIX(free)(p);
4574}
4575
4576static noinline void free_clear(atls *tl)
4577{
4578        clear_fast(tl);
4579}
4580
4581void PREFIX(free)(void *p)
4582{
4583        DECL_PROF_FUNC;
4584
4585        btree *b;
4586        size_t size;
4587
4588        atls *tl;
4589
4590        if (!p) return;
4591
4592        tl = get_tls();
4593
4594        if (!tl)
4595        {
4596                free_aux(p);
4597                return;
4598        }
4599
4600        test_all(tl);
4601
4602        if (likely(is_slab(p)))
4603        {
4604                slab_free(tl, p);
4605
4606                test_all(tl);
4607
4608                return;
4609        }
4610
4611        b = CONTAINER(btree, data, p);
4612        size = b->s.size;
4613
4614#ifdef DEBUG_ALLOC
4615        /* Check for double-free errors */
4616        if (un_used(b)) errx(1, "Double free with %p\n", p);
4617#endif
4618
4619        if (size)
4620        {
4621                /* Get block start */
4622                mealloc *m = read_bs(b);
4623
4624                /* My tail = a local node */
4625                if (unlikely(m->tail != &tl->tail))
4626                {
4627
4628                        /* Add to their queue, and let them deal with it */
4629                        prepend_queue(p, tl, &m->tail);
4630
4631                        return;
4632                }
4633
4634                /* Inlined version of fast_free() */
4635                size = size2fl(size);
4636                tl->f_mask |= 1ULL << size;
4637                slist_add(&tl->fl[size], p);
4638
4639                tl->fcount++;
4640                if (!(tl->fcount & FREE_FAST)) free_clear(tl);
4641
4642                test_all(tl);
4643        }
4644        else
4645        {
4646                big_free_aux(page_start(b));
4647        }
4648}
4649#if 0
4650void cfree(void *p)
4651{
4652        PREFIX(free)(p);
4653}
4654#endif
4655static noinline void *malloc_aux(size_t size)
4656{
4657        DECL_PROF_FUNC;
4658
4659        atls *tl = init_tls();
4660        if (!tl) return NULL;
4661        return PREFIX(malloc)(size);
4662}
4663
4664void *PREFIX(malloc)(size_t size)
4665{
4666        DECL_PROF_FUNC;
4667
4668        void *res;
4669        atls *tl;
4670
4671        test_leak();
4672
4673        /* Init local data if required */
4674        tl = get_tls();
4675
4676        if (!tl) return malloc_aux(size);
4677
4678        test_all(tl);
4679
4680        if (likely(size <= SB_MAX)) return slab_alloc(tl, size);
4681
4682        /* Prevent overflow bug in sep_align() below */
4683        if (unlikely(size > BTMALLOC)) return big_alloc(tl, size);
4684
4685        size = sep_align(size);
4686        res = fast_alloc(tl, size);
4687        if (res) return res;
4688
4689        return slow_alloc(tl, size);
4690}
4691
4692#ifdef DEBUG_ALLOC_SLOW
4693static void test_wiped(void *p, size_t len)
4694{
4695        char *endy = &(((char *)p)[len - 8]);
4696        char *y;
4697
4698        if (!len) return;
4699
4700        for (y = p; y < endy; y++)
4701        {
4702                if (*y) errx(1, "found non-zero\n");
4703        }
4704}
4705#else
4706#define test_wiped(P, L) ((void) (sizeof(P) + sizeof(L)))
4707#endif
4708
4709static noinline void *zalloc_aux(size_t size)
4710{
4711        atls *tl = init_tls();
4712        if (!tl) return NULL;
4713        return zalloc(tl, size);
4714}
4715
4716static void *zalloc(atls *tl, size_t size)
4717{
4718        void *p;
4719
4720        test_leak();
4721        test_all(tl);
4722
4723        if (likely(size <= SB_MAX)) return slab_zalloc(tl, size);
4724
4725        /* Prevent overflow bug in sep_align() below */
4726        if (unlikely(size > BTMALLOC)) return big_alloc(tl, size);
4727
4728        size = sep_align(size);
4729
4730        p = fast_alloc(tl, size);
4731
4732        if (!p)
4733        {
4734                tl->callocable = 0;
4735                p = slow_alloc(tl, size);
4736
4737                /* No need to memset? */
4738                if (!p || tl->callocable)
4739                {
4740                        test_wiped(p, size);
4741
4742                        return p;
4743                }
4744        }
4745
4746        test_all(tl);
4747
4748        return memset(p, 0, size - 8);
4749}
4750
4751static size_t safemul(size_t n, size_t size)
4752{
4753#ifdef __x86_64__
4754        /* 64 bit */
4755        __uint128_t dn = n;
4756        __uint128_t dsize = size;
4757        __uint128_t drsize = dn*dsize;
4758        size_t rsize = drsize;
4759        if (drsize >> 64)
4760        {
4761                /* Overflow */
4762                return TOP_SIZE + 1;
4763        }
4764
4765#else
4766
4767        /* 32 bit */
4768        u64b dn = n;
4769        u64b dsize = size;
4770        u64b drsize = dn*dsize;
4771        size_t rsize = drsize;
4772
4773        if (drsize >> 32)
4774        {
4775                /* Overflow */
4776                return TOP_SIZE + 1;
4777        }
4778#endif
4779
4780        return rsize;
4781}
4782
4783void *PREFIX(calloc)(size_t n, size_t size)
4784{
4785        DECL_PROF_FUNC;
4786
4787        /* Init local data if required */
4788        atls *tl = get_tls();
4789
4790        size = safemul(n, size);
4791
4792        test_leak();
4793
4794        if (!tl) return zalloc_aux(size);
4795
4796        return zalloc(tl, size);
4797}
4798
4799#ifdef WINDOWS
4800void *PREFIX(_calloc_impl)(size_t n, size_t size, int *errno_tmp)
4801{
4802        DECL_PROF_FUNC;
4803
4804        void *ret;
4805        atls *tl;
4806
4807        int errno_orig;
4808        if (!errno_tmp) return PREFIX(calloc)(n, size);
4809
4810        /* Init local data if required */
4811        tl = get_tls();
4812
4813        size = safemul(n, size);
4814
4815        test_leak();
4816
4817        if (!tl) return zalloc_aux(size);
4818
4819        _get_errno(&errno_orig);
4820
4821        ret = zalloc(tl, safemul(n, size));
4822        _get_errno(errno_tmp);
4823        _set_errno(errno_orig);
4824
4825        return ret;
4826}
4827#endif
4828
4829static noinline void *realloc_aux(void *p, size_t size)
4830{
4831        atls *tl = init_tls();
4832
4833        /* Cannot allocate anything */
4834        if (!tl) return NULL;
4835
4836        return PREFIX(realloc)(p, size);
4837}
4838
4839static noinline void *realloc_aux2(void *p, size_t size, atls *tl)
4840{
4841        btree *b = CONTAINER(btree, data, p);
4842        size_t msize = b->s.size;
4843
4844        size_t old_size;
4845
4846#ifdef DEBUG_ALLOC
4847        if (un_used(b)) errx(1, "Realloc of unmalloced pointer %p\n", p);
4848#endif
4849
4850        /* Was a big block? */
4851        if (!msize)
4852        {
4853#ifndef WINDOWS
4854                size_t *np;
4855#endif
4856                size_t *ps = page_start(b);
4857
4858                size_t offset = (char *) b - (char *) ps;
4859
4860                /* Get old size */
4861                old_size = *ps;
4862
4863                /* Don't bother resizing shrinks that are more than half the allocated size */
4864                if ((old_size - offset <= size * 2) && (old_size - offset >= size)) return p;
4865
4866                /* Resize to new big block if possible */
4867                if (size >= BTMALLOC)
4868                {
4869                        /* Align */
4870                        size = page_align(size + offset + offsetof(btree, data));
4871
4872#ifndef WINDOWS
4873                        /* Use (nonportable) mremap */
4874                        np = mremap(ps, old_size, size, MREMAP_MAYMOVE);
4875
4876                        /* Success? */
4877                        if (np != MAP_FAILED)
4878                        {
4879                                /* Save new size */
4880                                *np = size;
4881
4882                                /* Return new pointer */
4883                                return shift(np, offset + offsetof(btree, data));
4884                        }
4885#endif
4886
4887                        if (size < old_size)
4888                        {
4889#ifndef WINDOWS
4890                                if (!munmap(shift(ps, size), old_size - size))
4891                                {
4892                                        /* Update size */
4893                                        *ps = size;
4894                                }
4895#else
4896                                /*
4897                                 * Say we no longer want the memory....
4898                                 * But it is still mapped into our address space taking up room!
4899                                 */
4900                                if (VirtualAlloc(shift(ps, size), old_size - size, MEM_RESET,
4901                                PAGE_NOACCESS))
4902                                {
4903                                        /* Update size */
4904                                        *ps = size;
4905                                }
4906#endif
4907
4908                                return p;
4909                        }
4910                }
4911        }
4912        else
4913        {
4914                mealloc *m;
4915
4916                /* Get old size */
4917                old_size = msize;
4918
4919                size = sep_align(size);
4920
4921                /* Don't bother resizing shrinks that are more than half the allocated size */
4922                if ((old_size <= size * 2) && (old_size >= size)) return p;
4923
4924                m = read_bs(b);
4925
4926                /* Local node? */
4927                if (m->tail == &tl->tail)
4928                {
4929                        btree *br;
4930
4931                        /* Easy case */
4932                        if (size <= msize) return split_node(tl, b, msize, size);
4933
4934                        /* Make sure adjacent nodes are in the btree */
4935                        clear_fast(tl);
4936
4937                        /* Medium or small size - try to merge */
4938                        br = shift(b, msize);
4939                        if (un_used(br))
4940                        {
4941                                if (br->s.bs_offset & FLG_SIZE8)
4942                                {
4943                                        small_remove(br);
4944
4945                                        /* Fixup sizes */
4946                                        b->s.size += 16;
4947                                        msize += 16;
4948
4949                                        br = shift(br, 16);
4950
4951                                        /* Set it as used */
4952                                        br->s.bs_offset &= ~FLG_LUNUSED;
4953                                }
4954                                else
4955                                {
4956                                        size_t rsize = br->s.size;
4957                                        if (rsize)
4958                                        {
4959                                                if (rsize > QS_MAX)
4960                                                {
4961                                                        btree_node_del(tl, br->parent, b_pindex(br));
4962                                                }
4963                                                else
4964                                                {
4965                                                        dlist_del(&br->list2);
4966                                                }
4967
4968                                                /* Fixup sizes */
4969                                                b->s.size += rsize;
4970                                                msize += rsize;
4971
4972                                                br = shift(br, rsize);
4973
4974                                                /* Set it as used */
4975                                                br->s.bs_offset &= ~FLG_LUNUSED;
4976                                        }
4977                                }
4978                        }
4979
4980                        /* Region fits? */
4981                        if (size <= msize) return split_node(tl, b, msize, size);
4982                }
4983                else
4984                {
4985                        /* We can only shrink a foreign node */
4986                        if (size <= msize)
4987                        {
4988                                /* Open coded split node */
4989                                btree *bm = shift(b, size);
4990
4991                                /* Update my size */
4992                                b->s.size = size;
4993
4994                                /* Create middle seperator */
4995                                set_sep(bm, old_size - size, b);
4996
4997                                /* Free the foreign excess */
4998                                prepend_queue((void *) &bm->data, tl, &m->tail);
4999
5000                                return p;
5001                        }
5002                }
5003        }
5004
5005        /* Failure */
5006        return NULL;
5007}
5008
5009void *PREFIX(realloc)(void *p, size_t size)
5010{
5011        DECL_PROF_FUNC;
5012
5013        void *np;
5014
5015        size_t old_size;
5016
5017        /* Init local data if required */
5018        atls *tl = get_tls();
5019
5020        int old_errno;
5021
5022        test_leak();
5023
5024        if (!tl) return realloc_aux(p, size);
5025
5026        test_all(tl);
5027
5028        /* realloc(p, 0) is the same as free(p) */
5029        if (!size)
5030        {
5031                PREFIX(free)(p);
5032
5033                return NULL;
5034        }
5035
5036        /* Relloc NULL is the same as malloc */
5037        if (!p) return PREFIX(malloc)(size);
5038
5039        /* Too large to allocate */
5040        if (size > TOP_SIZE) goto nomem;
5041
5042        if (!is_slab(p))
5043        {
5044                /* See if merging will work */
5045                np = realloc_aux2(p, size, tl);
5046
5047                if (np) return np;
5048        }
5049
5050        old_size = malloc_usable_size(p);
5051
5052#ifdef WINDOWS
5053        _get_errno(&old_errno);
5054#else
5055        /* Failure - have to do it manually */
5056        old_errno = errno;
5057#endif
5058
5059        np = PREFIX(malloc)(size);
5060        if (!np)
5061        {
5062                /* Is original allocation still okay? */
5063                if (size <= old_size)
5064                {
5065                        /* Don't set errno to be ENOMEM */
5066#ifdef WINDOWS
5067                        _set_errno(old_errno);
5068#else
5069                        errno = old_errno;
5070#endif
5071
5072                        /* Return old allocation */
5073                        return p;
5074                }
5075                goto nomem;
5076        }
5077
5078        /* Copy data */
5079        if (size > old_size) size = old_size;
5080        memcpy(np, p, size);
5081
5082        PREFIX(free)(p);
5083
5084        /* Done */
5085        return np;
5086
5087nomem:
5088        set_enomem();
5089        return NULL;
5090}
5091
5092#ifndef WINDOWS
5093static void unmap_range(void *x1, void *x2)
5094{
5095        if (x1 != x2)
5096        {
5097                munmap(x1, (char *) x2 - (char *) x1);
5098        }
5099}
5100#endif
5101
5102#ifdef DEBUG_ALLOC_SLOW
5103static void test_align(size_t align, void *p)
5104{
5105        uintptr_t x = (uintptr_t) p;
5106        if (align && (x & (align - 1))) errx(1, "Incorrect alignment of pointer\n");
5107}
5108#else
5109#define test_align(a, p) ((void) (sizeof(a) + sizeof(p)))
5110#endif
5111
5112static noinline void *memalign_aux(size_t align, size_t size)
5113{
5114        atls *tl = init_tls();
5115
5116        /* Cannot allocate anything! */
5117        if (!tl) return NULL;
5118
5119        return PREFIX(memalign)(align, size);
5120}
5121
5122#ifdef WINDOWS
5123static void *memalign_aux2(size_t align, size_t size, size_t rsize)
5124{
5125        size_t psize = page_align(rsize + PAGESIZE);
5126        size_t *ps;
5127
5128        (void) size;
5129
5130        if (align > PAGESIZE) goto nomem;
5131        if (rsize > TOP_SIZE) goto nomem;
5132
5133        ps = VirtualAlloc(NULL, rsize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
5134        if (ps == MAP_FAILED) goto nomem;
5135
5136        /* Small alignment */
5137        *ps = psize;
5138        ps = shift(ps, PAGESIZE);
5139
5140        test_align(align, ps);
5141
5142        return ps;
5143
5144nomem:
5145        set_enomem();
5146        return NULL;
5147}
5148#else
5149static void *memalign_aux2(size_t align, size_t size, size_t rsize)
5150{
5151        size_t pssize = page_align(size + PAGESIZE);
5152        size_t psize = page_align(rsize + PAGESIZE);
5153        size_t lsize;
5154        int flags = MAP_PRIVATE | MAP_ANONYMOUS;
5155
5156        size_t *lstart, *lend;
5157
5158        size_t *ps;
5159        void *p;
5160
5161        if (rsize > TOP_SIZE) goto nomem;
5162
5163        /*
5164         * Hack - large alignments require no reservation,
5165         * otherwise we run out of memory
5166         */
5167        if (align > size) flags |= MAP_NORESERVE;
5168
5169        ps = mmap(NULL, psize, PROT_READ | PROT_WRITE, flags, -1, 0);
5170
5171        /* Out of memory */
5172        if (ps == MAP_FAILED) goto nomem;
5173
5174        /* Small alignment */
5175        if (align <= PAGESIZE)
5176        {
5177                *ps = psize;
5178                p = shift(ps, PAGESIZE);
5179
5180                test_align(align, p);
5181
5182                return p;
5183        }
5184
5185        /* Large alignment */
5186        lstart = ps;
5187        lsize = (-(uintptr_t) ps) & (align - 1);
5188
5189        /* Already aligned - need to shift to get sep+size at beginning */
5190        if (!lsize)
5191        {
5192                ps = shift(ps, align - PAGESIZE);
5193
5194                /* Fragment at beginning to unmap */
5195                unmap_range(lstart, ps);
5196
5197                *ps = pssize;
5198                p = shift(ps, PAGESIZE);
5199
5200                test_align(align, p);
5201                return p;
5202        }
5203
5204        lend = shift(ps, rsize);
5205        ps = shift(ps, lsize - PAGESIZE);
5206
5207        /* Fragment at beginning to unmap */
5208        unmap_range(lstart, ps);
5209        *ps = pssize;
5210        p = shift(ps, PAGESIZE);
5211
5212        lstart = shift(p, pssize);
5213
5214        /* Fragment at end to unmap */
5215        unmap_range(lstart, lend);
5216
5217        test_align(align, p);
5218        return p;
5219
5220nomem:
5221        set_enomem();
5222        return NULL;
5223}
5224#endif
5225
5226void *PREFIX(memalign)(size_t align, size_t size)
5227{
5228        DECL_PROF_FUNC;
5229
5230        size_t rsize, lsize;
5231
5232        void *p;
5233
5234        btree *b;
5235
5236        atls *tl = get_tls();
5237
5238        test_leak();
5239
5240        /* Too large to allocate */
5241        if (size > TOP_SIZE) goto nomem;
5242
5243        if (align <= SEPSIZE) return PREFIX(malloc)(size);
5244
5245        if (!tl) return memalign_aux(align, size);
5246
5247        /* Try to cache-line align via slab special case */
5248        if ((size <= 64) && (align <= 64))
5249        {
5250                p = slab_alloc(tl, 64);
5251                if (p)
5252                {
5253                        /* Double-check alignment as slab_alloc may fall-back in low mem */
5254                        if (!(63 & (uintptr_t) p)) return p;
5255                        local_free(tl, p);
5256                }
5257        }
5258
5259        size = sep_align(size);
5260        rsize = sep_align(size + align);
5261
5262        /* Check for overflow */
5263        if ((rsize <= size) || (rsize <= align)) goto nomem;
5264
5265#ifdef WINDOWS
5266        /* Large allocations are special */
5267        if (rsize >= BTMALLOC)
5268        {
5269                return memalign_aux2(align, size, rsize);
5270        }
5271#else
5272        /* Large allocations are special */
5273        if (rsize >= BTMALLOC)
5274        {
5275                return memalign_aux2(align, size, rsize);
5276        }
5277#endif
5278
5279        while (1)
5280        {
5281                p = fast_alloc(tl, rsize);
5282                if (p) break;
5283
5284                if (rsize < QS_MAX)
5285                {
5286                        p = slow_alloc_aux(tl, rsize);
5287                        if (p) break;
5288
5289                        /* Clear fast lists */
5290                        clear_fast(tl);
5291
5292                        p = slow_alloc_aux(tl, rsize);
5293                        if (p) break;
5294                }
5295                else
5296                {
5297                        /* Clear fast lists */
5298                        clear_fast(tl);
5299                }
5300
5301                /* Try to alloc on the btree */
5302                b = btree_get(tl, rsize);
5303                if (b)
5304                {
5305                        p = split_node(tl, b, b->s.size, rsize);
5306                        break;
5307                }
5308
5309                /* Try to grab space from a dead thread */
5310                if (reap_dead(tl)) continue;
5311
5312                /* We need more space, so try to free memory. */
5313                if (scan_queue(tl, &tl->head, rsize)) continue;
5314
5315                /* Everything failed - fall back to large allocation */
5316                return memalign_aux2(align, size, rsize);
5317        }
5318
5319        lsize = (-(uintptr_t) p) & (align - 1);
5320
5321        b = CONTAINER(btree, data, p);
5322
5323#ifdef DEBUG_ALLOC_SLOW
5324        if (rsize > b->s.size) errx(1, "node received is too small\n");
5325#endif
5326
5327        /* get real size allocated */
5328        rsize = b->s.size;
5329
5330        /* Already aligned? */
5331        if (!lsize)
5332        {
5333                test_align(align, &b->data);
5334
5335                /* Split off part we need */
5336                return split_node(tl, b, rsize, size);
5337        }
5338
5339        b = split_node_rhs(tl, b, rsize, lsize);
5340        test_align(align, &b->data);
5341
5342        return split_node(tl, b, rsize - lsize, size);
5343
5344nomem:
5345        set_enomem();
5346        return NULL;
5347}
5348
5349int PREFIX(posix_memalign)(void **p, size_t align, size_t size)
5350{
5351        /* Make sure power of two and greater than sizeof(void *) */
5352#ifdef __x86_64__       
5353        if (align & ((align - 1) | 7))
5354        {
5355                *p = NULL;
5356                return EINVAL;
5357        }
5358#else
5359        if (align & ((align - 1) | 3))
5360        {
5361                *p = NULL;
5362                return EINVAL;
5363        }
5364#endif
5365
5366        *p = PREFIX(memalign)(align, size);
5367
5368        if (!*p) return ENOMEM;
5369
5370        return 0;
5371}
5372#if 0
5373void *valloc(size_t size)
5374{
5375        return PREFIX(memalign)(PAGESIZE, size);
5376}
5377
5378void *pvalloc(size_t size)
5379{
5380        return PREFIX(memalign)(PAGESIZE, page_align(size));
5381}
5382#endif
5383//#ifdef WINDOWS
5384#if 1
5385static
5386#endif
5387size_t malloc_usable_size(void *p)
5388{
5389        size_t offset;
5390        size_t *ps;
5391        size_t size;
5392
5393        DECL_PROF_FUNC;
5394
5395        btree *b = CONTAINER(btree, data, p);
5396
5397        /* Don't crash on a NULL pointer */
5398        if (!p) return 0;
5399
5400        /* Handle slab allocations */
5401        if (is_slab(p))
5402        {
5403                sbheader *sb = slab_start(p);
5404                return sb->size;
5405        }
5406
5407        size = b->s.size;
5408
5409        /* Small allocation */
5410        if (size) return size - PTRSIZE;
5411
5412        /* Large allocation */
5413        ps = page_start(b);
5414        offset = (uintptr_t) &b->data - (uintptr_t) ps;
5415
5416        return *ps - offset;
5417}
5418
5419#ifdef WINDOWS
5420#ifdef PREFIX
5421size_t PREFIX(_msize)(void *p)
5422#else /* !PREFIX */
5423__attribute__((dllimport)) size_t _msize(void *p)
5424#endif /* PREFIX */
5425{
5426        return malloc_usable_size(p);
5427}
5428#endif
5429
5430
5431#if 0
5432struct mallinfo mallinfo(void)
5433{
5434        atls *tl = get_tls();
5435        struct mallinfo mi = {0,0,0,0,0,0,0,0,0,0};
5436
5437        dlist *d;
5438        slist *s;
5439
5440        int i;
5441
5442        btree *b;
5443
5444        size_t size;
5445
5446        mi.arena = sbrk_size;
5447
5448        if (!tl)
5449        {
5450                tl = init_tls();
5451
5452                /* Cannot allocate anything, just return arena count */
5453                if (!tl) return mi;
5454        }
5455
5456        /* Scan slab */
5457        for (i = 0; i < NUM_SB; i++)
5458        {
5459                scan_list(&tl->slab[i], d)
5460                {
5461                        mi.smblks++;
5462                        mi.usmblks++;
5463                }
5464        }
5465
5466        scan_list(&tl->slab_full, d)
5467        {
5468                mi.smblks++;
5469                mi.usmblks++;
5470        }
5471
5472        if (tl->slab_chunk)
5473        {
5474                mi.fsmblks = 1 + tl->slab_chunk->count;
5475                mi.smblks += mi.fsmblks;
5476        }
5477
5478        /* Scan dlists */
5479        for (i = 1; i < NUM_QS; i++)
5480        {
5481                scan_list(&tl->qs[i], d)
5482                {
5483                        mi.ordblks++;
5484
5485                        b = CONTAINER(btree, list, d);
5486                        size = b->s.size - PTRSIZE;
5487                        mi.fordblks += size;
5488                }
5489        }
5490
5491        /* Add in results from small list */
5492        for (b = small_next((btree *) &tl->qs[0]); b != (btree *) &tl->qs[0]; b = small_next(b))
5493        {
5494                mi.ordblks++;
5495                mi.fordblks += 8;
5496        }
5497
5498        /* Scan fastlists */
5499        for (i = 0; i < NUM_FL; i++)
5500        {
5501                scan_slist(&tl->fl[i], s)
5502                {
5503                        mi.ordblks++;
5504
5505                        b = CONTAINER(btree, list, s);
5506                        size = b->s.size - PTRSIZE;
5507                        mi.fordblks += size;
5508                }
5509        }
5510
5511        /* Count memory blocks */
5512        scan_list(&tl->bl, d)
5513        {
5514                mi.hblks++;
5515        }
5516
5517        /* Count btree nodes */
5518        mi.hblkhd = count_btree(&tl->bheap);
5519
5520        /* Count btree space */
5521        mi.fordblks += count_btree_space(&tl->bheap);
5522
5523        /* Total allocated space (including overhead of seperators and atls) */
5524        mi.uordblks = tl->a_alloced - mi.fordblks + PAGESIZE;
5525
5526        /* Total easily callocable region */
5527        mi.keepcost = 0;
5528
5529        /* Done */
5530        return mi;
5531}
5532
5533int malloc_trim(size_t pad)
5534{
5535        atls *tl = get_tls();
5536
5537        /* Nothing allocated - do nothing */
5538        if (!tl) return 1;
5539
5540        /* Clear incoming frees */
5541        scan_queue(tl, &tl->head, 0);
5542
5543        /* Hack - ignore pad - and just free as much as possible */
5544        clear_fast(tl);
5545
5546        (void) pad;
5547
5548        /* Always return success */
5549        return 1;
5550}
5551
5552
5553
5554int mallopt(int param, int val)
5555{
5556        /* Ignore parameters */
5557        (void) param;
5558        (void) val;
5559
5560        /* Just return success - we don't have any parameters to modify */
5561        return 1;
5562}
5563
5564#endif
5565
5566#ifdef DEBUG_LEAK
5567static int btree_print(atls *tl, btree *b)
5568{
5569        int i;
5570        btree *bc;
5571
5572        int count = 1;
5573
5574        if (b_leaf(b))
5575        {
5576                leak_print(tl, "%u\n", b->s.size);
5577                return 0;
5578        }
5579
5580        leak_print(tl, "Btree: %p\n", (void *) b);
5581
5582        for (i = b_start(b); i; i = b_next(b, i))
5583        {
5584                bc = b_ptr(b, i);
5585                leak_print(tl, "link %p\n", (void *) bc);
5586                count += btree_print(tl, bc);
5587        }
5588
5589        return count;
5590}
5591#endif
5592
5593#if 0
5594// #ifndef WINDOWS
5595
5596static void mem_slab(void)
5597{
5598        int i;
5599        int count;
5600        dlist *d;
5601
5602        atls *tl = get_tls();
5603        if (!tl) return;
5604
5605        leak_print(tl, "Total Slab Virtual: %llu\n", (unsigned long long) sbrk_size);
5606
5607        for (i = 0; i < NUM_SB; i++)
5608        {
5609                if (dlist_empty(&tl->slab[i])) continue;
5610
5611                count = 0;
5612                scan_list(&tl->slab[i], d)
5613                {
5614                        count++;
5615                }
5616                leak_print(tl, "Partial slab %d used: %lld\n", i * 16, count * 65536ULL);
5617        }
5618
5619        if (!dlist_empty(&tl->slab_full))
5620        {
5621                count = 0;
5622                scan_list(&tl->slab_full, d)
5623                {
5624                        count++;
5625                }
5626                leak_print(tl, "Full slab used: %lld\n", count * 65536ULL);
5627        }
5628
5629        if (tl->slab_chunk)
5630        {
5631                leak_print(tl, "Local free slabs: %lld\n", (tl->slab_chunk->count + 1) * 65536LL);
5632        }
5633        else
5634        {
5635                leak_print(tl, "Local free slabs: 0\n");
5636        }
5637}
5638
5639#ifdef DEBUG_LEAK
5640static void mem_big(void)
5641{
5642        int i;
5643
5644        /* If vsnprintf allocates, we may have a problem... */
5645        mutex_lock(&l_lock);
5646
5647        for (i = 0; i < LEAK_MAX; i++)
5648        {
5649                if (big_leak[i].p)
5650                {
5651                        leak_print(get_tls(), "big block %p: %llu\n", big_leak[i].p, (unsigned long long) big_leak[i].size);
5652                }
5653        }
5654
5655        mutex_unlock(&l_lock);
5656}
5657#endif
5658
5659static void malloc_stats_aux(int show_nodes)
5660{
5661        atls *tl = get_tls();
5662
5663        dlist *d;
5664        btree *b;
5665
5666        size_t size;
5667        size_t tsize = 0;
5668        size_t asize = 0;
5669
5670        /* Nothing allocated - print nothing */
5671        if (!tl) return;
5672
5673        clear_fast(tl);
5674
5675        scan_list(&tl->bl, d)
5676        {
5677                mealloc *m = list_entry(mealloc, m_list, d);
5678
5679                size = big_block_size(m);
5680
5681                if (size)
5682                {
5683                        leak_print(tl, "Block: %p %llu\n", (void *) m, (unsigned long long) size);
5684                }
5685
5686                /* Scan seps for this block */
5687                for (b = &m->b;; b = shift(b, size))
5688                {
5689                        if (b->s.bs_offset & FLG_SIZE8)
5690                        {
5691                                size = 16;
5692                        }
5693                        else
5694                        {
5695                                size = b->s.size;
5696                        }
5697
5698                        if (!size) break;
5699
5700                        tsize += size;
5701
5702                        if (un_used(b))
5703                        {
5704                                if (show_nodes) leak_print(tl, "  %p\n", (void *) size);
5705                        }
5706                        else
5707                        {
5708                                if (show_nodes) leak_print(tl, "* %p\n", (void *) size);
5709                                asize += size;
5710                        }
5711                }
5712        }
5713
5714        leak_print(tl, "Total in btree %llu, total alloced %llu\n", (unsigned long long) tsize, (unsigned long long) asize);
5715
5716#ifdef DEBUG_LEAK
5717        if (show_nodes & 2)
5718        {
5719                int count = btree_print(tl, &tl->bheap);
5720
5721                leak_print(tl, "b_cnt = %d, b_hgt = %d, total = %d\n", tl->b_cnt, tl->b_hgt, count);
5722        }
5723
5724        mutex_lock(&h_lock);
5725        size = 0;
5726        scan_list(&h_list, d)
5727        {
5728                size++;
5729        }
5730        mutex_unlock(&h_lock);
5731        leak_print(tl, "%d threads\n", (int) size);
5732
5733        mem_big();
5734#endif
5735        mem_slab();
5736}
5737
5738void malloc_stats(void)
5739{
5740        malloc_stats_aux(0);
5741}
5742#endif
5743
5744static void **ialloc_fallback(atls *tl, size_t n, size_t *sizes, void **chunks, int clear)
5745{
5746        size_t i;
5747        void **out;
5748
5749        /* Get storage for pointers */
5750        if (!chunks)
5751        {
5752                out = local_alloc(tl, sep_align(sizeof(void *) * n));
5753                if (!out) return NULL;
5754        }
5755        else
5756        {
5757                out = chunks;
5758        }
5759
5760        /* Do it manually */
5761        if (clear)
5762        {
5763                for (i = 0; i < n; i++)
5764                {
5765                        out[i] = zalloc(tl, sizes[0]);
5766                        if (!out[i]) goto fail;
5767                }
5768        }
5769        else
5770        {
5771                for (i = 0; i < n; i++)
5772                {
5773                        out[i] = local_alloc(tl, sizes[i]);
5774                        if (!out[i]) goto fail;
5775                }
5776        }
5777
5778        return out;
5779
5780fail:
5781        for (n = 0; n < i; n++)
5782        {
5783                PREFIX(free)(out[i]);
5784        }
5785
5786        if (!chunks) PREFIX(free)(out);
5787
5788        return NULL;
5789}
5790
5791static void **ialloc(atls *tl, size_t n, size_t *sizes, void **chunks, int clear)
5792{
5793        size_t i;
5794
5795        size_t nsize;
5796        size_t total_size = 0;
5797
5798        void *p;
5799        btree *b, *br;
5800        unsigned offset;
5801
5802        void **out;
5803
5804        test_all(tl);
5805
5806        test_leak();
5807
5808        /* Zero sized array? */
5809        if (!n)
5810        {
5811                if (chunks) return chunks;
5812
5813                return PREFIX(malloc)(0);
5814        }
5815
5816        /* Get total size to allocate */
5817        if (clear)
5818        {
5819                total_size = safemul(sep_align(sizes[0]), n);
5820
5821                /* Overflow */
5822                if (total_size >= TOP_SIZE)
5823                {
5824                        set_enomem();
5825                        return NULL;
5826                }
5827        }
5828        else
5829        {
5830                for (i = 0; i < n; i++)
5831                {
5832                        nsize = sep_align(sizes[i]);
5833                        total_size += nsize;
5834
5835                        /* Overflow */
5836                        if (total_size < nsize)
5837                        {
5838                                set_enomem();
5839                                return NULL;
5840                        }
5841                }
5842        }
5843
5844        if (clear) tl->callocable = 0;
5845
5846        while (1)
5847        {
5848                p = fast_alloc(tl, total_size);
5849                if (p) break;
5850
5851                if (total_size < QS_MAX) p = slow_alloc(tl, total_size);
5852                if (p) break;
5853
5854                /* Too large to allocate normally */
5855                if (total_size >= BTMALLOC) return ialloc_fallback(tl, n, sizes, chunks, clear);
5856
5857                /* Clear fast lists */
5858                clear_fast(tl);
5859
5860                /* Try to alloc on the btree */
5861                b = btree_get(tl, total_size);
5862                if (b)
5863                {
5864                        p = split_node(tl, b, b->s.size, total_size);
5865                        break;
5866                }
5867
5868                /* Try to grab space from a dead thread */
5869                if (reap_dead(tl)) continue;
5870
5871                /* We need more space, so try to free memory. */
5872                if (scan_queue(tl, &tl->head, total_size)) continue;
5873
5874                /* Try to allocate a new block */
5875                p = block_alloc_aux(tl, total_size);
5876                if (p) break;
5877
5878                /* Everything failed - fall back to individual allocations */
5879                return ialloc_fallback(tl, n, sizes, chunks, clear);
5880        }
5881
5882        b = CONTAINER(btree, data, p);
5883
5884        /* Get real total size */
5885        total_size = b->s.size;
5886        offset = b->s.bs_offset & ~15;
5887
5888        /* Do we need to clear it? */
5889        if (clear && !tl->callocable) memset(p, 0, total_size - 8);
5890
5891        /* Get storage for pointers */
5892        if (!chunks)
5893        {
5894                out = local_alloc(tl, sep_align(sizeof(void *) * n));
5895
5896                if (!out)
5897                {
5898                        PREFIX(free)(p);
5899                        return NULL;
5900                }
5901        }
5902        else
5903        {
5904                out = chunks;
5905        }
5906
5907        for (i = 0; i < n; i++)
5908        {
5909                out[i] = p;
5910
5911                if (clear)
5912                {
5913                        nsize = sep_align(sizes[0]);
5914                }
5915                else
5916                {
5917                        nsize = sep_align(sizes[i]);
5918                }
5919                total_size -= nsize;
5920
5921                /* Update local size */
5922                b->s.size = nsize;
5923
5924                p = shift(p, nsize);
5925                br = CONTAINER(btree, data, p);
5926
5927                /* Create offset part of right seperator */
5928                offset += nsize;
5929                if (i != n - 1) br->s.bs_offset = offset;
5930
5931                b = br;
5932        }
5933
5934        /* Nothing left - then we are done */
5935        if (!total_size)
5936        {
5937                test_all(tl);
5938                return out;
5939        }
5940
5941        /* Resize last element to have the slack */
5942        p = out[n - 1];
5943        b = CONTAINER(btree, data, p);
5944
5945        b->s.size += total_size;
5946        check_sep(b);
5947
5948        /* How big is last allocation? */
5949        if (clear)
5950        {
5951                nsize = sep_align(sizes[0]);
5952        }
5953        else
5954        {
5955                nsize = sep_align(sizes[n - 1]);
5956        }
5957
5958        /* Split off excess if too much */
5959        split_node(tl, b, b->s.size, nsize);
5960
5961        test_all(tl);
5962        return out;
5963}
5964
5965#if 0
5966static noinline void **ialloc_aux(size_t n, size_t *sizes, void **chunks, int clear)
5967{
5968        atls *tl = init_tls();
5969        if (!tl) return NULL;
5970
5971        return ialloc(tl, n, sizes, chunks, clear);
5972}
5973
5974void **independent_calloc(size_t n, size_t size, void **chunks)
5975{
5976        atls *tl = get_tls();
5977
5978        if (!tl) return ialloc_aux(n, &size, chunks, 1);
5979
5980        return ialloc(tl, n, &size, chunks, 1);
5981}
5982
5983void **independent_comalloc(size_t n, size_t *sizes, void **chunks)
5984{
5985        atls *tl = get_tls();
5986
5987        if (!tl) return ialloc_aux(n, sizes, chunks, 0);
5988
5989        return ialloc(tl, n, sizes, chunks, 0);
5990}
5991#endif
5992//#ifndef WINDOWS
5993#if 0
5994void *malloc_get_state(void)
5995{
5996        abort();
5997
5998        return NULL;
5999}
6000
6001int malloc_set_state(void *p)
6002{
6003        (void) p;
6004        abort();
6005
6006        return 0;
6007}
6008#endif
6009
6010
6011#ifdef WINDOWS
6012#ifdef PREFIX
6013void *PREFIX(_expand)(void *p, size_t size)
6014#else /* PREFIX */
6015__attribute__((dllimport)) void *_expand(void *p, size_t size)
6016#endif /* PREFIX */
6017{
6018        DECL_PROF_FUNC;
6019
6020        atls *tl = get_tls();
6021
6022        /* paranoia */
6023        if (!p) return NULL;
6024
6025        /* Handle expansion into already allocated memory */
6026        if (malloc_usable_size(p) <= size) return p;
6027
6028        /* Don't handle slab allocations */
6029        if (is_slab(p)) return NULL;
6030
6031        /* Cannot expand a block created by someone else */
6032        if (!tl) goto nomem;
6033
6034        p = realloc_aux2(p, size, tl);
6035
6036        /* Did it work? */
6037        if (malloc_usable_size(p) >= size) return p;
6038
6039nomem:
6040        set_enomem();
6041        return NULL;
6042}
6043
6044/* Nolock functions call their normal functions */
6045void PREFIX(_free_nolock)(void *p)
6046{
6047        PREFIX(free)(p);
6048}
6049
6050void *PREFIX(_realloc_nolock)(void *p, size_t size)
6051{
6052        return PREFIX(realloc)(p, size);
6053}
6054
6055void *PREFIX(_calloc_nolock)(size_t n, size_t size)
6056{
6057        return PREFIX(calloc)(n, size);
6058}
6059
6060size_t PREFIX(_msize_nolock)(void *p)
6061{
6062        return malloc_usable_size(p);
6063}
6064
6065#endif
Note: See TracBrowser for help on using the repository browser.