xref: /haiku/src/system/libroot/posix/malloc/hoard2/threadheap.h (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
1 ///-*-C++-*-//////////////////////////////////////////////////////////////////
2 //
3 // Hoard: A Fast, Scalable, and Memory-Efficient Allocator
4 //        for Shared-Memory Multiprocessors
5 // Contact author: Emery Berger, http://www.cs.utexas.edu/users/emery
6 //
7 // Copyright (c) 1998-2000, The University of Texas at Austin.
8 //
9 // This library is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU Library General Public License as
11 // published by the Free Software Foundation, http://www.fsf.org.
12 //
13 // This library is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Library General Public License for more details.
17 //
18 //////////////////////////////////////////////////////////////////////////////
19 
20 #ifndef _THREADHEAP_H_
21 #define _THREADHEAP_H_
22 
23 #include "config.h"
24 
25 #include <string.h>
26 
27 #include "heap.h"
28 
29 namespace BPrivate {
30 
31 class processHeap;		 // forward declaration
32 
33 //
34 // We use one threadHeap for each thread (processor).
35 //
36 
37 class threadHeap : public hoardHeap {
38 	public:
39 		threadHeap(void);
40 
41 		// Memory allocation routines.
42 		void *malloc(const size_t sz);
43 		inline void *memalign(size_t alignment, size_t sz);
44 
45 		// Find out how large an allocated object is.
46 		inline static size_t objectSize(void *ptr);
47 
48 		// Set our process heap.
49 		inline void setpHeap(processHeap *p);
50 
51 	private:
52 		// Prevent copying and assignment.
53 		threadHeap(const threadHeap &);
54 		const threadHeap &operator=(const threadHeap &);
55 
56 		// Our process heap.
57 		processHeap *_pHeap;
58 
59 		// We insert a cache pad here to avoid false sharing (the
60 		// processHeap holds an array of threadHeaps, and we don't want
61 		// these to share any cache lines).
62 		double _pad[CACHE_LINE / sizeof(double)];
63 };
64 
65 
66 void *
67 threadHeap::memalign(size_t alignment, size_t size)
68 {
69 	// Calculate the amount of space we need
70 	// to satisfy the alignment requirements.
71 
72 	size_t newSize;
73 
74 	// If the alignment is less than the required alignment,
75 	// just call malloc.
76 	if (alignment <= ALIGNMENT)
77 		return this->malloc(size);
78 
79 	if (alignment < sizeof(block))
80 		alignment = sizeof(block);
81 
82 	// Alignment must be a power of two!
83 	assert((alignment & (alignment - 1)) == 0);
84 
85 	// Leave enough room to align the block within the malloced space.
86 	newSize = size + sizeof(block) + alignment;
87 
88 	// Now malloc the space up with a little extra (we'll put the block
89 	// pointer in right behind the allocated space).
90 
91 	void *ptr = this->malloc(newSize);
92 	if ((((unsigned long) ptr) & -((long) alignment)) == 0) {
93 		// ptr is already aligned, so return it.
94 		assert(((unsigned long) ptr % alignment) == 0);
95 		return ptr;
96 	} else {
97 		// Align ptr.
98 		char *newptr = (char *)(((unsigned long)ptr + alignment - 1) & -((long)alignment));
99 
100 		// If there's not enough room for the block header, skip to the
101 		// next aligned space within the block..
102 		if ((unsigned long)newptr - (unsigned long)ptr < sizeof(block))
103 			newptr += alignment;
104 
105 		assert(((unsigned long)newptr % alignment) == 0);
106 
107 		// Copy the block from the start of the allocated memory.
108 		block *b = ((block *)ptr - 1);
109 
110 		assert(b->isValid());
111 		assert(b->getSuperblock()->isValid());
112 
113 		// Make sure there's enough room for the block header.
114 		assert(((unsigned long)newptr - (unsigned long)ptr) >=
115 		       sizeof(block));
116 
117 		block *p = ((block *)newptr - 1);
118 
119 		// Make sure there's enough room allocated for size bytes.
120 		assert(((unsigned long)p - sizeof(block)) >= (unsigned long)b);
121 
122 		if (p != b) {
123 			assert((unsigned long)newptr > (unsigned long)ptr);
124 			// Copy the block header.
125 			*p = *b;
126 			assert(p->isValid());
127 			assert(p->getSuperblock()->isValid());
128 
129 			// Set the next pointer to point to b with the 1 bit set.
130 			// When this block is freed, it will be treated specially.
131 			p->setNext((block *)((unsigned long)b | 1));
132 		} else
133 			assert(ptr != newptr);
134 
135 		assert(((unsigned long)ptr + newSize) >=
136 		       ((unsigned long)newptr + size));
137 		return newptr;
138 	}
139 }
140 
141 
142 size_t
143 threadHeap::objectSize(void *ptr)
144 {
145 	// Find the superblock pointer.
146 	block *b = ((block *)ptr - 1);
147 	assert(b->isValid());
148 	superblock *sb = b->getSuperblock();
149 	assert(sb);
150 
151 	// Return the size.
152 	return sizeFromClass(sb->getBlockSizeClass());
153 }
154 
155 
156 void threadHeap::setpHeap(processHeap *p)
157 {
158 	_pHeap = p;
159 }
160 
161 }	// namespace BPrivate
162 
163 #endif				 // _THREADHEAP_H_
164