Gide Nwawudu wrote:
On Tue, 27 Jan 2009 22:48:33 -0800, Charles Hixson
<[email protected]> wrote:
Main routine:
void main()
{
try
{ BlockFile bf;
bf = new BlockFile ("test.bf", 4096);
writefln ("before close");
bf.close;
bf = null;
writefln ("after close");
BlockFile cf = new BlockFile ("test.bf", 4096);
writefln ("after second open");
}
catch (Exception e)
{ writefln ("Caught Exception ", e); }
}
Results in:
Exiting BlockFile::this
before close
after close
Exiting BlockFile::this
after second open
Segmentation fault
I could post all the code. It's only 146 lines. But perhaps this is
enough?
I'm thinking it might be an issue with close and the dtor being called
on the same object. If you add std.gc.fullCollect() after the bf =
null. Does that make the code seg fault before 'after close' is
written?
Gide
I had to wriggle the code around a bit. (It's D2 not D1.) However it
didn't make any difference to do:
void main()
{
try
{ BlockFile bf;
bf = new BlockFile ("test.bf", 4096);
writefln ("before close");
bf.close;
bf = null;
GC.collect;
writefln ("after close");
BlockFile cf = new BlockFile ("test.bf",
4096);
writefln ("after second open");
}
catch (Exception e)
{ writefln ("Caught Exception ", e); }
}
-------------------
And the docs say that GC.collect does a full collect;
P.S.: Attached is the full listing
import std.file;
import core.memory;
import std.stdio;
import std.stream;
/** the BlockNo type is used to specify block number. */
typedef ulong BlockNo;
/** the DskAddr type is used to specify file byte offset. */
typedef ulong DskAddr;
/** A BlockFile is a file of fixed size blocks with a file header. It knows nothing
* about the internal structure of those blocks, but each block has a header */
class BlockFile
{ BufferedFile bf;
struct FileHead
{ uint sig;
ushort blockSize;
}
FileHead fh;
/** This is the signature of a BlockFile. It should be overridden by subclasses
* I'm using a date (yyyymmdd) ~ a 2 digit sequence #. Descendent classes should
* override this value. */
protected uint fhSig = 2009012901;
struct BlockHead
{ ushort sig;
BlockNo num;
}
BlockHead bh;
/** The block signature is used to denote the start of a block. It's an arbitrary
* value whose only purpose is to facilitate recovery after a crash */
protected ushort bhSig = cast(ushort)314195;
string filName;
/** Params:
* filNam: the name of the file to be used as a string, either in absolute path
* form of relative to the current directory.
* blkSiz: if this is a new file, then the size of data block (excluding block
* header) that will be written in the file. If the file already exists
* then this parameter will be ignored. (So check later if it matters
* to you!)
*/
this (in string filNam, in ushort blkSiz)
in { assert (filNam.length > 0); }
out { assert (bf !is null);
assert (bf.readable);
assert (bf.writeable);
assert (bf.seekable);
}
body
{ if (exists (filNam) )
{ if (isfile (filNam) ) openExistingFile (filNam);
else throw new Exception ("\"" ~ filNam
~ "\n exists on disk but is not a file.");
}
else
{ fh.sig = fhSig;
fh.blockSize = blkSiz;
createFile (filNam);
}
writefln ("Exiting BlockFile::this");
}
~this()
{ close; }
void close()
{ if (bf !is null) bf.close;
bf = null;
}
private void createFile (in string filNam)
{ bf = new BufferedFile (filNam, FileMode.In | FileMode.Out);
}
DskAddr dskAddr (BlockNo num)
in { assert (num > 0); }
out (result) { assert (result - 1 <= bf.size); }
body
{ DskAddr d = cast(DskAddr)(fh.sizeof + (num - 1) * fh.blockSize);
return d;
}
private void openExistingFile (in string filNam)
{ bf = new BufferedFile (filNam, FileMode.In | FileMode.Out);
}
void position (BlockNo num)
{ DskAddr d = dskAddr (num);
bf.position(d);
}
private void readFileHead()
in { assert (bf.size > fh.sizeof); }
body
{ bf.position (0);
auto cnt = bf.readBlock ( cast(void *)&fh, fh.sizeof);
if (cnt != fh.sizeof)
throw new Exception ("In \"" ~ filName ~ "\"read the wrong # of bytes for "
~ "the file header.");
if (fh.sig != fhSig) throw new Exception ("\"" ~ filName
~ "\" is not a BlockFile.");
}
void readBlock (BlockNo blkNo)
{ position (blkNo);
auto cnt = bf.readBlock (cast(void *)&bh, bh.sizeof);
if (cnt != bh.sizeof)
throw new Exception ("In \"" ~ filName ~ "\"read the wrong # of bytes for "
~ "the header of block " ~ blkNo.stringof);
if (bh.sig != bhSig)
throw new Exception ("\"" ~ filName ~ ":blk " ~ blkNo.stringof
~ " the block has a bad signature.");
if (bh.num != blkNo)
throw new Exception ("\"" ~ filName ~ ":blk " ~ blkNo.stringof
~ " the block has a bad block # == " ~ bh.num.stringof);
}
private void writeFileHead()
{ bf.position (0);
auto cnt = bf.writeBlock ( cast(void *)&fh, fh.sizeof);
if (cnt != fh.sizeof)
throw new Exception ("In \"" ~ filName ~ "\"Wrote the wrong # of bytes for "
~ "the file header.");
}
}
void main()
{
try
{ BlockFile bf;
bf = new BlockFile ("test.bf", 4096);
writefln ("before close");
bf.close;
bf = null;
GC.collect;
writefln ("after close");
BlockFile cf = new BlockFile ("test.bf", 4096);
writefln ("after second open");
}
catch (Exception e)
{ writefln ("Caught Exception ", e); }
}