Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set stack size in TThread?

How can I set a custom stack size in TThread? I am trying to reintroduce the constructor of TThread but it says that ThreadProc is missing yet its right there in System.Classes.

type
  TThreadHelper = class helper for TThread
    constructor Create(const CreateSuspended: Boolean = False; const StackSize: Integer = 0); reintroduce;
 end;

{ TThreadHelper }

constructor TThreadHelper.Create(const CreateSuspended: Boolean; const StackSize: Integer);
begin
  Self.FSuspended := not Self.FExternalThread;
  Self.FCreateSuspended := CreateSuspended and not Self.FExternalThread;
  if not Self.FExternalThread then
  begin
    Self.FHandle := BeginThread(nil, StackSize, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, Self.FThreadID);
    if Self.FHandle = 0 then
    raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(GetLastError)]);
  end
  else
  begin
    Self.FHandle := Winapi.Windows.GetCurrentThread;
    Self.FThreadId := GetCurrentThreadId;
  end;
end;

[dcc32 Error] Project5.dpr(29): E2003 Undeclared identifier: 'ThreadProc'

like image 425
user3725897 Avatar asked Jun 10 '14 11:06

user3725897


People also ask

How do you specify stack size?

You may need to increase the stack size if your program gets stack-overflow messages at runtime. You can also set the stack size by: Using the /STACK linker option. For more information, see /STACK (Stack allocations).

How to set stack size in c++?

CPP. size() function is used to return the size of the stack container or the number of elements in the stack container. Syntax : stackname.

What is Java thread stack size?

Default Stack Size for JVM Internal Threads The default system stack size is 256 KB on all platforms.


2 Answers

I do not know, if you can set stack size after a thread is created. Maybe SetThreadStackGuarantee can be helpful?

You can create a thread from scratch by using BeginThread, but it is quite complicated. I have here a workaround by using Detours. Note that there are several Detours variants. I think only the Cromis.Detours is x64 compatible.

unit IndividualStackSizeForThread;

interface

uses 
  System.Classes,
  Cromis.Detours { http://www.cromis.net/blog/downloads/cromis-ipc/ };

type
  TThreadHelper = class helper for TThread
    constructor Create(CreateSuspended: Boolean; StackSize: LongWord);
 end;

implementation

var
  TrampolineBeginThread: function(SecurityAttributes: Pointer; StackSize: LongWord;
    ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord; 
    var ThreadId: TThreadID): THandle = nil;

threadvar
  StackSizeOverride: LongWord;

function InterceptBeginThread(SecurityAttributes: Pointer; StackSize: LongWord;
  ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord;
  var ThreadId: TThreadID): THandle;
const
  STACK_SIZE_PARAM_IS_A_RESERVATION = $00010000; // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682453(v=vs.85).aspx
begin
  if StackSizeOverride <> 0 then
  begin
    CreationFlags := CreationFlags or STACK_SIZE_PARAM_IS_A_RESERVATION;
    StackSize := StackSizeOverride;
    StackSizeOverride := 0;
  end;

  Result := TrampolineBeginThread(SecurityAttributes, StackSize, ThreadFunc, 
    Parameter, CreationFlags, ThreadId);
end;

constructor TThreadHelper.Create(CreateSuspended: Boolean; StackSize: LongWord);
begin
  StackSizeOverride := StackSize;
  inherited Create(CreateSuspended);
end;

initialization

TrampolineBeginThread := InterceptCreate(@BeginThread, @InterceptBeginThread);

finalization

InterceptRemove(@TrampolineBeginThread, @InterceptBeginThread);

end.

I do not know why Embt does not allow programmer to specify the stack size, if someone knows the reason, it will be very interesting to me.

like image 196
stanleyxu2005 Avatar answered Sep 25 '22 01:09

stanleyxu2005


There is simply no way to control the stack size using TThread. For whatever reason, the designers of TThread failed to include a stack size parameter in the constructor of TThread. This is clearly an omission. You should call BeginThread or CreateThread directly.

If you are simply desperate to make your hack work then you'll need to find the address of the ThreadProc function declared in the implementation section of the Classes unit. Some possible approaches:

  1. Disassemble TThread.Create at runtime to read out the address of ThreadProc.
  2. Create a dummy thread that looks at its call stack to find the address of ThreadProc.
  3. Hook BeginThread using a detour. Create a dummy thread. Note the address of the thread procedure passed. That is ThreadProc.

A good source of ideas for this sort of hacking is the source code for madExcept.

Another way to apply the hack would again be to use a detour on BeginThread. You could then use a thread local variable to supply the stack size. A value of high(LongWord) for that thread local variable would mean "use the value passed as a parameter", and any other value would be the value used by the detoured BeginThread.

like image 25
David Heffernan Avatar answered Sep 25 '22 01:09

David Heffernan