diff --git a/sys/kern/kern_id.pas b/sys/kern/kern_id.pas new file mode 100644 index 00000000..cd82effb --- /dev/null +++ b/sys/kern/kern_id.pas @@ -0,0 +1,215 @@ +unit kern_id; + +{$mode ObjFPC}{$H+} +{$CALLING SysV_ABI_CDecl} + +interface + +uses + hamt, + kern_rwlock; + +Const + def_max_key=$7FFFFFFF; + +type + p_id_desc=^t_id_desc; + t_id_desc=packed record + refs:QWORD; + free:procedure(data:pointer); + end; + + p_id_desc_table=^t_id_desc_table; + t_id_desc_table=packed record + FLock :Pointer; + FHAMT :TSTUB_HAMT32; + FCount :Integer; + FPos :Integer; + min_key:Integer; + max_key:Integer; + end; + +Procedure id_acqure (d:p_id_desc); +Procedure id_release(d:p_id_desc); + +procedure id_table_init(t:p_id_desc_table;min:Integer); +procedure id_table_fini(t:p_id_desc_table); + +function id_new(t:p_id_desc_table;d:p_id_desc;pKey:PInteger):Boolean; +function id_set(t:p_id_desc_table;d:p_id_desc;Key:Integer):Boolean; +function id_get(t:p_id_desc_table;Key:Integer):p_id_desc; +function id_del(t:p_id_desc_table;Key:Integer):Boolean; + +implementation + +Procedure id_acqure(d:p_id_desc); +begin + System.InterlockedIncrement64(d^.refs); +end; + +Procedure id_release(d:p_id_desc); +begin + if (System.InterlockedDecrement64(d^.refs)=0) then + if (d^.free<>nil) then + begin + d^.free(d); + end; +end; + +procedure _free_data_cb(data,userdata:Pointer); register; +begin + if (data<>nil) then + begin + id_release(data); + end; +end; + +procedure id_table_init(t:p_id_desc_table;min:Integer); +begin + if (t=nil) then Exit; + FillChar(t^,SizeOf(t_id_desc_table),0); + t^.min_key:=min; + t^.max_key:=def_max_key; + t^.FPos :=min; +end; + +procedure id_table_fini(t:p_id_desc_table); +begin + if (t=nil) then Exit; + HAMT_clear32(@t^.FHAMT,@_free_data_cb,nil); +end; + +function id_new(t:p_id_desc_table;d:p_id_desc;pKey:PInteger):Boolean; +Label + _data,_exit; +Var + i,m:Integer; + data:PPointer; +begin + Result:=False; + if (t=nil) or (d=nil) or (pKey=nil) then Exit; + + rw_wlock(t^.FLock); + + m:=(t^.max_key-t^.min_key); + if (t^.FCount>=m+1) then goto _exit; + + if (t^.FPost^.max_key) then + begin + t^.FPos:=t^.min_key; + end; + + if (t^.FCount=0) then + begin + pKey^:=t^.FPos; + Inc(t^.FPos); + + data:=HAMT_insert32(@t^.FHAMT,pKey^,Pointer(d)); + + if (data=nil) then goto _exit; + if (data^<>Pointer(d)) then goto _exit; + end else + begin + For i:=0 to m do + begin + pKey^:=t^.FPos; + Inc(t^.FPos); + + if (t^.FPos>t^.max_key) then + begin + t^.FPos:=t^.min_key; + end; + + data:=HAMT_insert32(@t^.FHAMT,pKey^,Pointer(d)); + + if (data=nil) then goto _exit; + if (data^=Pointer(d)) then goto _data; + end; + goto _exit; + end; + + _data: + Inc(t^.FCount); + id_acqure(d); + id_acqure(d); + + Result:=True; + + _exit: + rw_wunlock(t^.FLock); +end; + +function id_set(t:p_id_desc_table;d:p_id_desc;Key:Integer):Boolean; +Label + _exit; +Var + data:PPointer; +begin + Result:=False; + if (t=nil) or (d=nil) or (Keyt^.max_key) then Exit; + + rw_wlock(t^.FLock); + + data:=HAMT_insert32(@t^.FHAMT,Key,Pointer(d)); + + if (data=nil) then goto _exit; + if (data^<>Pointer(d)) then goto _exit; + + Inc(t^.FCount); + id_acqure(d); + id_acqure(d); + + Result:=True; + + _exit: + rw_wunlock(t^.FLock); +end; + +function id_get(t:p_id_desc_table;Key:Integer):p_id_desc; +Var + data:PPointer; +Label + _exit; +begin + Result:=nil; + if (t=nil) or (Keyt^.max_key) then Exit; + + rw_rlock(t^.FLock); + + data:=HAMT_search32(@t^.FHAMT,Key); + if (data=nil) then Goto _exit; + + Pointer(Result):=data^; + if (Result<>nil) then + begin + id_acqure(Result); + end; + + _exit: + rw_runlock(t^.FLock); +end; + +function id_del(t:p_id_desc_table;Key:Integer):Boolean; +Var + d:p_id_desc; +begin + Result:=False; + if (t=nil) or (Keyt^.max_key) then Exit; + + rw_wlock(t^.FLock); + + Pointer(d):=HAMT_delete32(@t^.FHAMT,Key); + + if (d<>nil) then + begin + id_release(d); + Dec(t^.FCount); + Result:=True; + end; + + rw_wunlock(t^.FLock); +end; + +end. + diff --git a/sys/kern/kern_osem.pas b/sys/kern/kern_osem.pas index 04ab2d41..6325883a 100644 --- a/sys/kern/kern_osem.pas +++ b/sys/kern/kern_osem.pas @@ -5,20 +5,36 @@ unit kern_osem; interface -uses - mqueue, - kern_mtx, - kern_thr, - kern_condvar; - const SEMA_ATTR_FIFO=$1; SEMA_ATTR_PRIO=$2; SEMA_ATTR_DELF=$1000; + SEMA_ATTR_SHRD=$1000; + +function sys_osem_create(name:PChar;attr:DWORD;initCount,maxCount:Integer):Integer; +function sys_osem_delete(key:Integer):Integer; +function sys_osem_cancel(key,setCount:Integer;pNumWait:PInteger):Integer; +function sys_osem_post(key,signalCount:Integer):Integer; +function sys_osem_trywait(key,needCount:Integer):Integer; +function sys_osem_wait(key,needCount:Integer;pTimeout:PDWORD):Integer; + +implementation + +uses + mqueue, + errno, + systm, + time, + kern_time, + kern_mtx, + kern_thr, + kern_condvar, + kern_id; type p_osem=^t_osem; t_osem=packed record + desc :t_id_desc; mtx :mtx; cv :t_cv; list :TAILQ_HEAD; @@ -27,6 +43,7 @@ type init_count:Integer; max_count :Integer; wait_count:Integer; + name :array[0..31] of Char; end; p_osem_node=^t_osem_node; @@ -37,15 +54,22 @@ type retval:Integer; end; -implementation +var + osem_table:t_id_desc_table; -uses - errno, - time, - kern_time; +function osem_alloc:p_osem; inline; +begin + Result:=AllocMem(SizeOf(t_osem)); +end; + +procedure osem_free(data:pointer); +begin + FreeMem(data); +end; function osem_init(sem:p_osem;attr:DWORD;initCount,max_count:Integer):Integer; begin + sem^.desc.free :=@osem_free; sem^.count :=initCount; sem^.init_count:=initCount; sem^.max_count :=max_count; @@ -237,7 +261,9 @@ begin begin if (needCount<=sem^.max_count) then begin - node.retval:=0; + node:=Default(t_osem_node); + node.td :=td; + node.count:=needCount; if ((sem^.attr and SEMA_ATTR_FIFO)=0) then begin //_PRIO @@ -262,8 +288,6 @@ begin sem^.list.tqh_last:=@node.entry.tqe_next; end; sem^.wait_count:=sem^.wait_count+1; - node.td:=td; - node.count:=needCount; if (timeout=nil) then begin Result:=_cv_wait_sig(@sem^.cv,@sem^.mtx); @@ -348,7 +372,164 @@ begin end; end; +// +function sys_osem_create(name:PChar;attr:DWORD;initCount,maxCount:Integer):Integer; +var + td:p_kthread; + _name:array[0..31] of Char; + sem:p_osem; + key:Integer; +begin + Result:=EINVAL; + td:=curkthread; + + if ((attr and $fffffefc)<>0) or ((attr and 3)=3) then Exit; + + //process shared osem not support + if ((attr and SEMA_ATTR_SHRD)<>0) then Exit(EPERM); + + if (initCount<0) or + (maxCount<=0) or + (initCount>maxCount) or + (name=nil) then Exit; + + if ((attr and 3)=0) then + begin + attr:=attr or 1; + end; + + FillChar(_name,32,0); + if (copyinstr(name,@_name,32,nil)<>0) then Exit; + + sem:=osem_alloc; + if (sem=nil) then Exit(ENOMEM); //EAGAIN + + osem_init(sem,attr,initCount,maxCount); + sem^.name:=_name; + + if not id_new(@osem_table,@sem^.desc,@key) then + begin + osem_free(sem); + Exit(EAGAIN); + end; + id_release(@sem^.desc); + + td^.td_retval[0]:=key; + + Result:=0; +end; + +function sys_osem_delete(key:Integer):Integer; +var + sem:p_osem; +begin + Result:=ESRCH; + + sem:=p_osem(id_get(@osem_table,key)); + if (sem=nil) then Exit; + + osem_delete(sem); + id_release(@sem^.desc); + + if not id_del(@osem_table,key) then Exit; + + Result:=0; +end; + +function sys_osem_cancel(key,setCount:Integer;pNumWait:PInteger):Integer; +var + sem:p_osem; + num:Integer; +begin + Result:=ESRCH; + num:=0; + + sem:=p_osem(id_get(@osem_table,key)); + if (sem=nil) then Exit; + + Result:=osem_cancel(sem,setCount,@num); + id_release(@sem^.desc); + + if (Result=0) then + begin + if (pNumWait<>nil) then + begin + Result:=copyout(@num,pNumWait,SizeOf(Integer)); + end; + end; +end; + +function sys_osem_post(key,signalCount:Integer):Integer; +var + sem:p_osem; +begin + Result:=EINVAL; + if (signalCount<=0) then Exit; + + Result:=ESRCH; + + sem:=p_osem(id_get(@osem_table,key)); + if (sem=nil) then Exit; + + Result:=osem_post(sem,signalCount); + id_release(@sem^.desc); +end; + +function sys_osem_trywait(key,needCount:Integer):Integer; +var + sem:p_osem; +begin + Result:=EINVAL; + if (needCount<=0) then Exit; + + Result:=ESRCH; + + sem:=p_osem(id_get(@osem_table,key)); + if (sem=nil) then Exit; + + Result:=osem_trywait(sem,needCount); + id_release(@sem^.desc); +end; + +function sys_osem_wait(key,needCount:Integer;pTimeout:PDWORD):Integer; +var + sem:p_osem; + timeout:PDWORD; + time:DWORD; +begin + Result:=EINVAL; + if (needCount<=0) then Exit; + + time:=0; + timeout:=nil; + + if (pTimeout<>nil) then + begin + Result:=copyin(pTimeout,@time,SizeOf(DWORD)); + if (Result<>0) then Exit; + timeout:=@time; + end; + + Result:=ESRCH; + + sem:=p_osem(id_get(@osem_table,key)); + if (sem=nil) then Exit; + + Result:=osem_wait(sem,needCount,timeout); + id_release(@sem^.desc); + + if (pTimeout<>nil) then + begin + Result:=copyout(@time,pTimeout,SizeOf(DWORD)); + end; +end; + +initialization + id_table_init(@osem_table,1); + +finalization + id_table_fini(@osem_table); end. diff --git a/sys/kern/machdep.pas b/sys/kern/machdep.pas index 8b959894..ba4ee962 100644 --- a/sys/kern/machdep.pas +++ b/sys/kern/machdep.pas @@ -17,6 +17,7 @@ const _ufssel =(2 shl 3) or 3; _ugssel =(3 shl 3) or 3; +procedure cpu_set_syscall_retval(td:p_kthread;error:Integer); procedure sendsig(catcher:sig_t;ksi:p_ksiginfo;mask:p_sigset_t); function sys_sigreturn(sigcntxp:p_ucontext_t):Integer; @@ -29,6 +30,33 @@ uses kern_sig, trap; +procedure cpu_set_syscall_retval(td:p_kthread;error:Integer); +begin + Case error of + 0:With td^.td_frame^ do + begin + tf_rax:=td^.td_retval[0]; + tf_rdx:=td^.td_retval[1]; + tf_rflags:=tf_rflags and (not PSL_C); + end; + ERESTART: + With td^.td_frame^ do + begin + //tf_err = size of syscall cmd + tf_rip:=tf_rip-td^.td_frame^.tf_err; + tf_r10:=tf_rcx; + set_pcb_flags(td,PCB_FULL_IRET); + end; + EJUSTRETURN:; //nothing + else + With td^.td_frame^ do + begin + tf_rax:=error; + tf_rflags:=tf_rflags or PSL_C; + end; + end; +end; + function get_fpcontext(td:p_kthread;mcp:p_mcontext_t;xstate:Pointer):Integer; begin Result:=0; diff --git a/sys/kern/trap.pas b/sys/kern/trap.pas index 1d8f8257..4c8704f5 100644 --- a/sys/kern/trap.pas +++ b/sys/kern/trap.pas @@ -233,6 +233,10 @@ begin td:=curkthread; td_frame:=td^.td_frame; + //cpu_fetch_syscall_args + td^.td_retval[0]:=0; + td^.td_retval[1]:=td_frame^.tf_rdx; + error:=0; if (td_frame^.tf_rax<>0) then begin diff --git a/sys/kern/vm_machdep.pas b/sys/kern/vm_machdep.pas index 7e9a2d8b..77f32ae3 100644 --- a/sys/kern/vm_machdep.pas +++ b/sys/kern/vm_machdep.pas @@ -18,7 +18,6 @@ var function cpu_thread_alloc(td:p_kthread):Integer; function cpu_thread_free(td:p_kthread):Integer; -procedure cpu_set_syscall_retval(td:p_kthread;error:Integer); function cpuset_setaffinity(td:p_kthread;new:Ptruint):Integer; function cpuset_setproc(new:Ptruint):Integer; function cpuset_getproc(var old:Ptruint):Integer; @@ -172,33 +171,6 @@ begin ); end; -procedure cpu_set_syscall_retval(td:p_kthread;error:Integer); -begin - Case error of - 0:With td^.td_frame^ do - begin - tf_rax:=td^.td_retval[0]; - tf_rdx:=td^.td_retval[1]; - tf_rflags:=tf_rflags and (not PSL_C); - end; - ERESTART: - With td^.td_frame^ do - begin - //tf_err = size of syscall cmd - tf_rip:=tf_rip-td^.td_frame^.tf_err; - tf_r10:=tf_rcx; - set_pcb_flags(td,PCB_FULL_IRET); - end; - EJUSTRETURN:; //nothing - else - With td^.td_frame^ do - begin - tf_rax:=error; - tf_rflags:=tf_rflags or PSL_C; - end; - end; -end; - function cpuset_setaffinity(td:p_kthread;new:Ptruint):Integer; begin td^.td_cpuset:=new; diff --git a/sys/sys_osem.pas b/sys/sys_osem.pas new file mode 100644 index 00000000..3944c760 --- /dev/null +++ b/sys/sys_osem.pas @@ -0,0 +1,59 @@ +unit sys_osem; + +{$mode ObjFPC}{$H+} +{$CALLING SysV_ABI_CDecl} + +interface + +function _osem_create_err(name:PChar;attr:DWORD;initCount,maxCount:Integer):Integer; +function _osem_delete_err(key:Integer):Integer; +function _osem_cancel_err(key,setCount:Integer;pNumWait:PInteger):Integer; +function _osem_post_err(key,signalCount:Integer):Integer; +function _osem_trywait_err(key,needCount:Integer):Integer; +function _osem_wait_err(key,needCount:Integer;pTimeout:PDWORD):Integer; + +implementation + +uses + kern_osem, + trap, + thr_error; + +function _osem_create_err(name:PChar;attr:DWORD;initCount,maxCount:Integer):Integer; assembler; nostackframe; +asm + movq sys_osem_create,%rax + call fast_syscall +end; + +function _osem_delete_err(key:Integer):Integer; assembler; nostackframe; +asm + movq sys_osem_delete,%rax + call fast_syscall +end; + +function _osem_cancel_err(key,setCount:Integer;pNumWait:PInteger):Integer; assembler; nostackframe; +asm + movq sys_osem_cancel,%rax + call fast_syscall +end; + +function _osem_post_err(key,signalCount:Integer):Integer; assembler; nostackframe; +asm + movq sys_osem_post,%rax + call fast_syscall +end; + +function _osem_trywait_err(key,needCount:Integer):Integer; assembler; nostackframe; +asm + movq sys_osem_trywait,%rax + call fast_syscall +end; + +function _osem_wait_err(key,needCount:Integer;pTimeout:PDWORD):Integer; assembler; nostackframe; +asm + movq sys_osem_wait,%rax + call fast_syscall +end; + +end. + diff --git a/sys/sys_umtx.pas b/sys/sys_umtx.pas index 4076db34..62865583 100644 --- a/sys/sys_umtx.pas +++ b/sys/sys_umtx.pas @@ -6,7 +6,6 @@ unit sys_umtx; interface uses - errno, time, _umtx; @@ -27,6 +26,7 @@ function _umtx_op_err(obj:Pointer;op:Integer;val:QWORD;uaddr1,uaddr2:Pointer):I implementation uses + errno, kern_umtx, trap, thr_error; diff --git a/sys/test/project1.lpi b/sys/test/project1.lpi index a1630ce6..2a98900b 100644 --- a/sys/test/project1.lpi +++ b/sys/test/project1.lpi @@ -185,6 +185,14 @@ + + + + + + + + diff --git a/sys/test/project1.lpr b/sys/test/project1.lpr index 2cb5c35b..29c7f2ec 100644 --- a/sys/test/project1.lpr +++ b/sys/test/project1.lpr @@ -28,7 +28,9 @@ uses kern_thr, rtprio, kern_condvar, - kern_osem; + kern_osem, + kern_id, + sys_osem; var mtx:umutex;