In ArcIWWebModuleBridge, method TArcIWWebModuleBridge.LockSession, a
coding problem results in a serious threading problem.
The method locks the global list of sessions, walks the list to find the
desired session, locks the session, then unlocks the global list.
The problem is that the call to lock the session is a blocking call. This
means that while waiting for that lock, the global GSessions list is
locked.
This further means that the session can never be unlocked, as the
UnlockSessions method needs to lock GSessions before the unlock can
proceed. Thus you have a deadlock.
So as soon as there are two threads making requests from the same session
simultaneously, this bug basically locks up the Intraweb application.
The resolution is simple: alter LockSessions so that it looks up the
session, then releases the lock on GSessions, and THEN locks the session.
Here is the modified routine:
function TArcIWWebModuleBridge.LockSession(const AppID: string):
TIWApplication;
var
ls : TList;
i : integer;
begin
Result := nil;
ls := GSessions.LockList;
try
for i := 0 to ls.Count-1 do
if TIWApplication(ls[i]).AppID = AppID then
begin
Result := ls[i];
break;
end;
//dbr: WRONG! Result.Lock is a blocking call--you do NOT
// want to call it while GSessions is locked. Will result
// in a deadlock as soon as there are two active threads for
// the same session.
//dbr if Result <> nil then
//dbr Result.Lock;
finally
GSessions.UnlockList;
end;
//dbr start
try
if Result <> nil then begin
Result.Lock;
end;
except
Result := nil;
end;
//dbr end
if Result = nil then
raise EArcIWBridgeSessionNotFound.Create('Session not found for
AppID: '+AppID+'. Session may have expired.');
end;
Original issue reported on code.google.com by dbrue...@gmail.com on 30 Apr 2009 at 4:43
Original issue reported on code.google.com by
dbrue...@gmail.com
on 30 Apr 2009 at 4:43