Icon View Incident Report

Serious Serious
Reported By: Darian Miller
Reported On: 7/20/2001
For: Version 2.10 Build 1
# 821 Using LoadFromStream from within Multiple Threads Causes a Lockup

When using Memory based tables and accessing table in child threads everything works correctly unless the table was restored from disk in the main thread using .LoadFromStream then the table .Open 'locks-up' the child thread. (Looks like it's waiting for access to a critical section.)

If you comment out {SECTION1} then {SECTION2} gets executed and no errors occur in the child thread. If the file is saved to disk and successfully restored within {SECTION1} then the child threads get locked on .Open..

    FMimeTable := TDBISAMTable.Create(nil);
    FMimeTable.SessionName := FDBSession.SessionName;
    FMimeTable.InMemory := True;
    FMimeTable.TableName := 'Memory_Mime';
    TableBuild_Mime(FMimeTable);

{SECTION1}
    bErr := False;
    try
      MimeStream := TFileStream.Create(FThreadVar.FConfigDirectory   
'MIME.DAT', fmOpenRead or fmShareDenyNone);
      try
        try
          FMimeTable.Open;
          FMimeTable.LoadFromStream(MimeStream);  //no errors
        except
          bErr := True;
        end;
      finally
        MimeStream.Free;
      end;
    except
      bErr := True;
    end;

{SECTION2}
    if bErr then
    begin
      PostWarning('Cannot load mime table...creating one with default values.');

      TableFill_Mime(FMimeTable);

      try
        bErr := False;
        try
          MimeStream := TFileStream.Create(FWebThreadVar.FConfigDirectory   
'MIME.DAT', fmCreate or fmShareDenyWrite);
        except
          bErr := True;
        end;

        if not bErr then
        begin
          try
            try
              FMimeTable.SaveToStream(MimeStream);
            except
            end;
          finally
            MimeStream.Free;
          end;
        end;
      except
      end;
    end;
    FMimeTable.Open;

{SUPPORT FUNCTIONS CALLED}
procedure TableBuild_Mime(Table:TDBISAMTable);
begin

  with Table do
  begin
    Close;
    FieldDefs.Clear;
    IndexDefs.Clear;
    FieldDefs.Add('Extension', ftString, 10, False);   
    FieldDefs.Add('Content', ftString, 100, False);    
    IndexDefs.Add('ByExtension','Extension',[]);
    CreateTable;
    IndexName := 'ByExtension';
  end;
end;


procedure TableFill_Mime(Table:TDBISAMTable);
  type TMimeTable = Array[0..10, 0..1] of string;
  const aDefault:TMimeTable = (
                               ('',     'application/octet-stream'),
                               ('.BMP',  'image/bmp'),
                               ('.GIF',  'image/gif'),
                               ('.HTM',  'text/html'),
                               ('.HTML', 'text/html'),
                               ('.JPEG', 'image/jpeg'),
                               ('.JPG',  'image/jpeg'),
                               ('.TXT',  'text/plain'),
                               ('.XML',  'text/xml'),
                               ('.XSL',  'text/xml'),
                               ('.ZIP',  'application/x-zip-compressed')
                              );
  var
    i:Integer;
begin

  with Table do
  begin
    Open;
    for i := Low(aDefault) to High(aDefault) do
    begin
      Append;
      Fields[0].AsString := aDefault[i][0];
      Fields[1].AsString := aDefault[i][1];
      Post;
    end;

  end;
end;

{CHILD THREAD}
    LocalDatabase := TDBISAMTable.Create(nil);
    try
      LocalDatabase.SessionName := Session.SessionName;  //unique w/thread 
ID
      LocalDatabase.InMemory := True;
      LocalDatabase.Exclusive := False;
      LocalDatabase.TableName := 'Memory_Mime';
      LocalDatabase.IndexName := 'ByExtension';
      LocalDatabase.Open;  //locks-up
     ....



Comments Comments
The problem was exactly as Darian described it - a critical section was acquired during the LoadFromStream but not released afterward.


Resolution Resolution
Fixed Problem on 7/24/2001 in version 2.12 build 1
Image