mirror of https://github.com/red-prig/fpPS4.git
181 lines
3.9 KiB
Plaintext
181 lines
3.9 KiB
Plaintext
unit thr_stack;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
mqueue,
|
|
syscalls,
|
|
pthread_md,
|
|
thr_private,
|
|
thr_init;
|
|
|
|
procedure _thr_stack_fix_protection(td:p_pthread);
|
|
function _thr_stack_alloc(attr:p_pthread_attr):Integer;
|
|
procedure _thr_stack_free(attr:p_pthread_attr);
|
|
|
|
implementation
|
|
|
|
uses
|
|
sys_mmap;
|
|
|
|
type
|
|
//Spare thread stack.
|
|
p_stack=^t_stack;
|
|
t_stack=packed record
|
|
qe :LIST_ENTRY; //Stack queue linkage.
|
|
stacksize:QWORD; //Stack size (rounded up).
|
|
guardsize:QWORD; //Guard size.
|
|
stackaddr:Pointer; //Stack address.
|
|
end;
|
|
|
|
var
|
|
dstackq :p_stack=nil;
|
|
mstackq :p_stack=nil;
|
|
last_stack:Pointer=nil;
|
|
|
|
function round_up(size:QWORD):QWORD; inline;
|
|
begin
|
|
if ((size mod _thr_page_size)<>0) then
|
|
begin
|
|
size:=((size div _thr_page_size)+1)*_thr_page_size;
|
|
end;
|
|
Result:=size;
|
|
end;
|
|
|
|
const
|
|
_rtld_get_stack_prot=PROT_READ or PROT_WRITE;
|
|
|
|
procedure _thr_stack_fix_protection(td:p_pthread);
|
|
begin
|
|
mprotect(td^.attr.stackaddr_attr+
|
|
round_up(td^.attr.guardsize_attr),
|
|
round_up(td^.attr.stacksize_attr),
|
|
_rtld_get_stack_prot);
|
|
end;
|
|
|
|
function _thr_stack_alloc(attr:p_pthread_attr):Integer;
|
|
var
|
|
curthread:p_pthread;
|
|
spare_stack,next:p_stack;
|
|
stacksize:QWORD;
|
|
guardsize:QWORD;
|
|
stackaddr:Pointer;
|
|
r:Integer;
|
|
begin
|
|
curthread:=_get_curthread;
|
|
|
|
stacksize:=round_up(attr^.stacksize_attr);
|
|
guardsize:=round_up(attr^.guardsize_attr);
|
|
|
|
attr^.stackaddr_attr:=nil;
|
|
attr^.flags:=attr^.flags and (not THR_STACK_USER);
|
|
|
|
THREAD_LIST_WRLOCK(curthread);
|
|
|
|
if ((stacksize=THR_STACK_DEFAULT) and
|
|
(guardsize=_thr_guard_default)) then
|
|
begin
|
|
spare_stack:=LIST_FIRST(@dstackq);
|
|
if (spare_stack<>nil) then
|
|
begin
|
|
LIST_REMOVE(spare_stack,@spare_stack^.qe);
|
|
attr^.stackaddr_attr:=spare_stack^.stackaddr;
|
|
end;
|
|
end else
|
|
begin
|
|
spare_stack:=LIST_FIRST(@mstackq);
|
|
While (spare_stack<>nil) do
|
|
begin
|
|
next:=LIST_NEXT(spare_stack,@spare_stack^.qe);
|
|
if (spare_stack^.stacksize=stacksize) and
|
|
(spare_stack^.guardsize=guardsize) then
|
|
begin
|
|
LIST_REMOVE(spare_stack,@spare_stack^.qe);
|
|
attr^.stackaddr_attr:=spare_stack^.stackaddr;
|
|
break;
|
|
end;
|
|
spare_stack:=next;
|
|
end;
|
|
end;
|
|
|
|
if (attr^.stackaddr_attr<>nil) then
|
|
begin
|
|
THREAD_LIST_UNLOCK(curthread);
|
|
end else
|
|
begin
|
|
if (last_stack=nil) then
|
|
begin
|
|
last_stack:=_usrstack-_thr_stack_initial-_thr_guard_default;
|
|
end;
|
|
|
|
stackaddr:=last_stack-stacksize-guardsize;
|
|
|
|
last_stack:=last_stack-(stacksize+guardsize);
|
|
|
|
THREAD_LIST_UNLOCK(curthread);
|
|
|
|
stackaddr:=mmap(stackaddr,
|
|
stacksize+guardsize,
|
|
_rtld_get_stack_prot,
|
|
MAP_STACK,-1,0
|
|
);
|
|
|
|
r:=0;
|
|
if (stackaddr<>MAP_FAILED) then
|
|
begin
|
|
r:=mprotect(stackaddr,guardsize,PROT_NONE);
|
|
end;
|
|
|
|
if (stackaddr<>MAP_FAILED) and
|
|
((guardsize=0) or (r=0)) then
|
|
begin
|
|
sceKernelSetVirtualRangeName(stackaddr,guardsize,'stack guard');
|
|
stackaddr:=stackaddr+guardsize;
|
|
end else
|
|
begin
|
|
if (stackaddr<>MAP_FAILED) then
|
|
begin
|
|
munmap(stackaddr,stacksize+guardsize);
|
|
end;
|
|
stackaddr:=nil;
|
|
end;
|
|
attr^.stackaddr_attr:=stackaddr;
|
|
end;
|
|
|
|
if (attr^.stackaddr_attr<>nil) then
|
|
Result:=0
|
|
else
|
|
Result:=-1;
|
|
end;
|
|
|
|
procedure _thr_stack_free(attr:p_pthread_attr);
|
|
var
|
|
spare_stack:p_stack;
|
|
begin
|
|
if (attr<>nil) and
|
|
((attr^.flags and THR_STACK_USER)=0) and
|
|
(attr^.stackaddr_attr<>nil) then
|
|
begin
|
|
spare_stack:=attr^.stackaddr_attr+attr^.stacksize_attr-sizeof(t_stack);
|
|
spare_stack^.stacksize:=round_up(attr^.stacksize_attr);
|
|
spare_stack^.guardsize:=round_up(attr^.guardsize_attr);
|
|
spare_stack^.stackaddr:=attr^.stackaddr_attr;
|
|
|
|
if (spare_stack^.stacksize=THR_STACK_DEFAULT) and
|
|
(spare_stack^.guardsize=_thr_guard_default) then
|
|
begin
|
|
LIST_INSERT_HEAD(@dstackq,spare_stack,@spare_stack^.qe);
|
|
end else
|
|
begin
|
|
LIST_INSERT_HEAD(@mstackq,spare_stack,@spare_stack^.qe);
|
|
end;
|
|
attr^.stackaddr_attr:=nil;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|