📄 ibsqlmonitor.pas
字号:
{$ENDIF}
FreeAndNil(FWriterThread);
end;
end;
end;
procedure TIBSQLMonitorHook.WriteSQLData(Text: String;
DataType: TTraceFlag);
begin
if not FEventsCreated then
try
CreateEvents;
except
Enabled := false;
Exit;
end;
Text := CRLF + '[Application: ' + DBApplication.Title + ']' + CRLF + Text; {do not localize}
if not Assigned(FWriterThread) then
FWriterThread := TWriterThread.Create;
FWriterThread.WriteSQLData(Text, DataType);
end;
{ TWriterThread }
constructor TWriterThread.Create;
begin
inherited Create(true);
FMsgs := TObjectList.Create(true);
Resume;
end;
destructor TWriterThread.Destroy;
begin
FMsgs.Free;
inherited Destroy;
end;
procedure TWriterThread.Execute;
begin
{$IFDEF MSWINDOWS}
{ Place thread code here }
while ((not Terminated) and (not bDone)) or
(FMsgs.Count <> 0) do
begin
{ Any one listening? }
if FMonitorCount^ = 0 then
begin
if FMsgs.Count <> 0 then
FMsgs.Remove(FMsgs[0]);
Sleep(50);
end
else
{ Anything to process? }
if FMsgs.Count <> 0 then
begin
{ If the current queued message is a release release the object }
if FMsgs.Items[0] is TReleaseObject then
PostMessage(TReleaseObject(FMsgs.Items[0]).FHandle, CM_RELEASE, 0, 0)
else
{ Otherwise write the TraceObject to the buffer }
begin
WriteToBuffer;
end;
end
else
Sleep(50);
end;
{$ENDIF}
end;
procedure TWriterThread.Lock;
begin
{$IFDEF MSWINDOWS}
WaitForSingleObject(FWriteLock, INFINITE);
{$ENDIF}
end;
procedure TWriterThread.Unlock;
begin
{$IFDEF MSWINDOWS}
ReleaseMutex(FWriteLock);
{$ENDIF}
end;
procedure TWriterThread.WriteSQLData(Msg : String; DataType: TTraceFlag);
begin
if FMonitorCount^ <> 0 then
FMsgs.Add(TTraceObject.Create(Msg, DataType));
end;
procedure TWriterThread.BeginWrite;
begin
Lock;
end;
procedure TWriterThread.EndWrite;
begin
{$IFDEF MSWINDOWS}
{
* 1. Wait to end the write until all registered readers have
* started to wait for a write event
* 2. Block all of those waiting for the write to finish.
* 3. Block all of those waiting for all readers to finish.
* 4. Unblock all readers waiting for a write event.
* 5. Wait until all readers have finished reading.
* 6. Now, block all those waiting for a write event.
* 7. Unblock all readers waiting for a write to be finished.
* 8. Unlock the mutex.
}
while WaitForSingleObject(FReadEvent, cDefaultTimeout) = WAIT_TIMEOUT do
begin
if FMonitorCount^ > 0 then
InterlockedDecrement(FMonitorCount^);
if (FReaderCount^ = FMonitorCount^ - 1) or (FMonitorCount^ = 0) then
SetEvent(FReadEvent);
end;
ResetEvent(FWriteFinishedEvent);
ResetEvent(FReadFinishedEvent);
SetEvent(FWriteEvent); { Let all readers pass through. }
while WaitForSingleObject(FReadFinishedEvent, cDefaultTimeout) = WAIT_TIMEOUT do
if (FReaderCount^ = 0) or (InterlockedDecrement(FReaderCount^) = 0) then
SetEvent(FReadFinishedEvent);
ResetEvent(FWriteEvent);
SetEvent(FWriteFinishedEvent);
Unlock;
{$ENDIF}
end;
procedure TWriterThread.WriteToBuffer;
var
i, len: Integer;
Text : String;
begin
Lock;
try
{ If there are no monitors throw out the message
The alternative is to have messages queue up until a
monitor is ready.}
if FMonitorCount^ = 0 then
FMsgs.Remove(FMsgs[0])
else
begin
Text := TTraceObject(FMsgs[0]).FMsg;
i := 1;
len := Length(Text);
while (len > 0) do begin
BeginWrite;
try
FTraceDataType^ := Integer(TTraceObject(FMsgs[0]).FDataType);
FTimeStamp^ := TTraceObject(FMsgs[0]).FTimeStamp;
FBufferSize^ := Min(len, cMaxBufferSize);
Move(Text[i], FBuffer[0], FBufferSize^);
Inc(i, cMaxBufferSize);
Dec(len, cMaxBufferSize);
finally
EndWrite;
end;
end;
FMsgs.Remove(FMsgs[0]);
end;
finally
Unlock;
end;
end;
procedure TWriterThread.ReleaseMonitor(HWnd: THandle);
begin
FMsgs.Add(TReleaseObject.Create(HWnd));
end;
{ TTraceObject }
constructor TTraceObject.Create(Msg : String; DataType: TTraceFlag);
begin
FMsg := Msg;
FDataType := DataType;
FTimeStamp := Now;
end;
constructor TTraceObject.Create(obj: TTraceObject);
begin
FMsg := obj.FMsg;
FDataType := obj.FDataType;
FTimeStamp := obj.FTimeStamp;
end;
{ TReleaseObject }
constructor TReleaseObject.Create(Handle: THandle);
begin
FHandle := Handle;
end;
{ ReaderThread }
procedure TReaderThread.AddMonitor(Arg: TIBCustomSQLMonitor);
begin
EnterCriticalSection(CS);
if FMonitors.IndexOf(Arg) < 0 then
FMonitors.Add(Arg);
LeaveCriticalSection(CS);
end;
procedure TReaderThread.BeginRead;
begin
{$IFDEF MSWINDOWS}
{
* 1. Wait for the "previous" write event to complete.
* 2. Increment the number of readers.
* 3. if the reader count is the number of interested readers, then
* inform the system that all readers are ready.
* 4. Finally, wait for the FWriteEvent to signal.
}
WaitForSingleObject(FWriteFinishedEvent, INFINITE);
InterlockedIncrement(FReaderCount^);
if FReaderCount^ = FMonitorCount^ then
SetEvent(FReadEvent);
WaitForSingleObject(FWriteEvent, INFINITE);
{$ENDIF}
end;
constructor TReaderThread.Create;
begin
inherited Create(true);
st := TTraceObject.Create('', tfMisc); {do not localize}
FMonitors := TObjectList.Create(false);
{$IFDEF MSWINDOWS}
InterlockedIncrement(FMonitorCount^);
{$ENDIF}
Resume;
end;
destructor TReaderThread.Destroy;
begin
{$IFDEF MSWINDOWS}
if FMonitorCount^ > 0 then
InterlockedDecrement(FMonitorCount^);
{$ENDIF}
FMonitors.Free;
st.Free;
inherited Destroy;
end;
procedure TReaderThread.EndRead;
begin
{$IFDEF MSWINDOWS}
if InterlockedDecrement(FReaderCount^) = 0 then
begin
ResetEvent(FReadEvent);
SetEvent(FReadFinishedEvent);
end;
{$ENDIF}
end;
procedure TReaderThread.Execute;
var
i : Integer;
FTemp : TTraceObject;
begin
{$IFDEF MSWINDOWS}
{ Place thread code here }
while (not Terminated) and (not bDone) do
begin
ReadSQLData;
if (st.FMsg <> '') and {do not localize}
not ((st.FMsg = ' ') and (st.FDataType = tfMisc)) then {do not localize}
begin
for i := 0 to FMonitors.Count - 1 do
begin
FTemp := TTraceObject.Create(st);
PostMessage(TIBCustomSQLMonitor(FMonitors[i]).Handle,
WM_IBSQL_SQL_EVENT,
0,
LPARAM(FTemp));
end;
end;
end;
{$ENDIF}
end;
procedure TReaderThread.ReadSQLData;
begin
st.FMsg := ''; {do not localize}
BeginRead;
if not bDone then
try
SetString(st.FMsg, FBuffer, FBufferSize^);
st.FDataType := TTraceFlag(FTraceDataType^);
st.FTimeStamp := TDateTime(FTimeStamp^);
finally
EndRead;
end;
end;
procedure TReaderThread.RemoveMonitor(Arg: TIBCustomSQLMonitor);
begin
EnterCriticalSection(CS);
FMonitors.Remove(Arg);
LeaveCriticalSection(CS);
end;
{ Misc methods }
function MonitorHook: IIBSQLMonitorHook;
begin
if (_MonitorHook = nil) and (not bDone) then
begin
EnterCriticalSection(CS);
if (_MonitorHook = nil) and (not bDone) then
begin
_MonitorHook := TIBSQLMonitorHook.Create;
_MonitorHook._AddRef;
end;
LeaveCriticalSection(CS);
end;
result := _MonitorHook;
end;
procedure EnableMonitoring;
begin
MonitorHook.Enabled := True;
end;
procedure DisableMonitoring;
begin
MonitorHook.Enabled := False;
end;
function MonitoringEnabled: Boolean;
begin
result := MonitorHook.Enabled;
end;
procedure CloseThreads;
begin
if Assigned(FReaderThread) then
begin
FReaderThread.Terminate;
{$IFDEF MSWINDOWS}
FReaderThread.WaitFor;
{$ENDIF}
FreeAndNil(FReaderThread);
end;
if Assigned(FWriterThread) then
begin
FWriterThread.Terminate;
{$IFDEF MSWINDOWS}
FWriterThread.WaitFor;
{$ENDIF}
FreeAndNil(FWriterThread);
end;
end;
initialization
InitializeCriticalSection(CS);
_MonitorHook := nil;
FWriterThread := nil;
FReaderThread := nil;
bDone := False;
finalization
try
bDone := True;
if Assigned(FReaderThread) then
begin
if not Assigned(FWriterThread) then
FWriterThread := TWriterThread.Create;
FWriterThread.WriteSQLData(' ', tfMisc);
end;
CloseThreads;
if Assigned(_MonitorHook) then
_MonitorHook._Release;
finally
_MonitorHook := nil;
DeleteCriticalSection(CS);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -