1 using System;
2 using System.Collections;
3 using cmsx.util;
4
5 namespace cmsx.kernel
6 {
7 public const int blockSize = 4096;
8 public const int numBitsInBitmapBlock = blockSize * 8;
9 public const int numULongsInBitmapBlock = blockSize / 8;
10 public const int numBlockNumbersInBlock = blockSize / 4;
11 public const int invalidBlockNumber = 0;
12 public const int maxCachedBlocks = 1024;
13 public const int nameMax = 252;
14
15 public class BlockKey
16 {
17 public nothrow BlockKey() : blockNumber(-1), fsNumber(-1)
18 {
19 }
20 public nothrow BlockKey(int blockNumber_, int fsNumber_) : blockNumber(blockNumber_), fsNumber(fsNumber_)
21 {
22 }
23 public nothrow string ToString() const
24 {
25 string s;
26 s.Append("block.").Append(ToString(fsNumber)).Append('.').Append(ToString(blockNumber));
27 return s;
28 }
29 public int blockNumber;
30 public int fsNumber;
31 }
32
33 public nothrow bool operator==(const BlockKey& left, const BlockKey& right)
34 {
35 return left.blockNumber == right.blockNumber && left.fsNumber == right.fsNumber;
36 }
37
38 public class BlockKeyHash : UnaryFun<BlockKey, ulong>
39 {
40 public inline nothrow ulong operator()(const BlockKey& key) const
41 {
42 return cast<ulong>(1099511628211 * key.fsNumber + key.blockNumber);
43 }
44 }
45
46 public class Block
47 {
48 public enum Flags : byte
49 {
50 none = 0u,
51 locked = 1u << 0u,
52 valid = 1u << 1u,
53 dirty = 1u << 2u,
54 old = 1u << 3u
55 }
56 public nothrow string BlockFlagStr(Flags flags)
57 {
58 string s = "flags";
59 if ((flags & Flags.locked) != Flags.none)
60 {
61 s.Append(".locked");
62 }
63 if ((flags & Flags.valid) != Flags.none)
64 {
65 s.Append(".valid");
66 }
67 if ((flags & Flags.dirty) != Flags.none)
68 {
69 s.Append(".dirty");
70 }
71 if ((flags & Flags.old) != Flags.none)
72 {
73 s.Append(".old");
74 }
75 return s;
76 }
77 public nothrow Block(const BlockKey& key_, BlockManager* manager_, BlockCache* cache_) : key(key_), manager(manager_), cache(cache_), flags(Flags.none), iterator(), owner(null)
78 {
79 }
80 public inline nothrow cmsx.kernel.Process* Owner() const
81 {
82 return owner;
83 }
84 public inline nothrow void SetOwner(cmsx.kernel.Process* owner_)
85 {
86 owner = owner_;
87 }
88 public inline nothrow void ResetOwner()
89 {
90 owner = null;
91 }
92 public virtual default ~Block();
93 public nothrow string ToString() const
94 {
95 string s;
96 s.Append(key.ToString());
97 s.Append('.').Append(BlockFlagStr(flags));
98 return s;
99 }
100 public nothrow void Read(MemoryReader& reader)
101 {
102 for (int i = 0; i < blockSize; ++i;)
103 {
104 data[i] = reader.ReadByte();
105 }
106 }
107 public nothrow void Write(MemoryWriter& writer)
108 {
109 for (int i = 0; i < blockSize; ++i;)
110 {
111 writer.Write(data[i]);
112 }
113 ResetFlag(Flags.dirty);
114 }
115 public nothrow void Clear()
116 {
117 for (int i = 0; i < data.Length(); ++i;)
118 {
119 data[i] = 0u;
120 }
121 SetFlag(Flags.dirty);
122 }
123 public inline nothrow bool GetFlag(Flags flag) const
124 {
125 return (flags & flag) != Flags.none;
126 }
127 public inline nothrow void SetFlag(Flags flag)
128 {
129 flags = cast<Flags>(flags | flag);
130 if (flag == Flags.dirty)
131 {
132 cache->AddDirtyBlock(this);
133 }
134 }
135 public inline nothrow void ResetFlag(Flags flag)
136 {
137 flags = cast<Flags>(flags & ~flag);
138 }
139 public inline nothrow void ResetFlags()
140 {
141 flags = Flags.none;
142 }
143 public inline nothrow BlockKey& Key() const
144 {
145 return key;
146 }
147 public nothrow void SetKey(const BlockKey& key_)
148 {
149 key = key_;
150 }
151 public void AddWaitingProcess(cmsx.kernel.Process* process)
152 {
153 waitingProcesses.Add(process);
154 }
155 public nothrow List<cmsx.kernel.Process*> GetWaitingProcesses()
156 {
157 List<cmsx.kernel.Process*> processes;
158 Swap(processes, waitingProcesses);
159 return processes;
160 }
161 public nothrow LinkedList<Block*>.Iterator GetIterator() const
162 {
163 return iterator;
164 }
165 public nothrow void SetIterator(LinkedList<Block*>.Iterator iterator_)
166 {
167 iterator = iterator_;
168 }
169 public inline nothrow BlockManager* Manager()
170 {
171 return manager;
172 }
173 public byte[blockSize] data;
174 private BlockKey key;
175 private BlockManager* manager;
176 private BlockCache* cache;
177 private Flags flags;
178 private List<cmsx.kernel.Process*> waitingProcesses;
179 private LinkedList<Block*>.Iterator iterator;
180 private cmsx.kernel.Process* owner;
181 }
182
183 public class SuperBlock : Block
184 {
185 public nothrow SuperBlock(BlockManager* manager_, BlockCache* cache_) : base(BlockKey(0, 0), manager_, cache_)
186 {
187 }
188 public nothrow int GetFirstINodeBitmapBlockNumber() const
189 {
190 MemoryReader reader(&data[firstINodeBitmapBlockNumberOffset], 4);
191 return reader.ReadInt();
192 }
193 public nothrow void SetFirstINodeBitmapBlockNumber(int firstINodeBitmapBlockNumber)
194 {
195 MemoryWriter writer(&data[firstINodeBitmapBlockNumberOffset], 4);
196 writer.Write(firstINodeBitmapBlockNumber);
197 SetFlag(Block.Flags.dirty);
198 }
199 public nothrow int GetNumINodeBitmapBlocks() const
200 {
201 MemoryReader reader(&data[numINodeBitmapBlocksOffset], 4);
202 return reader.ReadInt();
203 }
204 public nothrow void SetNumINodeBitmapBlocks(int numINodeBitmapBlocks)
205 {
206 MemoryWriter writer(&data[numINodeBitmapBlocksOffset], 4);
207 writer.Write(numINodeBitmapBlocks);
208 SetFlag(Block.Flags.dirty);
209 }
210 public nothrow int GetFirstBlockBitmapBlockNumber() const
211 {
212 MemoryReader reader(&data[firstBlockBitmapBlockNumberOffset], 4);
213 return reader.ReadInt();
214 }
215 public nothrow void SetFirstBlockBitmapBlockNumber(int firstBlockBitmapBlockNumber)
216 {
217 MemoryWriter writer(&data[firstBlockBitmapBlockNumberOffset], 4);
218 writer.Write(firstBlockBitmapBlockNumber);
219 SetFlag(Block.Flags.dirty);
220 }
221 public nothrow int GetNumBlockBitmapBlocks() const
222 {
223 MemoryReader reader(&data[numBlockBitmapBlocksOffset], 4);
224 return reader.ReadInt();
225 }
226 public nothrow void SetNumBlockBitmapBlocks(int numBlockBitmapBlocks)
227 {
228 MemoryWriter writer(&data[numBlockBitmapBlocksOffset], 4);
229 writer.Write(numBlockBitmapBlocks);
230 SetFlag(Block.Flags.dirty);
231 }
232 public nothrow int GetFirstINodeBlockNumber() const
233 {
234 MemoryReader reader(&data[firstINodeBlockNumberOffset], 4);
235 return reader.ReadInt();
236 }
237 public nothrow void SetFirstINodeBlockNumber(int firstINodeBlockNumber)
238 {
239 MemoryWriter writer(&data[firstINodeBlockNumberOffset], 4);
240 writer.Write(firstINodeBlockNumber);
241 SetFlag(Block.Flags.dirty);
242 }
243 public nothrow int GetNumINodeBlocks() const
244 {
245 MemoryReader reader(&data[numINodeBlocksOffset], 4);
246 return reader.ReadInt();
247 }
248 public nothrow void SetNumINodeBlocks(int numINodeBlocks)
249 {
250 MemoryWriter writer(&data[numINodeBlocksOffset], 4);
251 writer.Write(numINodeBlocks);
252 SetFlag(Block.Flags.dirty);
253 }
254 public nothrow int GetFirstDataBlockNumber() const
255 {
256 MemoryReader reader(&data[firstDataBlockNumberOffset], 4);
257 return reader.ReadInt();
258 }
259 public nothrow void SetFirstDataBlockNumber(int firstDataBlockNumber)
260 {
261 MemoryWriter writer(&data[firstDataBlockNumberOffset], 4);
262 writer.Write(firstDataBlockNumber);
263 SetFlag(Block.Flags.dirty);
264 }
265 public nothrow int GetRootDirINodeNumber() const
266 {
267 MemoryReader reader(&data[rootDirINodeNumberOffset], 4);
268 return reader.ReadInt();
269 }
270 public nothrow void SetRootDirINodeNumber(int rootDirINodeNumber)
271 {
272 MemoryWriter writer(&data[rootDirINodeNumberOffset], 4);
273 writer.Write(rootDirINodeNumber);
274 SetFlag(Block.Flags.dirty);
275 }
276 public nothrow int GetLastBlockNumber() const
277 {
278 MemoryReader reader(&data[lastBlockNumberOffset], 4);
279 return reader.ReadInt();
280 }
281 public nothrow void SetLastBlockNumber(int lastBlockNumber)
282 {
283 MemoryWriter writer(&data[lastBlockNumberOffset], 4);
284 writer.Write(lastBlockNumber);
285 SetFlag(Block.Flags.dirty);
286 }
287 private const int firstINodeBitmapBlockNumberOffset = 4 * 0;
288 private const int numINodeBitmapBlocksOffset = 4 * 1;
289 private const int firstBlockBitmapBlockNumberOffset = 4 * 2;
290 private const int numBlockBitmapBlocksOffset = 4 * 3;
291 private const int firstINodeBlockNumberOffset = 4 * 4;
292 private const int numINodeBlocksOffset = 4 * 5;
293 private const int firstDataBlockNumberOffset = 4 * 6;
294 private const int rootDirINodeNumberOffset = 4 * 7;
295 private const int lastBlockNumberOffset = 4 * 8;
296 }
297
298 public class BitmapBlock : Block
299 {
300 public nothrow BitmapBlock(BlockManager* manager_, BlockCache* cache_) : base(BlockKey(0, 0), manager_, cache_)
301 {
302 }
303 public nothrow ulong GetBitChunk(int i) const
304 {
305 MemoryReader reader(&data[i * 8], 8);
306 return reader.ReadULong();
307 }
308 public nothrow void SetBitChunk(int i, ulong chunk)
309 {
310 MemoryWriter writer(&data[i * 8], 8);
311 writer.Write(chunk);
312 SetFlag(Flags.dirty);
313 }
314 public nothrow int GetFirstZeroBitIndex() const
315 {
316 long n = numULongsInBitmapBlock;
317 for (long i = 0; i < n; ++i;)
318 {
319 ulong chunk = GetBitChunk(cast<int>(i));
320 if (chunk != MaxValue<ulong>())
321 {
322 for (byte j = 0u; j < 64u; ++j;)
323 {
324 if ((chunk & (cast<ulong>(1u) << j)) == 0u)
325 {
326 return cast<int>(i) * 64 + j;
327 }
328 }
329 }
330 }
331 return -1;
332 }
333 public nothrow bool GetBit(int index) const
334 {
335 int i = index / 64;
336 byte j = cast<byte>(index % 64);
337 ulong chunk = GetBitChunk(i);
338 return (chunk & (cast<ulong>(1u) << j)) != 0u;
339 }
340 public nothrow void SetBit(int index)
341 {
342 int i = index / 64;
343 byte j = cast<byte>(index % 64);
344 ulong chunk = GetBitChunk(i);
345 chunk = chunk | (cast<ulong>(1u) << j);
346 SetBitChunk(i, chunk);
347 SetFlag(Flags.dirty);
348 }
349 public nothrow void ResetBit(int index)
350 {
351 int i = index / 64;
352 byte j = cast<byte>(index % 64);
353 ulong chunk = GetBitChunk(i);
354 chunk = chunk & ~(cast<ulong>(1u) << j);
355 SetBitChunk(i, chunk);
356 SetFlag(Flags.dirty);
357 }
358 }
359
360 public class BlockNumberBlock : Block
361 {
362 public nothrow BlockNumberBlock(BlockManager* manager_, BlockCache* cache_) : base(BlockKey(0, 0), manager_, cache_)
363 {
364 }
365 public nothrow int GetBlockNumber(int index) const
366 {
367 #assert(index >= 0 && index < numBlockNumbersInBlock);
368 MemoryReader reader(&data[index * 4], 4);
369 return reader.ReadInt();
370 }
371 public nothrow void SetBlockNumber(int index, int blockNumber)
372 {
373 #assert(index >= 0 && index < numBlockNumbersInBlock);
374 MemoryWriter writer(&data[index * 4], 4);
375 writer.Write(blockNumber);
376 SetFlag(Block.Flags.dirty);
377 }
378 }
379
380 public class FileBlock : Block
381 {
382 public nothrow FileBlock(BlockManager* manager_, BlockCache* cache_) : base(BlockKey(0, 0), manager_, cache_)
383 {
384 }
385 public inline nothrow byte GetByte(long index) const
386 {
387 return data[index];
388 }
389 public inline nothrow void SetByte(long index, byte x)
390 {
391 data[index] = x;
392 }
393 }
394
395 public class DirectoryEntry
396 {
397 public nothrow DirectoryEntry(int inodeNumber_, const string& name_) : inodeNumber(inodeNumber_), name(name_)
398 {
399 #assert(name.Length() < nameMax);
400 }
401 public void Read(MemoryReader& reader)
402 {
403 inodeNumber = reader.ReadInt();
404 name = reader.ReadString();
405 }
406 public void Write(MemoryWriter& writer)
407 {
408 writer.Write(inodeNumber);
409 writer.Write(name);
410 }
411 public int inodeNumber;
412 public string name;
413 }
414
415 public const int directoryEntrySize = 4 + nameMax;
416 public const int numDirectoryEntriesInBlock = blockSize / directoryEntrySize;
417
418 public class DirectorySlot
419 {
420 public nothrow DirectorySlot() : blockNumber(invalidBlockNumber), fsNumber(0), offset(-1)
421 {
422 }
423 public nothrow DirectorySlot(int blockNumber_, int fsNumber_, long offset_) : blockNumber(blockNumber_), fsNumber(fsNumber_), offset(offset_)
424 {
425 }
426 public int blockNumber;
427 public int fsNumber;
428 public long offset;
429 }
430
431 public class DirectoryBlock : Block
432 {
433 public nothrow DirectoryBlock(BlockManager* manager_, BlockCache* cache_) : base(BlockKey(0, 0), manager_, cache_)
434 {
435 }
436 public nothrow DirectoryEntry GetDirectoryEntry(int index) const
437 {
438 #assert(index >= 0 && index < numDirectoryEntriesInBlock);
439 DirectoryEntry entry;
440 MemoryReader reader(&data[index * directoryEntrySize], directoryEntrySize);
441 entry.Read(reader);
442 return entry;
443 }
444 public nothrow void SetDirectoryEntry(int index, const DirectoryEntry& entry)
445 {
446 #assert(index >= 0 && index < numDirectoryEntriesInBlock);
447 MemoryWriter writer(&data[index * directoryEntrySize], directoryEntrySize);
448 entry.Write(writer);
449 }
450 }
451
452 public const int inodeSize = 128;
453 public const int numINodesInBlock = blockSize / inodeSize;
454
455 public class INodeBlock : Block
456 {
457 public nothrow INodeBlock(BlockManager* manager_, BlockCache* cache_) : base(BlockKey(0, 0), manager_, cache_)
458 {
459 }
460 public nothrow INode GetINode(int index) const
461 {
462 #assert(index >= 0 && index < numINodesInBlock);
463 INode inode;
464 MemoryReader reader(&data[index * inodeSize], inodeSize);
465 inode.Read(reader);
466 return inode;
467 }
468 public nothrow void SetINode(int index, const INode& inode) const
469 {
470 #assert(index >= 0 && index < numINodesInBlock);
471 MemoryWriter writer(&data[index * inodeSize], inodeSize);
472 inode.Write(writer);
473 }
474 }
475
476 public class BlockPutter
477 {
478 public nothrow BlockPutter() : block(null)
479 {
480 }
481 public nothrow BlockPutter(Block* block_) : block(block_)
482 {
483 }
484 public nothrow void Reset(Block* block_)
485 {
486 if (block != block_)
487 {
488 if (block != null)
489 {
490 block->Manager()->PutBlock(block);
491 }
492 block = block_;
493 }
494 }
495 public nothrow Block* Release()
496 {
497 Block* result = block;
498 block = null;
499 return result;
500 }
501 public ~BlockPutter()
502 {
503 if (block != null)
504 {
505 block->Manager()->PutBlock(block);
506 }
507 }
508 private Block* block;
509 }
510 }