1
/*
2
 * $Id$
3
 *
4
 * Copyright (C) 2003-2009 JNode.org
5
 *
6
 * This library is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation; either version 2.1 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful, but 
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
14
 * License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with this library; If not, write to the Free Software Foundation, Inc., 
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
 */
20
 
21
package org.jnode.vm;
22
23
import org.jnode.annotation.MagicPermission;
24
import org.jnode.annotation.Uninterruptible;
25
import org.jnode.vm.scheduler.VmThread;
26
import org.vmmagic.unboxed.Address;
27
import org.vmmagic.unboxed.Extent;
28
import org.vmmagic.unboxed.Word;
29
30
/**
31
 * A bitmap that stores its bits in a raw memory region.
32
 *
33
 * @author Ewout Prangsma (epr@users.sourceforge.net)
34
 */
35
@MagicPermission
36
@Uninterruptible
37
public class AllocationBitmap {
38
39
    /**
40
     * Inclusive start address of the bitmap memory region
41
     */
42
    private Address start = Address.zero();
43
44
    /**
45
     * Exclusive end address of the bitmap memory region
46
     */
47
    private Address end = Address.zero();
48
49
    /**
50
     * Number of bits in the bitmap
51
     */
52
    private Word bits;
53
54
    /**
55
     * Lock address for access to the bits in this bitmap
56
     */
57
    private Address lock;
58
59
    /**
60
     * Address of bits data
61
     */
62
    private Address bitmap;
63
64
    /**
65
     * Size of the bitmap memory region
66
     */
67
    private Extent size;
68
69
    /**
70
     * Number of allocated bits
71
     */
72
    private Word allocatedBits = Word.zero();
73
74
    /**
75
     * Number of next allocatable bit
76
     */
77
    private Word nextBitNr = Word.zero();
78
79
    /**
80
     * Initialize this instance.
81
     */
82
    public AllocationBitmap() {
83
        // Nothing here
84
    }
85
86
    /**
87
     * Initialize this bitmap.
88
     *
89
     * @param start
90
     * @param bits
91
     */
92
    public final void initialize(Address start, Word bits) {
93
        // Size of the lock (we only use an int)
94
        final Extent lockSize = Extent.fromIntZeroExtend(Vm.getArch()
95
            .getReferenceSize());
96
97
        // Create a lock and actual bitmap
98
        final Extent rawBitmapSize = bits.rshl(3).toExtent();
99
        final Extent bitmapSize = rawBitmapSize.toWord().add(lockSize)
100
            .toExtent();
101
102
        this.start = start;
103
        this.end = start.add(bitmapSize);
104
        this.bits = bits;
105
        this.lock = start;
106
        this.bitmap = start.add(lockSize);
107
        this.size = bitmapSize;
108
        this.allocatedBits = Word.zero();
109
        this.nextBitNr = Word.zero();
110
111
        // Clear the total bitmap + lock region
112
        Unsafe.clear(start, bitmapSize);
113
    }
114
115
    /**
116
     * Gets the size of the memory region occupied by this bitmap.
117
     *
118
     * @return the size as an Extent.
119
     */
120
    public final Extent getSize() {
121
        return size;
122
    }
123
124
    /**
125
     * Allocate a new series of bits.
126
     *
127
     * @param noBits
128
     * @return The bit index of the start of the bit series, or Word.max() when
129
     *         not enough free bits are available.
130
     */
131
    public final Word allocateBits(Word noBits) {
132
        lock();
133
        try {
134
            // Find a large enough series of bits
135
            final Word nr = findFreeBits(noBits);
136
            if (nr.isMax()) {
137
                return nr;
138
            }
139
            // Mark all blocks as in use
140
            for (Word i = Word.zero(); i.LT(noBits); i = i.add(1)) {
141
                set(nr.add(i), true);
142
            }
143
            // Return the address of block "nr".
144
            allocatedBits = allocatedBits.add(noBits);
145
            nextBitNr = nr.add(noBits);
146
            return nr;
147
        } finally {
148
            unlock();
149
        }
150
    }
151
152
    /**
153
     * Free a previously allocated series of bits.
154
     *
155
     * @param bit    The bit number as returned by allocateBits.
156
     * @param noBits The size of the bit series as given to allocateBits.
157
     */
158
    public final void freeBits(Word bit, Word noBits) {
159
        lock();
160
        try {
161
            // Mark all blocks as free
162
            for (Word i = Word.zero(); i.LT(noBits); i = i.add(1)) {
163
                set(bit.add(i), false);
164
            }
165
            allocatedBits = allocatedBits.sub(noBits);
166
            if (bit.LT(nextBitNr)) {
167
                nextBitNr = bit;
168
            }
169
        } finally {
170
            unlock();
171
        }
172
    }
173
174
    /**
175
     * Mark a series of bits as set.
176
     *
177
     * @param bit    The start of the series
178
     * @param noBits The number of bits in the series
179
     */
180
    public final void setBits(Word bit, Word noBits) {
181
        if (bit.add(noBits).GT(this.bits)) {
182
            throw new IndexOutOfBoundsException();
183
        }
184
        lock();
185
        try {
186
            // Mark all bits as set
187
            for (Word i = Word.zero(); i.LT(noBits); i = i.add(1)) {
188
                set(bit.add(i), true);
189
            }
190
            allocatedBits = allocatedBits.add(noBits);
191
        } finally {
192
            unlock();
193
        }
194
    }
195
196
    /**
197
     * Find the first free bits that is following by freeBits-1 free bits.
198
     *
199
     * @param freeBits
200
     * @return The bit number of the first block, or Word.max() if not found.
201
     */
202
    private final Word findFreeBits(Word freeBits) {
203
        final Word max = bits;
204
        Word nr = nextBitNr;
205
        while (nr.LT(max)) {
206
            boolean inUse = false;
207
            Word i;
208
            for (i = Word.zero(); i.LT(freeBits) && (!inUse); i = i.add(1)) {
209
                inUse |= isSet(nr.add(i));
210
            }
211
            if (!inUse) {
212
                // We found it
213
                return nr;
214
            } else {
215
                // Unsafe.debug("nr"); Unsafe.debug(nr);
216
                // Unsafe.debug("i"); Unsafe.debug(i);
217
                // We came across an used block
218
                nr = nr.add(i).add(1);
219
            }
220
        }
221
        // Unsafe.debug("ret -1"); Unsafe.die();
222
        return Word.max();
223
    }
224
225
    /**
226
     * Test if a given bit is set.
227
     *
228
     * @param bit the bit to be tested
229
     * @return {@link true} if the bit is set, {@code false} otherwise.
230
     */
231
    private final boolean isSet(Word bit) {
232
        final Word offset = bit.rshl(3); // we still need a byte offset
233
        final int mask = (1 << bit.and(Word.fromIntZeroExtend(7)).toInt());
234
        final Address ptr = bitmap.add(offset);
235
        final int v = ptr.loadByte() & 0xFF;
236
        return ((v & mask) == mask);
237
    }
238
239
    /**
240
     * Set/Reset a given bit.
241
     *
242
     * @param bit the bit to be set or reset
243
     * @param value the new value for the bit
244
     */
245
    private final void set(Word bit, boolean value) {
246
        final Word offset = bit.rshl(3); // we still need a byte offset
247
        final int mask = (1 << bit.and(Word.fromIntZeroExtend(7)).toInt());
248
        // final int mask = (1 << blockNr);
249
        final Address ptr = bitmap.add(offset);
250
        int v = ptr.loadByte();
251
        if (value) {
252
            v |= mask;
253
        } else {
254
            v &= ~mask;
255
        }
256
        ptr.store((byte) v);
257
    }
258
259
    /**
260
     * Claim an exclusive access lock the Bitmap data structures. This is done without using java
261
     * monitorenter/exit instructions, since they may need a memory allocation.
262
     */
263
    private final void lock() {
264
        while (!lock.attempt(0, 1)) {
265
            // Unsafe.debug(lock.loadInt());
266
            VmThread.yield();
267
        }
268
    }
269
270
    /**
271
     * Release the exclusive access lock to the Bitmap data structures.  Note that no attempt
272
     * is made to check that the lock is owned by the current thread.
273
     */
274
    private final void unlock() {
275
        lock.store((int) 0);
276
    }
277
}