diff --git a/kernel/ps4_libkernel.pas b/kernel/ps4_libkernel.pas index 9942f8ef..8b67de7d 100644 --- a/kernel/ps4_libkernel.pas +++ b/kernel/ps4_libkernel.pas @@ -11,6 +11,7 @@ uses ps4_map_mm, ps4_mspace, ps4_pthread, + ps4_pthread_key, ps4_signal, ps4_mutex, ps4_cond, @@ -1058,12 +1059,21 @@ begin lib^.set_proc($D71BED515C75FD28,@ps4___pthread_cleanup_push_imp); lib^.set_proc($896B0595831FDCAC,@ps4___pthread_cleanup_pop_imp); + //thread + + //pthread_key + lib^.set_proc($9AA50B35D8A64E7D,@ps4_pthread_key_create); lib^.set_proc($E81A4466E0D3ED82,@ps4_pthread_key_delete); lib^.set_proc($D3F297692EF4C72E,@ps4_pthread_getspecific); lib^.set_proc($5AB38BBC7534C903,@ps4_pthread_setspecific); - //thread + lib^.set_proc($81E0DAAA01FD9538,@ps4_scePthreadKeyCreate); + lib^.set_proc($3EB747BAE0DE9216,@ps4_scePthreadKeyDelete); + lib^.set_proc($7A886DEE640E0A6A,@ps4_scePthreadGetspecific); + lib^.set_proc($F81CD7624A9878B1,@ps4_scePthreadSetspecific); + + //pthread_key lib^.set_proc($5AC95C2B51507062,@ps4_sceKernelIsNeoMode); lib^.set_proc($9A9C4076A5BB74A6,@ps4_sceKernelIsProspero); diff --git a/kernel/ps4_pthread.pas b/kernel/ps4_pthread.pas index 598b9c84..d9735f38 100644 --- a/kernel/ps4_pthread.pas +++ b/kernel/ps4_pthread.pas @@ -5,7 +5,6 @@ unit ps4_pthread; interface uses - LFQueue, windows, sys_crt, sys_pthread, @@ -92,11 +91,6 @@ procedure ps4___pthread_cleanup_push_imp(routine:t_cb_proc; info:p_pthread_cleanup); SysV_ABI_CDecl; procedure ps4___pthread_cleanup_pop_imp(execute:Integer); SysV_ABI_CDecl; -function ps4_pthread_key_create(pKey:Ppthread_key_t;dest:t_cb_proc):Integer; SysV_ABI_CDecl; -function ps4_pthread_key_delete(Key:pthread_key_t):Integer; SysV_ABI_CDecl; -function ps4_pthread_getspecific(Key:pthread_key_t):Pointer; SysV_ABI_CDecl; -function ps4_pthread_setspecific(Key:pthread_key_t;value:Pointer):Integer; SysV_ABI_CDecl; - function _pthread_run_entry(pthread:p_pthread;name:Pchar;stack:PDWORD):Integer; implementation @@ -105,26 +99,12 @@ uses atomic, spinlock, sys_kernel, + ps4_pthread_key, ps4_mutex, ps4_map_mm, ps4_program, ps4_elf; -type - p_pthread_key_node=^_pthread_key_node; - _pthread_key_node=packed record - next_:p_pthread_key_node; - version_:ptruint; - dest_:t_cb_proc; - end; - -var - _pthread_key_nodes:array[0..SCE_PTHREAD_KEYS_MAX-1] of _pthread_key_node; - _pthread_key_queue:TIntrusiveMPSCQueue; - _pthread_key_queue_lock:Pointer; - -procedure _pthread_keys_cleanup_dest; forward; - //struct dl_phdr_info procedure ps4_pthread_cxa_finalize(P:Pointer); SysV_ABI_CDecl; begin @@ -391,7 +371,7 @@ begin end; _sig_lock; - _pthread_keys_cleanup_dest; + _thread_cleanupspecific; ps4_app.FreeThread; UnRegistredStack; _sig_unlock; @@ -1023,139 +1003,6 @@ begin end; end; -procedure _pthread_keys_init; -var - i:Integer; -begin - _pthread_key_queue.Create; - For i:=Low(_pthread_key_nodes) to High(_pthread_key_nodes) do - begin - _pthread_key_nodes[i]:=Default(_pthread_key_node); - _pthread_key_queue.Push(@_pthread_key_nodes[i]); - end; -end; - -procedure _pthread_keys_cleanup_dest; -var - i:Integer; - local:p_pthread_key_data; - - node:p_pthread_key_node; - version:ptruint; - dest:t_cb_proc; -begin - local:=@tcb_thread^.keys[0]; - - For i:=Low(_pthread_key_nodes) to High(_pthread_key_nodes) do - begin - node:=@_pthread_key_nodes[i]; - - version:=load_consume(node^.version_); - dest:=t_cb_proc(load_consume(Pointer(node^.dest_))); - - if (ptruint(dest)>1) and - (local[i].version_=version) and - (local[i].data_<>nil) then - begin - dest(local[i].data_); - end; - - end; - -end; - -function ps4_pthread_key_create(pKey:Ppthread_key_t;dest:t_cb_proc):Integer; SysV_ABI_CDecl; -var - node:p_pthread_key_node; - Key:pthread_key_t; -begin - if (pKey=nil) then Exit(EINVAL); - Writeln('pthread_key_create',' ',ps4_pthread_self^.sig._lock); - - if (dest=nil) then dest:=t_cb_proc(1); - - node:=nil; - spin_lock(_pthread_key_queue_lock); - _pthread_key_queue.Pop(node); - spin_unlock(_pthread_key_queue_lock); - - if (node=nil) then Exit(EAGAIN); - - System.InterlockedIncrement(Pointer(node^.version_)); - XCHG(Pointer(node^.dest_),Pointer(dest)); - - Key:=(node-p_pthread_key_node(@_pthread_key_nodes)); - Key:=Key+1; - - pKey^:=Key; - Result:=0; -end; - -function ps4_pthread_key_delete(Key:pthread_key_t):Integer; SysV_ABI_CDecl; -var - node:p_pthread_key_node; -begin - Key:=Key-1; - - if (DWORD(Key)>SCE_PTHREAD_KEYS_MAX) then Exit(EINVAL); - Writeln('pthread_key_delete'); - - node:=@_pthread_key_nodes[Key]; - - if (XCHG(Pointer(node^.dest_),nil)=nil) then Exit(EINVAL); - - System.InterlockedIncrement(Pointer(node^.version_)); - - _pthread_key_queue.Push(node); -end; - -function ps4_pthread_getspecific(Key:pthread_key_t):Pointer; SysV_ABI_CDecl; -var - node:p_pthread_key_node; - version:ptruint; - local:p_pthread_key_data; -begin - Key:=Key-1; - - if (DWORD(Key)>=SCE_PTHREAD_KEYS_MAX) then Exit(nil); - - node:=@_pthread_key_nodes[Key]; - - version:=load_consume(node^.version_); - if (load_consume(Pointer(node^.dest_))=nil) then Exit(nil); - - local:=@tcb_thread^.keys[Key]; - - if (local^.version_<>version) then Exit(nil); - - Result:=local^.data_; -end; - -function ps4_pthread_setspecific(Key:pthread_key_t;value:Pointer):Integer; SysV_ABI_CDecl; -var - node:p_pthread_key_node; - version:ptruint; - local:p_pthread_key_data; -begin - Key:=Key-1; - - if (DWORD(Key)>=SCE_PTHREAD_KEYS_MAX) then Exit(EINVAL); - - node:=@_pthread_key_nodes[Key]; - - version:=load_consume(node^.version_); - if (load_consume(Pointer(node^.dest_))=nil) then Exit(EINVAL); - - local:=@tcb_thread^.keys[Key]; - - local^.version_:=version; - local^.data_ :=value; - - Result:=0; -end; - -initialization - _pthread_keys_init; end. diff --git a/kernel/ps4_pthread_key.pas b/kernel/ps4_pthread_key.pas new file mode 100644 index 00000000..0f168851 --- /dev/null +++ b/kernel/ps4_pthread_key.pas @@ -0,0 +1,230 @@ +unit ps4_pthread_key; + +{$mode ObjFPC}{$H+} + +interface + +uses + LFQueue, + spinlock, + sys_kernel, + sys_pthread, + sys_signal; + +procedure _thread_cleanupspecific; + +function ps4_pthread_key_create(pKey:Ppthread_key_t;dest:t_cb_proc):Integer; SysV_ABI_CDecl; +function ps4_pthread_key_delete(Key:pthread_key_t):Integer; SysV_ABI_CDecl; +function ps4_pthread_getspecific(Key:pthread_key_t):Pointer; SysV_ABI_CDecl; +function ps4_pthread_setspecific(Key:pthread_key_t;value:Pointer):Integer; SysV_ABI_CDecl; + +//undefined8 pthread_get_specificarray_np(long param_1,undefined4 *param_2) + +function ps4_scePthreadKeyCreate(pKey:Ppthread_key_t;dest:t_cb_proc):Integer; SysV_ABI_CDecl; +function ps4_scePthreadKeyDelete(Key:pthread_key_t):Integer; SysV_ABI_CDecl; +function ps4_scePthreadGetspecific(Key:pthread_key_t):Pointer; SysV_ABI_CDecl; +function ps4_scePthreadSetspecific(Key:pthread_key_t;value:Pointer):Integer; SysV_ABI_CDecl; + +implementation + +type + p_pthread_key_node=^_pthread_key_node; + _pthread_key_node=packed record + next_:p_pthread_key_node; + version_:ptruint; + dest_:t_cb_proc; + end; + +var + _pthread_key_nodes:array[0..SCE_PTHREAD_KEYS_MAX-1] of _pthread_key_node; + _pthread_key_queue:TIntrusiveMPSCQueue; + _pthread_key_queue_lock:Pointer; + +procedure _pthread_keys_init; +var + i:Integer; +begin + _pthread_key_queue.Create; + For i:=Low(_pthread_key_nodes) to High(_pthread_key_nodes) do + begin + _pthread_key_nodes[i]:=Default(_pthread_key_node); + _pthread_key_queue.Push(@_pthread_key_nodes[i]); + end; +end; + +const + PTHREAD_DESTRUCTOR_ITERATIONS=4; + +procedure _thread_cleanupspecific; +var + i,k:Integer; + keys:p_pthread_key_data; + local:p_pthread_key_data; + + node:p_pthread_key_node; + version:ptruint; + dest:t_cb_proc; + + nofree:Boolean; +begin + keys:=tcb_thread^.specific; + if (keys=nil) then Exit; + + local:=@keys[0]; + + For i:=0 to PTHREAD_DESTRUCTOR_ITERATIONS-1 do + begin + nofree:=True; + For k:=Low(_pthread_key_nodes) to High(_pthread_key_nodes) do + begin + node:=@_pthread_key_nodes[k]; + + version:=load_consume(node^.version_); + dest:=t_cb_proc(load_consume(Pointer(node^.dest_))); + + if (ptruint(dest)>1) and + (local[k].version_=version) and + (local[k].data_<>nil) then + begin + dest(local[k].data_); + local[k].data_:=nil; + nofree:=False; + end; + end; + if nofree then Break; + end; + + tcb_thread^.specific:=nil; + SwFreeMem(keys); +end; + +function ps4_pthread_key_create(pKey:Ppthread_key_t;dest:t_cb_proc):Integer; SysV_ABI_CDecl; +var + node:p_pthread_key_node; + Key:pthread_key_t; +begin + if (pKey=nil) then Exit(EINVAL); + Writeln('pthread_key_create'); + + if (dest=nil) then dest:=t_cb_proc(1); + + node:=nil; + spin_lock(_pthread_key_queue_lock); + _pthread_key_queue.Pop(node); + spin_unlock(_pthread_key_queue_lock); + + if (node=nil) then Exit(EAGAIN); + + System.InterlockedIncrement(Pointer(node^.version_)); + XCHG(Pointer(node^.dest_),Pointer(dest)); + + Key:=(node-p_pthread_key_node(@_pthread_key_nodes)); + Key:=Key+1; + + pKey^:=Key; + Result:=0; +end; + +function ps4_pthread_key_delete(Key:pthread_key_t):Integer; SysV_ABI_CDecl; +var + node:p_pthread_key_node; +begin + Key:=Key-1; + + if (DWORD(Key)>SCE_PTHREAD_KEYS_MAX) then Exit(EINVAL); + Writeln('pthread_key_delete'); + + node:=@_pthread_key_nodes[Key]; + + if (XCHG(Pointer(node^.dest_),nil)=nil) then Exit(EINVAL); + + System.InterlockedIncrement(Pointer(node^.version_)); + + _pthread_key_queue.Push(node); +end; + +function ps4_pthread_getspecific(Key:pthread_key_t):Pointer; SysV_ABI_CDecl; +var + node:p_pthread_key_node; + version:ptruint; + keys:p_pthread_key_data; + local:p_pthread_key_data; +begin + Key:=Key-1; + + if (DWORD(Key)>=SCE_PTHREAD_KEYS_MAX) then Exit(nil); + + node:=@_pthread_key_nodes[Key]; + + version:=load_consume(node^.version_); + if (load_consume(Pointer(node^.dest_))=nil) then Exit(nil); + + keys:=tcb_thread^.specific; + if (keys=nil) then Exit(nil); + + local:=@keys[Key]; + + if (local^.version_<>version) then Exit(nil); + + Result:=local^.data_; +end; + +function ps4_pthread_setspecific(Key:pthread_key_t;value:Pointer):Integer; SysV_ABI_CDecl; +var + node:p_pthread_key_node; + version:ptruint; + keys:p_pthread_key_data; + local:p_pthread_key_data; +begin + Key:=Key-1; + + if (DWORD(Key)>=SCE_PTHREAD_KEYS_MAX) then Exit(EINVAL); + + node:=@_pthread_key_nodes[Key]; + + version:=load_consume(node^.version_); + if (load_consume(Pointer(node^.dest_))=nil) then Exit(EINVAL); + + keys:=tcb_thread^.specific; + if (keys=nil) then + begin + keys:=SwAllocMem(SizeOf(_pthread_keys)); + if (keys=nil) then Exit(ENOMEM); + tcb_thread^.specific:=keys; + end; + + local:=@keys[Key]; + + local^.version_:=version; + local^.data_ :=value; + + Result:=0; +end; + +//interface + +function ps4_scePthreadKeyCreate(pKey:Ppthread_key_t;dest:t_cb_proc):Integer; SysV_ABI_CDecl; +begin + Result:=px2sce(ps4_pthread_key_create(pKey,dest)); +end; + +function ps4_scePthreadKeyDelete(Key:pthread_key_t):Integer; SysV_ABI_CDecl; +begin + Result:=px2sce(ps4_pthread_key_delete(Key)); +end; + +function ps4_scePthreadGetspecific(Key:pthread_key_t):Pointer; SysV_ABI_CDecl; +begin + Result:=ps4_pthread_getspecific(Key); +end; + +function ps4_scePthreadSetspecific(Key:pthread_key_t;value:Pointer):Integer; SysV_ABI_CDecl; +begin + Result:=px2sce(ps4_pthread_setspecific(Key,value)); +end; + +initialization + _pthread_keys_init; + +end. + diff --git a/sys/sys_pthread.pas b/sys/sys_pthread.pas index 0e7a1d7b..d23af259 100644 --- a/sys/sys_pthread.pas +++ b/sys/sys_pthread.pas @@ -122,6 +122,8 @@ type data_:Pointer; end; + _pthread_keys=array[0..SCE_PTHREAD_KEYS_MAX-1] of _pthread_key_data; + t_init_routine_proc=procedure; SysV_ABI_CDecl; t_cb_proc=procedure(data:Pointer); SysV_ABI_CDecl; @@ -151,7 +153,7 @@ type // cleanup:p_pthread_cleanup; // - keys:array[0..SCE_PTHREAD_KEYS_MAX-1] of _pthread_key_data; + specific:p_pthread_key_data; // sig:sigqueue_t; end;