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
29namespace BPrivate {
30
31class processHeap;		 // forward declaration
32
33//
34// We use one threadHeap for each thread (processor).
35//
36
37class 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
66void *
67threadHeap::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
142size_t
143threadHeap::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
156void threadHeap::setpHeap(processHeap *p)
157{
158	_pHeap = p;
159}
160
161}	// namespace BPrivate
162
163#endif				 // _THREADHEAP_H_
164