# HG changeset patch # User koda # Date 1365179123 -7200 # Node ID dd4035ee0f12e6cdf39e8b8940b5c91edb389cbd # Parent 85eb1f4b4a5f210fc2e810ef09198f6b3e66329f use SDL_Threads everywhere The trick was to mark the threaded functions as cdecl and load arguments correctly. This allows us to: - drop a few ifdefs; - use integrated waiting code; - remove some whitespaces \o/; - fix bug 591. diff -r 85eb1f4b4a5f -r dd4035ee0f12 hedgewars/SDLh.pas --- a/hedgewars/SDLh.pas Thu Apr 04 20:31:41 2013 -0400 +++ b/hedgewars/SDLh.pas Fri Apr 05 18:25:23 2013 +0200 @@ -946,12 +946,11 @@ procedure SDL_StartTextInput; cdecl; external SDLLibName; function SDL_PeepEvents(event: PSDL_Event; numevents: LongInt; action: TSDL_eventaction; minType, maxType: LongWord): LongInt; cdecl; external SDLLibName; -function SDL_CreateThread(fn: Pointer; name: PChar; data: Pointer): PSDL_Thread; cdecl; external SDLLibName; {$ELSE} -function SDL_CreateThread(fn: Pointer; data: Pointer): PSDL_Thread; cdecl; external SDLLibName; function SDL_PeepEvents(event: PSDL_Event; numevents: LongInt; action: TSDL_eventaction; mask: LongWord): LongInt; cdecl; external SDLLibName; {$ENDIF} + function SDL_GetMouseState(x, y: PLongInt): Byte; cdecl; external SDLLibName; function SDL_GetKeyName(key: LongWord): PChar; cdecl; external SDLLibName; function SDL_GetScancodeName(key: LongWord): PChar; cdecl; external SDLLibName; @@ -969,7 +968,13 @@ procedure SDL_WM_SetCaption(title: PChar; icon: PChar); cdecl; external SDLLibName; function SDL_WM_ToggleFullScreen(surface: PSDL_Surface): LongInt; cdecl; external SDLLibName; + +// remember to mark the threaded functions as 'cdecl; export;' +// (or have fun debugging nil arguments) +function SDL_CreateThread(fn: Pointer; {$IFDEF SDL13}name: PChar;{$ENDIF} data: Pointer): PSDL_Thread; cdecl; external SDLLibName; procedure SDL_WaitThread(thread: PSDL_Thread; status: PLongInt); cdecl; external SDLLibName; +procedure SDL_KillThread(thread: PSDL_Thread); cdecl; external SDLLibName; + function SDL_CreateMutex: PSDL_mutex; cdecl; external SDLLibName; procedure SDL_DestroyMutex(mutex: PSDL_mutex); cdecl; external SDLLibName; function SDL_LockMutex(mutex: PSDL_mutex): LongInt; cdecl; external SDLLibName name 'SDL_mutexP'; diff -r 85eb1f4b4a5f -r dd4035ee0f12 hedgewars/options.inc --- a/hedgewars/options.inc Thu Apr 04 20:31:41 2013 -0400 +++ b/hedgewars/options.inc Fri Apr 05 18:25:23 2013 +0200 @@ -29,10 +29,8 @@ {$DEFINE USE_LUA_SCRIPT} - {$IFDEF ANDROID} {$DEFINE MOBILE} - {$DEFINE USE_SDLTHREADS} {$DEFINE USE_CONTEXT_RESTORE} {$DEFINE Java_Prefix:= 'Java_org_hedgewars_hedgeroid_EngineProtocol_PascalExports_'} {$ENDIF} diff -r 85eb1f4b4a5f -r dd4035ee0f12 hedgewars/uAI.pas --- a/hedgewars/uAI.pas Thu Apr 04 20:31:41 2013 -0400 +++ b/hedgewars/uAI.pas Fri Apr 05 18:25:23 2013 +0200 @@ -30,31 +30,21 @@ implementation uses uConsts, SDLh, uAIMisc, uAIAmmoTests, uAIActions, - uAmmos, SysUtils{$IFNDEF USE_SDLTHREADS} {$IFDEF UNIX}, cthreads{$ENDIF} {$ENDIF}, uTypes, + uAmmos, SysUtils, uTypes, uVariables, uCommands, uUtils, uDebug, uAILandMarks; var BestActions: TActions; CanUseAmmo: array [TAmmoType] of boolean; StopThinking: boolean; -{$IFDEF USE_SDLTHREADS} ThinkThread: PSDL_Thread = nil; -{$ELSE} - ThinkThread: TThreadID; -{$ENDIF} - hasThread: LongInt; StartTicks: Longword; procedure FreeActionsList; begin AddFileLog('FreeActionsList called'); - if hasThread <> 0 then - begin - AddFileLog('Waiting AI thread to finish'); - StopThinking:= true; - repeat - SDL_Delay(10) - until hasThread = 0 - end; + if (ThinkThread <> nil) then + SDL_WaitThread(ThinkThread, nil); + ThinkThread:=nil; with CurrentHedgehog^ do if Gear <> nil then @@ -66,7 +56,6 @@ end; - const cBranchStackSize = 12; type TStackEntry = record WastedTicks: Longword; @@ -123,15 +112,11 @@ with Me^.Hedgehog^ do a:= CurAmmoType; aa:= a; -{$IFDEF USE_SDLTHREADS} - SDL_delay(0); //ThreadSwitch was only a hint -{$ELSE} - ThreadSwitch(); -{$ENDIF} + SDL_delay(0); // hint to let the context switch run repeat - if (CanUseAmmo[a]) - and ((not rareChecks) or ((AmmoTests[a].flags and amtest_Rare) = 0)) - and ((i = 0) or ((AmmoTests[a].flags and amtest_NoTarget) = 0)) + if (CanUseAmmo[a]) + and ((not rareChecks) or ((AmmoTests[a].flags and amtest_Rare) = 0)) + and ((i = 0) or ((AmmoTests[a].flags and amtest_NoTarget) = 0)) then begin {$HINTS OFF} @@ -150,10 +135,10 @@ AddAction(BestActions, aia_LookRight, 0, 200, 0, 0) else if (ap.Angle < 0) then AddAction(BestActions, aia_LookLeft, 0, 200, 0, 0); - + if (Ammoz[a].Ammo.Propz and ammoprop_Timerable) <> 0 then AddAction(BestActions, aia_Timer, ap.Time div 1000, 400, 0, 0); - + if (Ammoz[a].Ammo.Propz and ammoprop_NoCrosshair) = 0 then begin dAngle:= LongInt(Me^.Angle) - Abs(ap.Angle); @@ -168,23 +153,23 @@ AddAction(BestActions, aia_Down, aim_release, -dAngle, 0, 0) end end; - + if (Ammoz[a].Ammo.Propz and ammoprop_NeedTarget) <> 0 then begin AddAction(BestActions, aia_Put, 0, 1, ap.AttackPutX, ap.AttackPutY) end; - + if (Ammoz[a].Ammo.Propz and ammoprop_OscAim) <> 0 then begin AddAction(BestActions, aia_attack, aim_push, 350 + random(200), 0, 0); AddAction(BestActions, aia_attack, aim_release, 1, 0, 0); - + if abs(ap.Angle) > 32 then begin AddAction(BestActions, aia_Down, aim_push, 100 + random(150), 0, 0); AddAction(BestActions, aia_Down, aim_release, 32, 0, 0); end; - + AddAction(BestActions, aia_waitAngle, ap.Angle, 250, 0, 0); AddAction(BestActions, aia_attack, aim_push, 1, 0, 0); AddAction(BestActions, aia_attack, aim_release, 1, 0, 0); @@ -243,21 +228,21 @@ if (Me^.State and gstAttacked) = 0 then TestAmmos(Actions, Me, false); - + BestRate:= RatePlace(Me); BaseRate:= Max(BestRate, 0); -// switch to 'skip' if we can't move because of mouse cursor being shown +// switch to 'skip' if we cannot move because of mouse cursor being shown if (Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) <> 0 then AddAction(Actions, aia_Weapon, Longword(amSkip), 100 + random(200), 0, 0); - -if ((CurrentHedgehog^.MultiShootAttacks = 0) or ((Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NoMoveAfter) = 0)) + +if ((CurrentHedgehog^.MultiShootAttacks = 0) or ((Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NoMoveAfter) = 0)) and (GameFlags and gfArtillery = 0) then begin tmp:= random(2) + 1; Push(0, Actions, Me^, tmp); Push(0, Actions, Me^, tmp xor 3); - + while (Stack.Count > 0) and (not StopThinking) do begin Pop(ticks, Actions, Me^); @@ -267,7 +252,7 @@ AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0) else AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0); - + steps:= 0; while (not StopThinking) do @@ -280,8 +265,8 @@ if ticks > maxticks then break; - if (BotLevel < 5) - and (GoInfo.JumpType = jmpHJump) + if (BotLevel < 5) + and (GoInfo.JumpType = jmpHJump) and (not checkMark(hwRound(Me^.X), hwRound(Me^.Y), markHJumped)) then // hjump support begin @@ -295,7 +280,7 @@ AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0) else AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0); - + AddAction(MadeActions, aia_HJump, 0, 305 + random(50), 0, 0); AddAction(MadeActions, aia_HJump, 0, 350, 0, 0); end; @@ -303,8 +288,8 @@ Push(ticks, Stack.States[Pred(Stack.Count)].MadeActions, AltMe, Me^.Message) end; end; - if (BotLevel < 3) - and (GoInfo.JumpType = jmpLJump) + if (BotLevel < 3) + and (GoInfo.JumpType = jmpLJump) and (not checkMark(hwRound(Me^.X), hwRound(Me^.Y), markLJumped)) then // ljump support begin @@ -323,7 +308,7 @@ // push current position so we proceed from it after checking jump+forward walk opportunities if CanGo then Push(ticks, Actions, Me^, Me^.Message); - + // first check where we go after jump walking forward if Push(ticks, Actions, AltMe, Me^.Message) then with Stack.States[Pred(Stack.Count)] do @@ -331,10 +316,10 @@ break end; - // 'not CanGO' means we can't go straight, possible jumps are checked above + // 'not CanGO' means we cannot go straight, possible jumps are checked above if not CanGo then break; - + inc(steps); Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X); Rate:= RatePlace(Me); @@ -347,17 +332,17 @@ end else if Rate < BestRate then break; - + if ((Me^.State and gstAttacked) = 0) and ((steps mod 4) = 0) then begin if (steps > 4) and checkMark(hwRound(Me^.X), hwRound(Me^.Y), markWalkedHere) then - break; + break; addMark(hwRound(Me^.X), hwRound(Me^.Y), markWalkedHere); TestAmmos(Actions, Me, ticks shr 12 = oldticks shr 12); - + end; - + if GoInfo.FallPix >= FallPixForBranching then Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right end {while}; @@ -368,25 +353,25 @@ end {if} end; -function Think(Me: Pointer): ptrint; +function Think(Me: PGear): LongInt; cdecl; export; var BackMe, WalkMe: TGear; switchCount: LongInt; StartTicks, currHedgehogIndex, itHedgehog, switchesNum, i: Longword; switchImmediatelyAvailable: boolean; Actions: TActions; begin -InterlockedIncrement(hasThread); +AddFileLog('Thread started'); StartTicks:= GameTicks; currHedgehogIndex:= CurrentTeam^.CurrHedgehog; itHedgehog:= currHedgehogIndex; switchesNum:= 0; switchImmediatelyAvailable:= (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtSwitcher); -if PGear(Me)^.Hedgehog^.BotLevel <> 5 then +if Me^.Hedgehog^.BotLevel <> 5 then switchCount:= HHHasAmmo(PGear(Me)^.Hedgehog^, amSwitch) else switchCount:= 0; -if (PGear(Me)^.State and gstAttacked) = 0 then +if (Me^.State and gstAttacked) = 0 then if Targets.Count > 0 then begin // iterate over current team hedgehogs @@ -402,7 +387,7 @@ begin // when AI has to use switcher, make it cost smth unless they have a lot of switches if (switchCount < 10) then Actions.Score:= (-27+switchCount*3)*4000; - AddAction(Actions, aia_Weapon, Longword(amSwitch), 300 + random(200), 0, 0); + AddAction(Actions, aia_Weapon, Longword(amSwitch), 300 + random(200), 0, 0); AddAction(Actions, aia_attack, aim_push, 300 + random(300), 0, 0); AddAction(Actions, aia_attack, aim_release, 1, 0, 0); end; @@ -416,10 +401,9 @@ itHedgehog:= Succ(itHedgehog) mod CurrentTeam^.HedgehogsNumber; until (itHedgehog = currHedgehogIndex) or ((CurrentTeam^.Hedgehogs[itHedgehog].Gear <> nil) and (CurrentTeam^.Hedgehogs[itHedgehog].Effects[heFrozen]=0)); - inc(switchesNum); until (not (switchImmediatelyAvailable or (switchCount > 0))) - or StopThinking + or StopThinking or (itHedgehog = currHedgehogIndex) or BestActions.isWalkingToABetterPlace; @@ -435,7 +419,7 @@ end else SDL_Delay(100) else begin - BackMe:= PGear(Me)^; + BackMe:= Me^; while (not StopThinking) and (BestActions.Count = 0) do begin (* @@ -454,9 +438,9 @@ end end; -PGear(Me)^.State:= PGear(Me)^.State and (not gstHHThinking); +Me^.State:= Me^.State and (not gstHHThinking); +ThinkThread:= nil; Think:= 0; -InterlockedDecrement(hasThread) end; procedure StartThink(Me: PGear); @@ -487,12 +471,7 @@ FillBonuses((Me^.State and gstAttacked) <> 0); AddFileLog('Enter Think Thread'); -{$IFDEF USE_SDLTHREADS} -ThinkThread := SDL_CreateThread(@Think{$IFDEF SDL13}, nil{$ENDIF}, Me); -{$ELSE} -BeginThread(@Think, Me, ThinkThread); -{$ENDIF} -AddFileLog('Thread started'); +ThinkThread:= SDL_CreateThread(@Think{$IFDEF SDL13}, 'think'{$ENDIF}, Me); end; //var scoreShown: boolean = false; @@ -513,14 +492,14 @@ StopMessages(Gear^.Message); TryDo((Gear^.Message and gmAllStoppable) = 0, 'Engine bug: AI may break demos playing', true); end; - + if Gear^.Message <> 0 then exit; - - //scoreShown:= false; + + //scoreShown:= false; StartThink(Gear); StartTicks:= GameTicks - + end else begin {if not scoreShown then @@ -537,13 +516,15 @@ procedure initModule; begin - hasThread:= 0; StartTicks:= 0; - ThinkThread:= ThinkThread; + ThinkThread:= nil; end; procedure freeModule; begin + if (ThinkThread <> nil) then + SDL_KillThread(ThinkThread); + ThinkThread:= nil; FreeActionsList(); end; diff -r 85eb1f4b4a5f -r dd4035ee0f12 hedgewars/uMisc.pas --- a/hedgewars/uMisc.pas Thu Apr 04 20:31:41 2013 -0400 +++ b/hedgewars/uMisc.pas Fri Apr 05 18:25:23 2013 +0200 @@ -38,8 +38,7 @@ implementation uses SysUtils, uVariables, uUtils - {$IFDEF PNG_SCREENSHOTS}, PNGh, png {$ENDIF} - {$IFNDEF USE_SDLTHREADS} {$IFDEF UNIX}, cthreads{$ENDIF} {$ENDIF}; + {$IFDEF PNG_SCREENSHOTS}, PNGh, png {$ENDIF}; type PScreenshot = ^TScreenshot; TScreenshot = record @@ -64,7 +63,7 @@ {$IFDEF PNG_SCREENSHOTS} // this funtion will be executed in separate thread -function SaveScreenshot(screenshot: pointer): PtrInt; +function SaveScreenshot(screenshot: pointer): LongInt; cdecl; export; var i: LongInt; png_ptr: ^png_struct; info_ptr: ^png_info; @@ -119,7 +118,7 @@ {$ELSE} // no PNG_SCREENSHOTS // this funtion will be executed in separate thread -function SaveScreenshot(screenshot: pointer): PtrInt; +function SaveScreenshot(screenshot: pointer): LongInt; cdecl; export; var f: file; // Windows Bitmap Header head: array[0..53] of Byte = ( @@ -262,11 +261,7 @@ image^.size:= size; image^.buffer:= p; -{$IFDEF USE_SDLTHREADS} -SDL_CreateThread(@SaveScreenshot{$IFDEF SDL13}, nil{$ENDIF}, image); -{$ELSE} -BeginThread(@SaveScreenshot, image); -{$ENDIF} +SDL_CreateThread(@SaveScreenshot{$IFDEF SDL13}, 'snapshot'{$ENDIF}, image); MakeScreenshot:= true; // possibly it is not true but we will not wait for thread to terminate end;