mirror of https://github.com/red-prig/fpPS4.git
This commit is contained in:
parent
114689e7f8
commit
0c6088b809
|
@ -95,6 +95,9 @@ procedure _libpthread_init(curthread:p_pthread);
|
|||
|
||||
implementation
|
||||
|
||||
uses
|
||||
sys_mmap;
|
||||
|
||||
const
|
||||
g_user_stacksize=$10000;
|
||||
|
||||
|
@ -147,12 +150,12 @@ begin
|
|||
|
||||
thread^.attr:=_pthread_attr_default;
|
||||
|
||||
//ret:=mmap(_usrstack-_thr_guard_default-_thr_stack_initial)),
|
||||
// _thr_guard_default,0,$1000,-1,0); //MAP_ANON
|
||||
ret:=mmap(_usrstack-_thr_guard_default-_thr_stack_initial,_thr_guard_default,0,MAP_ANON,-1,0);
|
||||
|
||||
if (ret=Pointer(-1)) then //MAP_FAILED
|
||||
if (ret=MAP_FAILED) then
|
||||
begin
|
||||
Assert(false,'Cannot allocate red zone for initial thread');
|
||||
Exit;
|
||||
end;
|
||||
thread^.attr.stackaddr_attr:=(_usrstack-_thr_stack_initial);
|
||||
thread^.attr.stacksize_attr:=_thr_stack_initial;
|
||||
|
|
177
rtl/atomic.pas
177
rtl/atomic.pas
|
@ -35,93 +35,63 @@ Const
|
|||
|
||||
function load_consume(Var addr:Pointer):Pointer; inline;
|
||||
function load_consume(Var addr:SizeUInt):SizeUInt; inline;
|
||||
{$IF defined(CPUX86_64)}
|
||||
function load_consume(Var addr:DWORD):DWORD; inline;
|
||||
{$ENDIF}
|
||||
|
||||
function load_acquire(Var addr:Pointer):Pointer; inline;
|
||||
function load_acquire(Var addr:SizeUInt):SizeUInt; inline;
|
||||
{$IF defined(CPUX86_64)}
|
||||
function load_acquire(Var addr:DWORD):DWORD; inline;
|
||||
{$ENDIF}
|
||||
|
||||
function load_acq_rel(Var addr:Pointer):Pointer; inline;
|
||||
function load_acq_rel(Var addr:SizeUInt):SizeUInt; inline;
|
||||
{$IF defined(CPUX86_64)}
|
||||
function load_acq_rel(Var addr:DWORD):DWORD; inline;
|
||||
function load_acq_rel(Var addr:Integer):Integer; inline;
|
||||
{$ENDIF}
|
||||
|
||||
Procedure store_release(Var addr:Pointer;v:Pointer); inline;
|
||||
Procedure store_release(Var addr:SizeUInt;v:SizeUInt); inline;
|
||||
{$IF defined(CPUX86_64)}
|
||||
Procedure store_release(Var addr:DWORD;v:DWORD); inline;
|
||||
Procedure store_release(Var addr:Integer;v:Integer); inline;
|
||||
{$ENDIF}
|
||||
|
||||
Procedure store_seq_cst(Var addr:Pointer;v:Pointer); inline;
|
||||
Procedure store_seq_cst(Var addr:SizeUInt;v:SizeUInt); inline;
|
||||
{$IF defined(CPUX86_64)}
|
||||
Procedure store_seq_cst(Var addr:DWORD;v:DWORD); inline;
|
||||
Procedure store_seq_cst(Var addr:Integer;v:Integer); inline;
|
||||
{$ENDIF}
|
||||
|
||||
function _CAS(Var addr:Pointer;Comp,New:Pointer):Pointer; inline;
|
||||
function _CAS(Var addr:SizeUInt;Comp,New:SizeUInt):SizeUInt; inline;
|
||||
{$IF defined(CPUX86_64)}
|
||||
function _CAS(Var addr:DWORD;Comp,New:DWORD):DWORD; inline;
|
||||
{$ENDIF}
|
||||
|
||||
function CAS(Var addr:Pointer;Comp,New:Pointer):Boolean; inline;
|
||||
function CAS(Var addr:SizeUInt;Comp,New:SizeUInt):Boolean; inline;
|
||||
{$IF defined(CPUX86_64)}
|
||||
function CAS(Var addr:DWORD;Comp,New:DWORD):Boolean; inline;
|
||||
function CAS(Var addr:Integer;Comp,New:Integer):Boolean; inline;
|
||||
{$ENDIF}
|
||||
|
||||
function XCHG(Var addr:Pointer;New:Pointer):Pointer; inline;
|
||||
function XCHG(Var addr:SizeUInt;New:SizeUInt):SizeUInt; inline;
|
||||
{$IF defined(CPUX86_64)}
|
||||
function XCHG(Var addr:DWORD;New:DWORD):DWORD; inline;
|
||||
function XCHG(Var addr:Integer;New:Integer):Integer; inline;
|
||||
{$ENDIF}
|
||||
|
||||
function fetch_add(Var addr:SizeUInt;i:SizeUInt):SizeUInt; inline;
|
||||
{$IF defined(CPUX86_64)}
|
||||
function fetch_add(Var addr:DWORD;i:DWORD):DWORD; inline;
|
||||
function fetch_add(Var addr:Integer;i:Integer):Integer; inline;
|
||||
{$ENDIF}
|
||||
|
||||
function fetch_sub(Var addr:SizeUInt;i:SizeUInt):SizeUInt; inline;
|
||||
{$IF defined(CPUX86_64)}
|
||||
function fetch_sub(Var addr:DWORD;i:DWORD):DWORD; inline;
|
||||
function fetch_sub(Var addr:Integer;i:Integer):Integer; inline;
|
||||
{$ENDIF}
|
||||
|
||||
function fetch_xor(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default;
|
||||
{$IFDEF CPUX86_64}
|
||||
function fetch_xor(var Target:DWORD;mask:DWORD):Boolean; ms_abi_default;
|
||||
{$ENDIF}
|
||||
|
||||
function fetch_or(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default;
|
||||
{$IFDEF CPUX86_64}
|
||||
function fetch_or(var Target:DWORD;mask:DWORD):Boolean; ms_abi_default;
|
||||
{$ENDIF}
|
||||
|
||||
function fetch_and(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default;
|
||||
{$IFDEF CPUX86_64}
|
||||
function fetch_and(var Target:DWORD;mask:DWORD):Boolean; ms_abi_default;
|
||||
{$ENDIF}
|
||||
|
||||
function test_and_set(var Target:SizeUInt;bit:byte):Boolean; ms_abi_default;
|
||||
{$IFDEF CPUX86_64}
|
||||
function test_and_set(var Target:DWORD;bit:byte):Boolean; ms_abi_default;
|
||||
{$ENDIF}
|
||||
function test_and_set(var Target:DWORD;bit:byte):Boolean; ms_abi_default;
|
||||
|
||||
function test_and_reset(var Target:qword;bit:byte):Boolean; ms_abi_default;
|
||||
{$IFDEF CPUX86_64}
|
||||
function test_and_reset(var Target:DWORD;bit:byte):Boolean; ms_abi_default;
|
||||
{$ENDIF}
|
||||
|
||||
function marked_ptr(P:Pointer;B:SizeUInt=0):Pointer; inline;
|
||||
function ptr1(P:Pointer):Pointer; inline;
|
||||
|
@ -129,6 +99,9 @@ function bits1(P:Pointer):SizeUInt; inline;
|
|||
function bits1(P:SizeUInt):SizeUInt; inline;
|
||||
procedure spin_pause;
|
||||
|
||||
procedure atomic_set_int (addr:PInteger;val:Integer); sysv_abi_default;
|
||||
procedure atomic_clear_int(addr:PInteger;val:Integer); sysv_abi_default;
|
||||
|
||||
implementation
|
||||
|
||||
function load_consume(Var addr:Pointer):Pointer; inline;
|
||||
|
@ -143,13 +116,11 @@ begin
|
|||
Result:=addr;
|
||||
end;
|
||||
|
||||
{$IF defined(CPUX86_64)}
|
||||
function load_consume(Var addr:DWORD):DWORD; inline;
|
||||
begin
|
||||
ReadDependencyBarrier;
|
||||
Result:=addr;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function load_acquire(Var addr:Pointer):Pointer; inline;
|
||||
begin
|
||||
|
@ -163,13 +134,11 @@ begin
|
|||
Result:=addr;
|
||||
end;
|
||||
|
||||
{$IF defined(CPUX86_64)}
|
||||
function load_acquire(Var addr:DWORD):DWORD; inline;
|
||||
begin
|
||||
ReadBarrier;
|
||||
Result:=addr;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function load_acq_rel(Var addr:Pointer):Pointer; inline;
|
||||
begin
|
||||
|
@ -181,7 +150,6 @@ begin
|
|||
Result:=SizeUInt(load_acq_rel(Pointer(addr)));
|
||||
end;
|
||||
|
||||
{$IF defined(CPUX86_64)}
|
||||
function load_acq_rel(Var addr:DWORD):DWORD; inline;
|
||||
begin
|
||||
Result:=System.InterLockedExchangeAdd(addr,0);
|
||||
|
@ -191,7 +159,6 @@ function load_acq_rel(Var addr:Integer):Integer; inline;
|
|||
begin
|
||||
Result:=System.InterLockedExchangeAdd(addr,0);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
Procedure store_release(Var addr:Pointer;v:Pointer); inline;
|
||||
begin
|
||||
|
@ -205,7 +172,6 @@ begin
|
|||
addr:=v;
|
||||
end;
|
||||
|
||||
{$IF defined(CPUX86_64)}
|
||||
Procedure store_release(Var addr:DWORD;v:DWORD); inline;
|
||||
begin
|
||||
WriteBarrier;
|
||||
|
@ -217,7 +183,6 @@ begin
|
|||
WriteBarrier;
|
||||
addr:=v;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
Procedure store_seq_cst(Var addr:Pointer;v:Pointer); inline;
|
||||
begin
|
||||
|
@ -229,7 +194,6 @@ begin
|
|||
store_seq_cst(Pointer(addr),Pointer(v));
|
||||
end;
|
||||
|
||||
{$IF defined(CPUX86_64)}
|
||||
Procedure store_seq_cst(Var addr:DWORD;v:DWORD); inline;
|
||||
begin
|
||||
System.InterLockedExchange(addr,v);
|
||||
|
@ -239,7 +203,6 @@ Procedure store_seq_cst(Var addr:Integer;v:Integer); inline;
|
|||
begin
|
||||
System.InterLockedExchange(addr,v);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function _CAS(Var addr:Pointer;Comp,New:Pointer):Pointer; inline;
|
||||
begin
|
||||
|
@ -251,7 +214,6 @@ begin
|
|||
Result:=SizeUInt(system.InterlockedCompareExchange(Pointer(addr),Pointer(New),Pointer(Comp)));
|
||||
end;
|
||||
|
||||
{$IF defined(CPUX86_64)}
|
||||
function _CAS(Var addr:DWORD;Comp,New:DWORD):DWORD; inline;
|
||||
begin
|
||||
Result:=system.InterlockedCompareExchange(addr,New,Comp);
|
||||
|
@ -261,7 +223,6 @@ function _CAS(Var addr:Integer;Comp,New:Integer):Integer; inline;
|
|||
begin
|
||||
Result:=system.InterlockedCompareExchange(addr,New,Comp);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function CAS(Var addr:Pointer;Comp,New:Pointer):Boolean; inline;
|
||||
begin
|
||||
|
@ -273,7 +234,6 @@ begin
|
|||
Result:=system.InterlockedCompareExchange(Pointer(addr),Pointer(New),Pointer(Comp))=Pointer(Comp);
|
||||
end;
|
||||
|
||||
{$IF defined(CPUX86_64)}
|
||||
function CAS(Var addr:DWORD;Comp,New:DWORD):Boolean; inline;
|
||||
begin
|
||||
Result:=system.InterlockedCompareExchange(addr,New,Comp)=Comp;
|
||||
|
@ -283,7 +243,6 @@ function CAS(Var addr:Integer;Comp,New:Integer):Boolean; inline;
|
|||
begin
|
||||
Result:=system.InterlockedCompareExchange(addr,New,Comp)=Comp;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function XCHG(Var addr:Pointer;New:Pointer):Pointer; inline;
|
||||
begin
|
||||
|
@ -295,7 +254,6 @@ begin
|
|||
Result:=SizeUInt(System.InterLockedExchange(Pointer(addr),Pointer(New)));
|
||||
end;
|
||||
|
||||
{$IF defined(CPUX86_64)}
|
||||
function XCHG(Var addr:DWORD;New:DWORD):DWORD; inline;
|
||||
begin
|
||||
Result:=System.InterLockedExchange(addr,New);
|
||||
|
@ -305,14 +263,12 @@ function XCHG(Var addr:Integer;New:Integer):Integer; inline;
|
|||
begin
|
||||
Result:=System.InterLockedExchange(addr,New);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function fetch_add(Var addr:SizeUInt;i:SizeUInt):SizeUInt; inline;
|
||||
begin
|
||||
Result:=SizeUInt(System.InterLockedExchangeAdd(Pointer(addr),Pointer(i)));
|
||||
end;
|
||||
|
||||
{$IF defined(CPUX86_64)}
|
||||
function fetch_add(Var addr:DWORD;i:DWORD):DWORD; inline;
|
||||
begin
|
||||
Result:=System.InterLockedExchangeAdd(addr,i);
|
||||
|
@ -322,14 +278,12 @@ function fetch_add(Var addr:Integer;i:Integer):Integer; inline;
|
|||
begin
|
||||
Result:=System.InterLockedExchangeAdd(addr,i);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function fetch_sub(Var addr:SizeUInt;i:SizeUInt):SizeUInt; inline;
|
||||
begin
|
||||
Result:=fetch_add(addr,SizeUInt(-SizeInt(i)));
|
||||
end;
|
||||
|
||||
{$IF defined(CPUX86_64)}
|
||||
function fetch_sub(Var addr:DWORD;i:DWORD):DWORD; inline;
|
||||
begin
|
||||
Result:=fetch_add(addr,DWORD(-Integer(i)));
|
||||
|
@ -339,18 +293,9 @@ function fetch_sub(Var addr:Integer;i:Integer):Integer; inline;
|
|||
begin
|
||||
Result:=fetch_add(addr,-i);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
//xor
|
||||
|
||||
{$IFDEF CPU386}
|
||||
function fetch_xor(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default; assembler; nostackframe;
|
||||
asm
|
||||
lock xor %edx,(%ecx)
|
||||
setz %al
|
||||
end;
|
||||
{$ELSE}
|
||||
{$IFDEF CPUX86_64}
|
||||
function fetch_xor(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default; assembler; nostackframe;
|
||||
asm
|
||||
lock xor %rdx,(%rcx)
|
||||
|
@ -362,30 +307,9 @@ asm
|
|||
lock xor %edx,(%rcx)
|
||||
setz %al
|
||||
end;
|
||||
{$ELSE}
|
||||
function fetch_xor(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default;
|
||||
Var
|
||||
P,N:SizeUInt;
|
||||
begin
|
||||
repeat
|
||||
P:=load_consume(Target);
|
||||
N:=P xor mask;
|
||||
until CAS(Target,P,N);
|
||||
Result:=(N=0);
|
||||
end;
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
|
||||
//or
|
||||
|
||||
{$IFDEF CPU386}
|
||||
function fetch_or(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default; assembler; nostackframe;
|
||||
asm
|
||||
lock or %edx,(%ecx)
|
||||
setz %al
|
||||
end;
|
||||
{$ELSE}
|
||||
{$IFDEF CPUX86_64}
|
||||
function fetch_or(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default; assembler; nostackframe;
|
||||
asm
|
||||
lock or %rdx,(%rcx)
|
||||
|
@ -397,30 +321,9 @@ asm
|
|||
lock or %edx,(%rcx)
|
||||
setz %al
|
||||
end;
|
||||
{$ELSE}
|
||||
function fetch_or(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default;
|
||||
Var
|
||||
P,N:SizeUInt;
|
||||
begin
|
||||
repeat
|
||||
P:=load_consume(Target);
|
||||
N:=P or mask;
|
||||
until CAS(Target,P,N);
|
||||
Result:=(N=0);
|
||||
end;
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
|
||||
//and
|
||||
|
||||
{$IFDEF CPU386}
|
||||
function fetch_and(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default; assembler; nostackframe;
|
||||
asm
|
||||
lock and %edx,(%ecx)
|
||||
setz %al
|
||||
end;
|
||||
{$ELSE}
|
||||
{$IFDEF CPUX86_64}
|
||||
function fetch_and(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default; assembler; nostackframe;
|
||||
asm
|
||||
lock and %rdx,(%rcx)
|
||||
|
@ -432,30 +335,9 @@ asm
|
|||
lock and %edx,(%rcx)
|
||||
setz %al
|
||||
end;
|
||||
{$ELSE}
|
||||
function fetch_and(var Target:SizeUInt;mask:SizeUInt):Boolean; ms_abi_default;
|
||||
Var
|
||||
P,N:SizeUInt;
|
||||
begin
|
||||
repeat
|
||||
P:=load_consume(Target);
|
||||
N:=P and mask;
|
||||
until CAS(Target,P,N);
|
||||
Result:=(N=0);
|
||||
end;
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
|
||||
//bts
|
||||
|
||||
{$IFDEF CPU386}
|
||||
function test_and_set(var Target:SizeUInt;bit:byte):Boolean; ms_abi_default; assembler; nostackframe;
|
||||
asm
|
||||
lock bts %edx,(%ecx)
|
||||
setc %al
|
||||
end;
|
||||
{$ELSE}
|
||||
{$IFDEF CPUX86_64}
|
||||
function test_and_set(var Target:SizeUInt;bit:byte):Boolean; ms_abi_default; assembler; nostackframe;
|
||||
asm
|
||||
lock bts %rdx,(%rcx)
|
||||
|
@ -467,31 +349,9 @@ asm
|
|||
lock bts %edx,(%rcx)
|
||||
setc %al
|
||||
end;
|
||||
{$ELSE}
|
||||
function test_and_set(var Target:SizeUInt;bit:byte):Boolean; ms_abi_default;
|
||||
Var
|
||||
P,N,M:SizeUInt;
|
||||
begin
|
||||
M:=1 shl bit;
|
||||
repeat
|
||||
P:=load_consume(Target);
|
||||
N:=P or M;
|
||||
until CAS(Target,P,N);
|
||||
Result:=(P and M)<>0;
|
||||
end;
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
|
||||
//btr
|
||||
|
||||
{$IFDEF CPU386}
|
||||
function test_and_reset(var Target:qword;bit:byte):Boolean; ms_abi_default; assembler; nostackframe;
|
||||
asm
|
||||
lock btr %edx,(%ecx)
|
||||
setc %al
|
||||
end;
|
||||
{$ELSE}
|
||||
{$IFDEF CPUX86_64}
|
||||
function test_and_reset(var Target:qword;bit:byte):Boolean; ms_abi_default; assembler; nostackframe;
|
||||
asm
|
||||
lock btr %rdx,(%rcx)
|
||||
|
@ -503,20 +363,6 @@ asm
|
|||
lock btr %edx,(%rcx)
|
||||
setc %al
|
||||
end;
|
||||
{$ELSE}
|
||||
function test_and_reset(var Target:SizeUInt;bit:byte):Boolean; ms_abi_default;
|
||||
Var
|
||||
P,N,M:SizeUInt;
|
||||
begin
|
||||
M:=not (1 shl bit);
|
||||
repeat
|
||||
P:=load_consume(Target);
|
||||
N:=P and M;
|
||||
until CAS(Target,P,N);
|
||||
Result:=(P and M)<>0;
|
||||
end;
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
|
||||
function marked_ptr(P:Pointer;B:SizeUInt=0):Pointer; inline;
|
||||
begin
|
||||
|
@ -538,16 +384,21 @@ begin
|
|||
Result:=SizeUInt(P) and SizeUInt(1);
|
||||
end;
|
||||
|
||||
{$if defined(CPU386) or defined(CPUX86_64)}
|
||||
procedure spin_pause; assembler; nostackframe;
|
||||
asm
|
||||
pause
|
||||
end;
|
||||
{$ELSE}
|
||||
procedure spin_pause; inline;
|
||||
begin
|
||||
|
||||
procedure atomic_set_int(addr:PInteger;val:Integer); assembler; nostackframe; sysv_abi_default;
|
||||
asm
|
||||
lock orl %esi,(%rdi)
|
||||
end;
|
||||
|
||||
procedure atomic_clear_int(addr:PInteger;val:Integer); assembler; nostackframe; sysv_abi_default;
|
||||
asm
|
||||
not %esi
|
||||
lock andl %esi,(%rdi)
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
end.
|
||||
|
||||
|
|
123
rtl/mqueue.pas
123
rtl/mqueue.pas
|
@ -24,6 +24,23 @@ type
|
|||
le_prev:PPointer;
|
||||
end;
|
||||
|
||||
P_STAILQ_HEAD=^STAILQ_HEAD;
|
||||
STAILQ_HEAD=packed record
|
||||
stqh_first:Pointer;
|
||||
stqh_last :PPointer;
|
||||
end;
|
||||
|
||||
P_STAILQ_ENTRY=^STAILQ_ENTRY;
|
||||
STAILQ_ENTRY=packed record
|
||||
stqe_next:Pointer;
|
||||
end;
|
||||
|
||||
|
||||
P_SLIST_ENTRY=^SLIST_ENTRY;
|
||||
SLIST_ENTRY=packed record
|
||||
sle_next:Pointer;
|
||||
end;
|
||||
|
||||
procedure TAILQ_INIT (head:Pointer); inline;
|
||||
function TAILQ_EMPTY (head:Pointer):Boolean; inline;
|
||||
function TAILQ_FIRST (head:Pointer):Pointer; inline;
|
||||
|
@ -42,6 +59,17 @@ function LIST_NEXT (elm,field:Pointer):Pointer; inline;
|
|||
procedure LIST_INSERT_HEAD (head,elm,field:Pointer); inline;
|
||||
procedure LIST_REMOVE (elm,field:Pointer); inline;
|
||||
|
||||
procedure STAILQ_INIT(head:Pointer); inline;
|
||||
function STAILQ_EMPTY(head:Pointer):Boolean; inline;
|
||||
function STAILQ_FIRST(head:Pointer):Pointer; inline;
|
||||
function STAILQ_NEXT(elm,field:Pointer):Pointer; inline;
|
||||
procedure STAILQ_INSERT_AFTER(head,tqelm,elm,field:Pointer); inline;
|
||||
procedure STAILQ_INSERT_HEAD(head,elm,field:Pointer); inline;
|
||||
procedure STAILQ_INSERT_TAIL(head,elm,field:Pointer); inline;
|
||||
procedure STAILQ_REMOVE_AFTER(head,elm,field:Pointer); inline;
|
||||
procedure STAILQ_REMOVE_HEAD(head,elm,field:Pointer); inline;
|
||||
procedure STAILQ_REMOVE(head,elm,field:Pointer); inline;
|
||||
|
||||
implementation
|
||||
|
||||
procedure TAILQ_INIT(head:Pointer); inline;
|
||||
|
@ -187,6 +215,101 @@ end;
|
|||
|
||||
//
|
||||
|
||||
procedure STAILQ_INIT(head:Pointer); inline;
|
||||
begin
|
||||
P_STAILQ_HEAD(head)^.stqh_first:=nil;
|
||||
P_STAILQ_HEAD(head)^.stqh_last :=@P_STAILQ_HEAD(head)^.stqh_first;
|
||||
end;
|
||||
|
||||
function STAILQ_EMPTY(head:Pointer):Boolean; inline;
|
||||
begin
|
||||
Result:=P_STAILQ_HEAD(head)^.stqh_first=nil;
|
||||
end;
|
||||
|
||||
function STAILQ_FIRST(head:Pointer):Pointer; inline;
|
||||
begin
|
||||
Result:=P_STAILQ_HEAD(head)^.stqh_first;
|
||||
end;
|
||||
|
||||
function STAILQ_NEXT(elm,field:Pointer):Pointer; inline;
|
||||
begin
|
||||
Result:=P_STAILQ_ENTRY(field)^.stqe_next;
|
||||
end;
|
||||
|
||||
procedure STAILQ_INSERT_AFTER(head,tqelm,elm,field:Pointer); inline;
|
||||
var
|
||||
offset:ptruint;
|
||||
begin
|
||||
offset:=ptruint(field-elm);
|
||||
P_STAILQ_ENTRY(field)^.stqe_next:=P_STAILQ_ENTRY(tqelm+offset)^.stqe_next;
|
||||
if (P_STAILQ_ENTRY(field)^.stqe_next=nil) then
|
||||
begin
|
||||
P_STAILQ_HEAD(head)^.stqh_last:=@P_STAILQ_ENTRY(field)^.stqe_next;
|
||||
end;
|
||||
P_STAILQ_ENTRY(tqelm+offset)^.stqe_next:=elm;
|
||||
end;
|
||||
|
||||
procedure STAILQ_INSERT_HEAD(head,elm,field:Pointer); inline;
|
||||
begin
|
||||
P_STAILQ_ENTRY(field)^.stqe_next:=P_STAILQ_HEAD(head)^.stqh_first;
|
||||
if (P_STAILQ_HEAD(head)^.stqh_first=nil) then
|
||||
begin
|
||||
P_STAILQ_HEAD(head)^.stqh_last:=@P_STAILQ_ENTRY(field)^.stqe_next;
|
||||
end;
|
||||
P_STAILQ_HEAD(head)^.stqh_first:=elm;
|
||||
end;
|
||||
|
||||
procedure STAILQ_INSERT_TAIL(head,elm,field:Pointer); inline;
|
||||
begin
|
||||
P_STAILQ_ENTRY(field)^.stqe_next:=nil;
|
||||
P_STAILQ_HEAD(head)^.stqh_last^:=elm;
|
||||
P_STAILQ_HEAD(head)^.stqh_last:=@P_STAILQ_ENTRY(field)^.stqe_next;
|
||||
end;
|
||||
|
||||
procedure STAILQ_REMOVE_AFTER(head,elm,field:Pointer); inline;
|
||||
var
|
||||
offset:ptruint;
|
||||
begin
|
||||
offset:=ptruint(field-elm);
|
||||
P_STAILQ_ENTRY(field)^.stqe_next:=P_STAILQ_ENTRY(P_STAILQ_ENTRY(field)^.stqe_next+offset)^.stqe_next;
|
||||
if (P_STAILQ_ENTRY(field)^.stqe_next=nil) then
|
||||
begin
|
||||
P_STAILQ_HEAD(head)^.stqh_last:=@P_STAILQ_ENTRY(field)^.stqe_next;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure STAILQ_REMOVE_HEAD(head,elm,field:Pointer); inline;
|
||||
var
|
||||
offset:ptruint;
|
||||
begin
|
||||
offset:=ptruint(field-elm);
|
||||
P_STAILQ_HEAD(head)^.stqh_first:=P_STAILQ_ENTRY(P_STAILQ_HEAD(head)^.stqh_first+offset)^.stqe_next;
|
||||
if (P_STAILQ_HEAD(head)^.stqh_first=nil) then
|
||||
begin
|
||||
P_STAILQ_HEAD(head)^.stqh_last:=@P_STAILQ_HEAD(head)^.stqh_first;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure STAILQ_REMOVE(head,elm,field:Pointer); inline;
|
||||
var
|
||||
offset:ptruint;
|
||||
curelm:Pointer;
|
||||
begin
|
||||
if (P_STAILQ_HEAD(head)^.stqh_first=elm) then
|
||||
begin
|
||||
STAILQ_REMOVE_HEAD(head,elm,field);
|
||||
end else
|
||||
begin
|
||||
offset:=ptruint(field-elm);
|
||||
curelm:=P_STAILQ_HEAD(head)^.stqh_first;
|
||||
while (P_STAILQ_ENTRY(curelm+offset)^.stqe_next<>elm) do
|
||||
begin
|
||||
curelm:=P_STAILQ_ENTRY(curelm+offset)^.stqe_next;
|
||||
end;
|
||||
STAILQ_REMOVE_AFTER(head,curelm,curelm+offset);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ type
|
|||
t_cv=packed record
|
||||
cv_description:Pchar;
|
||||
cv_waiters :Integer;
|
||||
_align :Integer;
|
||||
end;
|
||||
|
||||
procedure cv_init(cvp:p_cv;desc:Pchar);
|
||||
|
|
|
@ -51,6 +51,7 @@ type
|
|||
bitPattern:QWORD;
|
||||
mtx :mtx;
|
||||
cv :t_cv;
|
||||
_align :Integer;
|
||||
list :TAILQ_HEAD;
|
||||
attr :DWORD;
|
||||
wait_count:Integer;
|
||||
|
@ -84,7 +85,7 @@ function evf_init(evf:p_evf;attr:DWORD;initPattern:QWORD):Integer;
|
|||
begin
|
||||
evf^.desc.free:=@evf_free;
|
||||
evf^.bitPattern:=initPattern;
|
||||
mtx_init(evf^.mtx);
|
||||
mtx_init(evf^.mtx,'evf mtx');
|
||||
cv_init(@evf^.cv,'evf cv');
|
||||
TAILQ_INIT(@evf^.list);
|
||||
evf^.wait_count:=0;
|
||||
|
|
|
@ -7,7 +7,10 @@ interface
|
|||
|
||||
type
|
||||
p_mtx=^mtx;
|
||||
mtx=TRTLCriticalSection;
|
||||
mtx=packed record
|
||||
n:PChar;
|
||||
c:TRTLCriticalSection;
|
||||
end;
|
||||
|
||||
const
|
||||
//Flags for lockinit().
|
||||
|
@ -41,7 +44,7 @@ const
|
|||
|
||||
LK_TOTAL_MASK=(LK_INIT_MASK or LK_EATTR_MASK or LK_TYPE_MASK);
|
||||
|
||||
procedure mtx_init (var m:mtx);
|
||||
procedure mtx_init (var m:mtx;name:PChar);
|
||||
procedure mtx_destroy(var m:mtx);
|
||||
procedure mtx_lock (var m:mtx);
|
||||
function mtx_trylock(var m:mtx):Boolean;
|
||||
|
@ -51,34 +54,35 @@ procedure mtx_assert (var m:mtx);
|
|||
|
||||
implementation
|
||||
|
||||
procedure mtx_init(var m:mtx); inline;
|
||||
procedure mtx_init(var m:mtx;name:PChar); inline;
|
||||
begin
|
||||
InitCriticalSection(m);
|
||||
m.n:=name;
|
||||
InitCriticalSection(m.c);
|
||||
end;
|
||||
|
||||
procedure mtx_destroy(var m:mtx); inline;
|
||||
begin
|
||||
DoneCriticalSection(m);
|
||||
DoneCriticalSection(m.c);
|
||||
end;
|
||||
|
||||
procedure mtx_lock(var m:mtx); inline;
|
||||
begin
|
||||
EnterCriticalSection(m);
|
||||
EnterCriticalSection(m.c);
|
||||
end;
|
||||
|
||||
function mtx_trylock(var m:mtx):Boolean; inline;
|
||||
begin
|
||||
Result:=TryEnterCriticalSection(m)<>0;
|
||||
Result:=TryEnterCriticalSection(m.c)<>0;
|
||||
end;
|
||||
|
||||
procedure mtx_unlock(var m:mtx); inline;
|
||||
begin
|
||||
LeaveCriticalSection(m);
|
||||
LeaveCriticalSection(m.c);
|
||||
end;
|
||||
|
||||
function mtx_owned(var m:mtx):Boolean; inline;
|
||||
begin
|
||||
Result:=m.OwningThread=GetCurrentThreadId;
|
||||
Result:=m.c.OwningThread=GetCurrentThreadId;
|
||||
end;
|
||||
|
||||
procedure mtx_assert(var m:mtx); inline;
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
unit kern_mtxpool;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
{$CALLING SysV_ABI_CDecl}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
kern_mtx;
|
||||
|
||||
const
|
||||
{ Pool sizes must be a power of two }
|
||||
MTX_POOL_LOCKBUILDER_SIZE=128;
|
||||
MTX_POOL_SLEEP_SIZE =128;
|
||||
|
||||
type
|
||||
mtxpool_header=packed record
|
||||
mtxpool_size :Integer;
|
||||
mtxpool_mask :Integer;
|
||||
mtxpool_shift:Integer;
|
||||
mtxpool_next :Integer;
|
||||
end;
|
||||
|
||||
pp_mtx_pool=^p_mtx_pool;
|
||||
p_mtx_pool=^mtx_pool;
|
||||
mtx_pool=packed object
|
||||
mtx_pool_header:mtxpool_header;
|
||||
mtx_pool_ary :array[0..0] of mtx;
|
||||
property mtx_pool_size :Integer read mtx_pool_header.mtxpool_size write mtx_pool_header.mtxpool_size ;
|
||||
property mtx_pool_mask :Integer read mtx_pool_header.mtxpool_mask write mtx_pool_header.mtxpool_mask ;
|
||||
property mtx_pool_shift:Integer read mtx_pool_header.mtxpool_shift write mtx_pool_header.mtxpool_shift;
|
||||
property mtx_pool_next :Integer read mtx_pool_header.mtxpool_next write mtx_pool_header.mtxpool_next ;
|
||||
end;
|
||||
|
||||
mtx_pool_lockbuilder=packed record
|
||||
mtx_pool_header:mtxpool_header;
|
||||
mtx_pool_ary :array[0..MTX_POOL_LOCKBUILDER_SIZE-1] of mtx;
|
||||
end;
|
||||
|
||||
function mtx_pool_find(pool:p_mtx_pool;ptr:Pointer):p_mtx;
|
||||
procedure mtx_pool_initialize(pool:p_mtx_pool;mtx_name:PChar;pool_size:Integer);
|
||||
function mtx_pool_create(mtx_name:PChar;pool_size:Integer):p_mtx_pool;
|
||||
procedure mtx_pool_destroy(poolp:pp_mtx_pool);
|
||||
function mtx_pool_alloc(pool:p_mtx_pool):p_mtx;
|
||||
|
||||
implementation
|
||||
|
||||
const
|
||||
POINTER_BITS =64;
|
||||
HASH_MULTIPLIER=11400714819323198485; { (2^64)*(sqrt(5)-1)/2 }
|
||||
|
||||
{
|
||||
* Exitthe (shared) pool mutex associated with the specified address.
|
||||
* The returned mutex is a leaf level mutex, meaning that if you obtain it
|
||||
* you cannot obtain any other mutexes until you release it. You can
|
||||
* legally msleep() on the mutex.
|
||||
}
|
||||
function mtx_pool_find(pool:p_mtx_pool;ptr:Pointer):p_mtx;
|
||||
var
|
||||
p:Integer;
|
||||
begin
|
||||
Assert(pool<>nil, ('_mtx_pool_find(): nil pool'));
|
||||
{
|
||||
* Fibonacci hash, see Knuth's
|
||||
* _Art of Computer Programming, Volume 3 / Sorting and Searching_
|
||||
}
|
||||
p:=((HASH_MULTIPLIER * ptruint(ptr)) shr pool^.mtx_pool_shift) and pool^.mtx_pool_mask;
|
||||
Exit(@pool^.mtx_pool_ary[p]);
|
||||
end;
|
||||
|
||||
procedure mtx_pool_initialize(pool:p_mtx_pool;mtx_name:PChar;pool_size:Integer);
|
||||
var
|
||||
i,maskbits:Integer;
|
||||
begin
|
||||
pool^.mtx_pool_size:=pool_size;
|
||||
pool^.mtx_pool_mask:=pool_size - 1;
|
||||
i:=1;
|
||||
maskbits:=0;
|
||||
while ((i and pool_size)=0) do
|
||||
begin
|
||||
Inc(maskbits);
|
||||
i:=i shl 1;
|
||||
end;
|
||||
pool^.mtx_pool_shift:=POINTER_BITS - maskbits;
|
||||
pool^.mtx_pool_next:=0;
|
||||
For i:=0 to pool_size-1 do
|
||||
mtx_init(pool^.mtx_pool_ary[i], mtx_name);
|
||||
end;
|
||||
|
||||
function powerof2(i:DWord):Boolean; inline;
|
||||
begin
|
||||
Result:=popcnt(i)=1;
|
||||
end;
|
||||
|
||||
function mtx_pool_create(mtx_name:PChar;pool_size:Integer):p_mtx_pool;
|
||||
var
|
||||
pool:p_mtx_pool;
|
||||
begin
|
||||
if (pool_size <= 0) or (not powerof2(pool_size)) then
|
||||
begin
|
||||
Writeln('WARNING: %s pool size is not a power of 2.', mtx_name);
|
||||
pool_size:=128;
|
||||
end;
|
||||
pool:=AllocMem(sizeof(mtx_pool)+
|
||||
((pool_size - 1) * sizeof(mtx))
|
||||
);
|
||||
mtx_pool_initialize(pool, mtx_name, pool_size);
|
||||
Exit(pool);
|
||||
end;
|
||||
|
||||
procedure mtx_pool_destroy(poolp:pp_mtx_pool);
|
||||
var
|
||||
i:Integer;
|
||||
pool:p_mtx_pool;
|
||||
begin
|
||||
pool:=poolp^;
|
||||
|
||||
For i:=(pool^.mtx_pool_size-1) downto 0 do
|
||||
begin
|
||||
mtx_destroy(pool^.mtx_pool_ary[i]);
|
||||
end;
|
||||
|
||||
FreeMem(pool);
|
||||
poolp^:=nil;
|
||||
end;
|
||||
|
||||
{
|
||||
* Obtain a (shared) mutex from the pool. The returned mutex is a leaf
|
||||
* level mutex, meaning that if you obtain it you cannot obtain any other
|
||||
* mutexes until you release it. You can legally msleep() on the mutex.
|
||||
}
|
||||
function mtx_pool_alloc(pool:p_mtx_pool):p_mtx;
|
||||
var
|
||||
i:Integer;
|
||||
begin
|
||||
Assert(pool<>nil, ('mtx_pool_alloc(): nil pool'));
|
||||
{
|
||||
* mtx_pool_next is unprotected against multiple accesses,
|
||||
* but simultaneous access by two CPUs should not be very
|
||||
* harmful.
|
||||
}
|
||||
i:=pool^.mtx_pool_next;
|
||||
pool^.mtx_pool_next:=(i + 1) and pool^.mtx_pool_mask;
|
||||
Exit(@pool^.mtx_pool_ary[i]);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
|
@ -39,6 +39,7 @@ type
|
|||
desc :t_id_desc;
|
||||
mtx :mtx;
|
||||
cv :t_cv;
|
||||
_align :Integer;
|
||||
list :TAILQ_HEAD;
|
||||
count :Integer;
|
||||
attr :DWORD;
|
||||
|
@ -76,7 +77,7 @@ begin
|
|||
sem^.count :=initCount;
|
||||
sem^.init_count:=initCount;
|
||||
sem^.max_count :=max_count;
|
||||
mtx_init(sem^.mtx);
|
||||
mtx_init(sem^.mtx,'osem mtx');
|
||||
cv_init(@sem^.cv,'osem cv');
|
||||
TAILQ_INIT(@sem^.list);
|
||||
sem^.wait_count:=0;
|
||||
|
|
|
@ -652,7 +652,7 @@ procedure siginit;
|
|||
var
|
||||
i:Integer;
|
||||
begin
|
||||
mtx_init(p_sigacts.ps_mtx);
|
||||
mtx_init(p_sigacts.ps_mtx,'sigacts');
|
||||
|
||||
For i:=1 to NSIG do
|
||||
begin
|
||||
|
|
|
@ -150,6 +150,7 @@ type
|
|||
td_timeo :Int64;
|
||||
//
|
||||
td_map_def_user :Pointer;
|
||||
td_sel :Pointer;
|
||||
end;
|
||||
|
||||
p_thr_param=^thr_param;
|
||||
|
@ -399,7 +400,7 @@ begin
|
|||
end;
|
||||
|
||||
initialization
|
||||
mtx_init(p_mtx);
|
||||
mtx_init(p_mtx,'process lock');
|
||||
|
||||
end.
|
||||
|
||||
|
|
|
@ -10,8 +10,13 @@ uses
|
|||
ntapi,
|
||||
time;
|
||||
|
||||
procedure timevalfix(t1:ptimeval);
|
||||
procedure timevaladd(t1,t2:ptimeval);
|
||||
procedure timevalsub(t1,t2:ptimeval);
|
||||
|
||||
function cputick2usec(time:QWORD):QWORD; inline;
|
||||
function get_unit_uptime:Int64;
|
||||
procedure getmicrouptime(tvp:ptimeval);
|
||||
procedure getnanotime(tp:Ptimespec);
|
||||
|
||||
function kern_clock_gettime_unit(clock_id:Integer;time:PInt64):Integer;
|
||||
|
@ -33,6 +38,34 @@ Const
|
|||
POW10_7 =10000000;
|
||||
POW10_9 =1000000000;
|
||||
|
||||
procedure timevalfix(t1:ptimeval);
|
||||
begin
|
||||
if (t1^.tv_usec < 0) then
|
||||
begin
|
||||
Dec(t1^.tv_sec);
|
||||
Inc(t1^.tv_usec,1000000);
|
||||
end;
|
||||
if (t1^.tv_usec >= 1000000) then
|
||||
begin
|
||||
Inc(t1^.tv_sec);
|
||||
Dec(t1^.tv_usec,1000000);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure timevaladd(t1,t2:ptimeval);
|
||||
begin
|
||||
Inc(t1^.tv_sec ,t2^.tv_sec);
|
||||
Inc(t1^.tv_usec,t2^.tv_usec);
|
||||
timevalfix(t1);
|
||||
end;
|
||||
|
||||
procedure timevalsub(t1,t2:ptimeval);
|
||||
begin
|
||||
Dec(t1^.tv_sec ,t2^.tv_sec);
|
||||
Dec(t1^.tv_usec,t2^.tv_usec);
|
||||
timevalfix(t1);
|
||||
end;
|
||||
|
||||
function cputick2usec(time:QWORD):QWORD; inline;
|
||||
begin
|
||||
Result:=time div 10;
|
||||
|
@ -63,6 +96,15 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
procedure getmicrouptime(tvp:ptimeval);
|
||||
var
|
||||
time:Int64;
|
||||
begin
|
||||
time:=get_unit_uptime;
|
||||
tvp^.tv_sec :=(time div POW10_7);
|
||||
tvp^.tv_usec:=(time mod POW10_7) div 10;
|
||||
end;
|
||||
|
||||
type
|
||||
tunittime=procedure(time:PInt64); stdcall;
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ var
|
|||
begin
|
||||
For i:=0 to SC_MASK do
|
||||
begin
|
||||
mtx_init(sleepq_chains[i].sc_lock);
|
||||
mtx_init(sleepq_chains[i].sc_lock,'sleepq chain');
|
||||
end;
|
||||
end;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ const
|
|||
function copyin(udaddr,kaddr:Pointer;len:ptruint):Integer; inline;
|
||||
function copyinstr(udaddr,kaddr:Pointer;len:ptruint;lencopied:pptruint):Integer;
|
||||
function copyout(kaddr,udaddr:Pointer;len:ptruint):Integer; inline;
|
||||
function fubyte(var base:Byte):Byte; inline;
|
||||
function fuword32(var base:DWORD):DWORD; inline;
|
||||
function fuword64(var base:QWORD):QWORD; inline;
|
||||
function casuword32(var base:DWORD;oldval,newval:DWORD):DWORD; inline;
|
||||
|
@ -72,6 +73,14 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
function fubyte(var base:Byte):Byte; inline;
|
||||
begin
|
||||
if (NtReadVirtualMemory(NtCurrentProcess,@base,@Result,SizeOf(Byte),nil)<>0) then
|
||||
begin
|
||||
Result:=BYTE(-1);
|
||||
end;
|
||||
end;
|
||||
|
||||
function fuword32(var base:DWORD):DWORD; inline;
|
||||
begin
|
||||
if (NtReadVirtualMemory(NtCurrentProcess,@base,@Result,SizeOf(DWORD),nil)<>0) then
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
unit signal;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
{$CALLING SysV_ABI_CDecl}
|
||||
|
||||
interface
|
||||
|
||||
|
|
|
@ -349,6 +349,46 @@
|
|||
<Filename Value="..\vfs\vdisk.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="..\vfs\vsys_generic.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="..\kern\kern_mtxpool.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="..\vfs\vselinfo.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="..\vfs\vioccom.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="..\vfs\vpoll.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="..\vfs\vselect.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="..\vfs\vsocket.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="..\vfs\vsocketvar.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="..\vfs\vsockstate.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="..\vfs\vsockbuf.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
|
|
|
@ -44,7 +44,10 @@ uses
|
|||
vfs_mount,
|
||||
vfs_default,
|
||||
sysent,
|
||||
vfs_syscalls;
|
||||
vfs_syscalls,
|
||||
vsys_generic,
|
||||
vsocket,
|
||||
vsocketvar;
|
||||
|
||||
var
|
||||
mtx:umutex;
|
||||
|
|
73
sys/time.pas
73
sys/time.pas
|
@ -54,27 +54,75 @@ type
|
|||
tz_dstsec :DWORD;
|
||||
end;
|
||||
|
||||
const
|
||||
tick=100;
|
||||
hz=10000000;
|
||||
|
||||
function _usec2msec(usec:QWORD):QWORD; //Microsecond to Milisecond
|
||||
function _msec2usec(msec:QWORD):QWORD; //Milisecond to Microsecond
|
||||
function _usec2nsec(usec:QWORD):QWORD; //Microsecond to Nanosecond
|
||||
function _nsec2usec(nsec:QWORD):QWORD; //Nanosecond to Microsecond
|
||||
function _msec2nsec(msec:QWORD):QWORD; //Milisecond to Nanosecond
|
||||
function _nsec2msec(nsec:QWORD):QWORD; //Nanosecond to Milisecond
|
||||
|
||||
function timespeccmp_lt(tvp,uvp:ptimespec):Integer; inline;
|
||||
|
||||
procedure TIMEVAL_TO_TIMESPEC(tv:ptimeval;ts:ptimespec); inline;
|
||||
procedure TIMESPEC_TO_TIMEVAL(tv:ptimeval;ts:ptimespec); inline;
|
||||
|
||||
function TIMESPEC_TO_UNIT(ts:ptimespec):Int64; inline; //Unit
|
||||
function TIMEVAL_TO_UNIT (tv:ptimeval ):Int64; inline; //Unit
|
||||
function USEC_TO_UNIT (usec:QWORD ):Int64; inline; //Unit
|
||||
|
||||
function tvtohz(time:Int64):Int64; inline;
|
||||
procedure usec2timespec(ts:ptimespec;timeo:DWORD);
|
||||
|
||||
procedure TIMESPEC_ADD(dst,src,val:ptimespec);
|
||||
procedure TIMESPEC_SUB(dst,src,val:ptimespec);
|
||||
|
||||
function itimerfix(tv:ptimeval):Integer;
|
||||
|
||||
function clock_gettime(clock_id:Integer;tp:Ptimespec):Integer;
|
||||
function clock_getres(clock_id:Integer;tp:Ptimespec):Integer;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
errno,
|
||||
trap,
|
||||
thr_error,
|
||||
kern_time;
|
||||
|
||||
function _usec2msec(usec:QWORD):QWORD; //Microsecond to Milisecond
|
||||
begin
|
||||
Result:=(usec+999) div 1000;
|
||||
end;
|
||||
|
||||
function _msec2usec(msec:QWORD):QWORD; //Milisecond to Microsecond
|
||||
begin
|
||||
Result:=msec*1000;
|
||||
end;
|
||||
|
||||
function _usec2nsec(usec:QWORD):QWORD; //Microsecond to Nanosecond
|
||||
begin
|
||||
Result:=usec*1000;
|
||||
end;
|
||||
|
||||
function _nsec2usec(nsec:QWORD):QWORD; //Nanosecond to Microsecond
|
||||
begin
|
||||
Result:=(nsec+999) div 1000;
|
||||
end;
|
||||
|
||||
function _msec2nsec(msec:QWORD):QWORD; //Milisecond to Nanosecond
|
||||
begin
|
||||
Result:=msec*1000000;
|
||||
end;
|
||||
|
||||
function _nsec2msec(nsec:QWORD):QWORD; //Nanosecond to Milisecond
|
||||
begin
|
||||
Result:=(nsec+999999) div 1000000;
|
||||
end;
|
||||
|
||||
function timespeccmp_lt(tvp,uvp:ptimespec):Integer; inline;
|
||||
begin
|
||||
if (tvp^.tv_sec=uvp^.tv_sec) then
|
||||
|
@ -103,6 +151,16 @@ begin
|
|||
Result:=(QWORD(ts^.tv_sec)*10000000)+(QWORD(ts^.tv_nsec) div 100);
|
||||
end;
|
||||
|
||||
function TIMEVAL_TO_UNIT(tv:ptimeval):Int64; inline; //Unit
|
||||
begin
|
||||
Result:=(QWORD(tv^.tv_sec)*10000000)+(QWORD(tv^.tv_usec)*10);
|
||||
end;
|
||||
|
||||
function USEC_TO_UNIT(usec:QWORD):Int64; inline; //Unit
|
||||
begin
|
||||
Result:=(usec*10);
|
||||
end;
|
||||
|
||||
function tvtohz(time:Int64):Int64; inline;
|
||||
begin
|
||||
Result:=time;
|
||||
|
@ -136,6 +194,21 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
{
|
||||
* Check that a proposed value to load into the .it_value or
|
||||
* .it_interval part of an interval timer is acceptable, and
|
||||
* fix it to have at least minimal value (i.e. if it is less
|
||||
* than the resolution of the clock, round it up.)
|
||||
}
|
||||
function itimerfix(tv:ptimeval):Integer;
|
||||
begin
|
||||
if (tv^.tv_sec < 0) or (tv^.tv_usec < 0) or (tv^.tv_usec >= 1000000) then
|
||||
Exit(EINVAL);
|
||||
if (tv^.tv_sec=0) and (tv^.tv_usec<>0) and (tv^.tv_usec < tick) then
|
||||
tv^.tv_usec:=tick;
|
||||
Exit(0);
|
||||
end;
|
||||
|
||||
function clock_gettime(clock_id:Integer;tp:Ptimespec):Integer; assembler; nostackframe;
|
||||
asm
|
||||
movq sys_clock_gettime,%rax
|
||||
|
|
|
@ -15,7 +15,8 @@ uses
|
|||
vfcntl,
|
||||
vfilio,
|
||||
vmount,
|
||||
vfs_vnode;
|
||||
vfs_vnode,
|
||||
vsocketvar;
|
||||
|
||||
const
|
||||
FGET_GETCAP=$00000001;
|
||||
|
@ -80,22 +81,22 @@ function fgetvp_write(fd:Integer;
|
|||
|
||||
function fgetsock(fd:Integer;
|
||||
rights:cap_rights_t;
|
||||
spp:PPointer; //socket **
|
||||
spp:pp_socket;
|
||||
fflagp:PDWORD):Integer;
|
||||
|
||||
procedure fdclose(fp:p_file;idx:Integer);
|
||||
function dupfdopen(indx,dfd,mode,error:Integer):Integer;
|
||||
procedure finit(fp:p_file;flag:DWORD;_type:Word;data:Pointer;ops:p_fileops);
|
||||
|
||||
function badfo_readwrite(fp:p_file;uio:p_uio;flags:Integer):Integer;
|
||||
function badfo_truncate(fp:p_file;length:Int64):Integer;
|
||||
function badfo_ioctl(fp:p_file;com:QWORD;data:Pointer):Integer;
|
||||
function badfo_poll(fp:p_file;events:Integer):Integer;
|
||||
function badfo_kqfilter(fp:p_file;kn:Pointer):Integer;
|
||||
function badfo_stat(fp:p_file;sb:p_stat):Integer;
|
||||
function badfo_close(fp:p_file):Integer;
|
||||
function badfo_chmod(fp:p_file;mode:mode_t):Integer;
|
||||
function badfo_chown(fp:p_file;uid:uid_t;gid:gid_t):Integer;
|
||||
function badfo_readwrite(fp:p_file;uio:p_uio;flags:Integer):Integer;
|
||||
function badfo_truncate(fp:p_file;length:Int64):Integer;
|
||||
function badfo_ioctl(fp:p_file;com:QWORD;data:Pointer):Integer;
|
||||
function badfo_poll(fp:p_file;events:Integer):Integer;
|
||||
function badfo_kqfilter(fp:p_file;kn:Pointer):Integer;
|
||||
function badfo_stat(fp:p_file;sb:p_stat):Integer;
|
||||
function badfo_close(fp:p_file):Integer;
|
||||
function badfo_chmod(fp:p_file;mode:mode_t):Integer;
|
||||
function badfo_chown(fp:p_file;uid:uid_t;gid:gid_t):Integer;
|
||||
|
||||
const
|
||||
badfileops:fileops=(
|
||||
|
@ -117,12 +118,10 @@ var
|
|||
p_flag:Integer;
|
||||
end;
|
||||
|
||||
procedure atomic_set_int(addr:PInteger;val:Integer); sysv_abi_default;
|
||||
procedure atomic_clear_int(addr:PInteger;val:Integer); sysv_abi_default;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
atomic,
|
||||
errno,
|
||||
systm,
|
||||
vfiledesc,
|
||||
|
@ -304,17 +303,6 @@ begin
|
|||
Exit(0);
|
||||
end;
|
||||
|
||||
procedure atomic_set_int(addr:PInteger;val:Integer); assembler; nostackframe; sysv_abi_default;
|
||||
asm
|
||||
lock orl %esi,(%rdi)
|
||||
end;
|
||||
|
||||
procedure atomic_clear_int(addr:PInteger;val:Integer); assembler; nostackframe; sysv_abi_default;
|
||||
asm
|
||||
not %esi
|
||||
lock andl %esi,(%rdi)
|
||||
end;
|
||||
|
||||
function kern_fcntl(fd,cmd:Integer;arg:QWORD):Integer;
|
||||
label
|
||||
_break,
|
||||
|
@ -391,10 +379,10 @@ begin
|
|||
end;
|
||||
if ((arg and FD_CLOEXEC)<>0) then
|
||||
begin
|
||||
fp^.f_exclose:=fp^.f_exclose or UF_EXCLOSE;
|
||||
atomic_set_int(@fp^.f_exclose,UF_EXCLOSE);
|
||||
end else
|
||||
begin
|
||||
fp^.f_exclose:=(fp^.f_exclose and (not UF_EXCLOSE));
|
||||
atomic_clear_int(@fp^.f_exclose,UF_EXCLOSE);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -724,7 +712,7 @@ begin
|
|||
begin
|
||||
Exit(EBADF);
|
||||
end;
|
||||
fp^.f_exclose:=fp^.f_exclose or UF_EXCLOSE;
|
||||
atomic_set_int(@fp^.f_exclose,UF_EXCLOSE);
|
||||
fdrop(fp);
|
||||
end;
|
||||
Exit(0);
|
||||
|
@ -1194,7 +1182,7 @@ begin
|
|||
|
||||
if ((flags and O_CLOEXEC)<>0) then
|
||||
begin
|
||||
fp^.f_exclose:=fp^.f_exclose or UF_EXCLOSE;
|
||||
atomic_set_int(@fp^.f_exclose,UF_EXCLOSE);
|
||||
end;
|
||||
|
||||
Exit(0);
|
||||
|
@ -1490,7 +1478,7 @@ end;
|
|||
}
|
||||
function fgetsock(fd:Integer;
|
||||
rights:cap_rights_t;
|
||||
spp:PPointer; //socket **
|
||||
spp:pp_socket;
|
||||
fflagp:PDWORD):Integer;
|
||||
var
|
||||
fp:p_file;
|
||||
|
@ -1510,9 +1498,9 @@ begin
|
|||
spp^:=fp^.f_data;
|
||||
if (fflagp<>nil) then
|
||||
fflagp^:=fp^.f_flag;
|
||||
//SOCK_LOCK(spp^);
|
||||
//soref(spp^);
|
||||
//SOCK_UNLOCK(spp^);
|
||||
SOCK_LOCK(spp^);
|
||||
soref(spp^);
|
||||
SOCK_UNLOCK(spp^);
|
||||
end;
|
||||
fdrop(fp);
|
||||
|
||||
|
|
|
@ -14,8 +14,13 @@ function uiomove(cp:Pointer;n:Integer;uio:p_uio):Integer;
|
|||
function uiomove_nofault(cp:Pointer;n:Integer;uio:p_uio):Integer;
|
||||
function uiomove_faultflag(cp:Pointer;n:Integer;uio:p_uio;nofault:Integer):Integer;
|
||||
|
||||
function copyinuio(iovp:p_iovec;iovcnt:DWORD;uiop:pp_uio):Integer;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
errno;
|
||||
|
||||
function uiomove(cp:Pointer;n:Integer;uio:p_uio):Integer;
|
||||
begin
|
||||
Exit(uiomove_faultflag(cp, n, uio, 0));
|
||||
|
@ -101,5 +106,45 @@ _out:
|
|||
Exit(error);
|
||||
end;
|
||||
|
||||
function copyinuio(iovp:p_iovec;iovcnt:DWORD;uiop:pp_uio):Integer;
|
||||
var
|
||||
iov:p_iovec;
|
||||
uio:p_uio;
|
||||
iovlen:DWORD;
|
||||
error,i:Integer;
|
||||
begin
|
||||
uiop^:=nil;
|
||||
if (iovcnt > UIO_MAXIOV) then
|
||||
Exit(EINVAL);
|
||||
iovlen:=iovcnt * sizeof (iovec);
|
||||
uio:=AllocMem(iovlen + sizeof(t_uio));
|
||||
iov:=p_iovec(uio + 1);
|
||||
error:=copyin(iovp, iov, iovlen);
|
||||
if (error<>0) then
|
||||
begin
|
||||
FreeMem(uio);
|
||||
Exit(error);
|
||||
end;
|
||||
uio^.uio_iov :=iov;
|
||||
uio^.uio_iovcnt:=iovcnt;
|
||||
uio^.uio_segflg:=UIO_USERSPACE;
|
||||
uio^.uio_offset:=-1;
|
||||
uio^.uio_resid :=0;
|
||||
|
||||
For i:=0 to iovcnt-1 do
|
||||
begin
|
||||
if (iov^.iov_len > IOSIZE_MAX - uio^.uio_resid) then
|
||||
begin
|
||||
FreeMem(uio);
|
||||
Exit(EINVAL);
|
||||
end;
|
||||
Inc(uio^.uio_resid,iov^.iov_len);
|
||||
Inc(iov);
|
||||
end;
|
||||
|
||||
uiop^:=uio;
|
||||
Exit(0);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
|
|
@ -16,10 +16,11 @@ uses
|
|||
vfs_mount,
|
||||
vnamei,
|
||||
vfcntl,
|
||||
vpoll,
|
||||
vsocketvar,
|
||||
kern_thr,
|
||||
kern_mtx;
|
||||
|
||||
|
||||
function vop_eopnotsupp(ap:Pointer):Integer;
|
||||
function vop_ebadf(ap:Pointer):Integer;
|
||||
function vop_enotty(ap:Pointer):Integer;
|
||||
|
@ -176,7 +177,8 @@ uses
|
|||
errno,
|
||||
vfs_subr,
|
||||
vfs_vnops,
|
||||
vfs_lookup;
|
||||
vfs_lookup,
|
||||
vsys_generic;
|
||||
|
||||
{
|
||||
* Series of placeholder functions for various error returns for
|
||||
|
@ -564,8 +566,7 @@ end;
|
|||
}
|
||||
function vop_nopoll(ap:p_vop_poll_args):Integer;
|
||||
begin
|
||||
Exit(EOPNOTSUPP);
|
||||
//Exit(poll_no_poll(ap^.a_events));
|
||||
Exit(poll_no_poll(ap^.a_events));
|
||||
end;
|
||||
|
||||
{
|
||||
|
@ -573,10 +574,9 @@ end;
|
|||
}
|
||||
function vop_stdpoll(ap:p_vop_poll_args):Integer;
|
||||
begin
|
||||
Exit(EOPNOTSUPP);
|
||||
//if ((ap^.a_events and (not POLLSTANDARD))<>0) then
|
||||
// Exit(vn_pollrecord(ap^.a_vp, ap^.a_td, ap^.a_events));
|
||||
//Exit(ap^.a_events and (POLLIN or POLLOUT or POLLRDNORM or POLLWRNORM));
|
||||
if ((ap^.a_events and (not POLLSTANDARD))<>0) then
|
||||
Exit(vn_pollrecord(ap^.a_vp, ap^.a_events));
|
||||
Exit(ap^.a_events and (POLLIN or POLLOUT or POLLRDNORM or POLLWRNORM));
|
||||
end;
|
||||
|
||||
{
|
||||
|
@ -1064,7 +1064,7 @@ end;
|
|||
|
||||
function vop_stdunp_connect(ap:p_vop_unp_connect_args):Integer;
|
||||
begin
|
||||
//ap^.a_socket^:=ap^.a_vp^.v_socket;
|
||||
ap^.a_socket^:=ap^.a_vp^.v_socket;
|
||||
Exit(0);
|
||||
end;
|
||||
|
||||
|
@ -1127,14 +1127,12 @@ label
|
|||
loop;
|
||||
var
|
||||
vp,mvp:p_vnode;
|
||||
td:p_kthread;
|
||||
error,lockreq,allerror:Integer;
|
||||
begin
|
||||
error:=0;
|
||||
lockreq:=0;
|
||||
allerror:=0;
|
||||
|
||||
td:=curkthread;
|
||||
lockreq:=LK_EXCLUSIVE or LK_INTERLOCK;
|
||||
if (waitfor<>MNT_WAIT) then
|
||||
lockreq:=lockreq or LK_NOWAIT;
|
||||
|
|
|
@ -41,8 +41,8 @@ end;
|
|||
|
||||
procedure mount_init(mp:p_mount);
|
||||
begin
|
||||
mtx_init(mp^.mnt_mtx);
|
||||
mtx_init(mp^.mnt_explock);
|
||||
mtx_init(mp^.mnt_mtx ,'struct mount mtx');
|
||||
mtx_init(mp^.mnt_explock,'explock');
|
||||
end;
|
||||
|
||||
procedure mount_fini(mp:p_mount);
|
||||
|
|
|
@ -46,6 +46,17 @@ procedure assert_vop_elocked (vp:p_vnode;str:PChar);
|
|||
|
||||
procedure vop_rename_fail(ap:p_vop_rename_args);
|
||||
procedure vop_rename_pre(ap:p_vop_rename_args);
|
||||
procedure vop_create_post(ap:p_vop_create_args;rc:Integer);
|
||||
procedure vop_deleteextattr_post(ap:p_vop_deleteextattr_args;rc:Integer);
|
||||
procedure vop_link_post(ap:p_vop_link_args;rc:Integer);
|
||||
procedure vop_mkdir_post(ap:p_vop_mkdir_args;rc:Integer);
|
||||
procedure vop_mknod_post(ap:p_vop_mknod_args;rc:Integer);
|
||||
procedure vop_remove_post(ap:p_vop_remove_args;rc:Integer);
|
||||
procedure vop_rename_post(ap:p_vop_rename_args;rc:Integer);
|
||||
procedure vop_rmdir_post(ap:p_vop_rmdir_args;rc:Integer);
|
||||
procedure vop_setattr_post(ap:p_vop_setattr_args;rc:Integer);
|
||||
procedure vop_setextattr_post(ap:p_vop_setextattr_args;rc:Integer);
|
||||
procedure vop_symlink_post(ap:p_vop_symlink_args;rc:Integer);
|
||||
|
||||
function vfs_read_dirent(ap:p_vop_readdir_args;dp:p_dirent;off:QWORD):Integer;
|
||||
procedure vfs_mark_atime(vp:p_vnode);
|
||||
|
@ -56,6 +67,11 @@ function count_dev(dev:Pointer):Integer; //cdev
|
|||
|
||||
procedure vfs_msync(mp:p_mount;flags:Integer);
|
||||
|
||||
procedure destroy_vpollinfo_free(vi:p_vpollinfo);
|
||||
procedure destroy_vpollinfo(vi:p_vpollinfo);
|
||||
procedure v_addpollinfo(vp:p_vnode);
|
||||
function vn_pollrecord(vp:p_vnode;events:Integer):Integer;
|
||||
|
||||
function __mnt_vnode_next_all(mvp:pp_vnode;mp:p_mount):p_vnode;
|
||||
function __mnt_vnode_first_all(mvp:pp_vnode;mp:p_mount):p_vnode;
|
||||
procedure __mnt_vnode_markerfree_all(mvp:pp_vnode;mp:p_mount);
|
||||
|
@ -66,7 +82,8 @@ uses
|
|||
errno,
|
||||
vfs_vnops,
|
||||
subr_uio,
|
||||
vm_object;
|
||||
vm_object,
|
||||
vsys_generic;
|
||||
|
||||
{
|
||||
* List of vnodes that are ready for recycling.
|
||||
|
@ -155,16 +172,16 @@ begin
|
|||
desiredvnodes:=MAXVNODES_MAX;
|
||||
end;
|
||||
wantfreevnodes:=desiredvnodes div 4;
|
||||
mtx_init(mntid_mtx);
|
||||
mtx_init(mntid_mtx,'mntid');
|
||||
TAILQ_INIT(@vnode_free_list);
|
||||
mtx_init(vnode_free_list_mtx);
|
||||
mtx_init(vnode_free_list_mtx,'vnode_free_list');
|
||||
{
|
||||
* Initialize the filesystem syncer.
|
||||
}
|
||||
//syncer_workitem_pending[WI_MPSAFEQ]:=hashinit(syncer_maxdelay, M_VNODE,&syncer_mask);
|
||||
//syncer_workitem_pending[WI_GIANTQ]:=hashinit(syncer_maxdelay, M_VNODE,&syncer_mask);
|
||||
syncer_maxdelay:=syncer_mask + 1;
|
||||
mtx_init(sync_mtx);
|
||||
mtx_init(sync_mtx,'Syncer mtx');
|
||||
cv_init(@sync_wakeup,'syncer');
|
||||
|
||||
i:=1;
|
||||
|
@ -290,28 +307,28 @@ end;
|
|||
}
|
||||
procedure vattr_null(vap:p_vattr);
|
||||
begin
|
||||
vap^.va_type:=VNON;
|
||||
vap^.va_size:=VNOVAL;
|
||||
vap^.va_bytes:=VNOVAL;
|
||||
vap^.va_mode:=VNOVAL;
|
||||
vap^.va_nlink:=VNOVAL;
|
||||
vap^.va_uid:=VNOVAL;
|
||||
vap^.va_gid:=VNOVAL;
|
||||
vap^.va_fsid:=VNOVAL;
|
||||
vap^.va_fileid:=VNOVAL;
|
||||
vap^.va_blocksize:=VNOVAL;
|
||||
vap^.va_rdev:=VNOVAL;
|
||||
vap^.va_atime.tv_sec:=VNOVAL;
|
||||
vap^.va_atime.tv_nsec:=VNOVAL;
|
||||
vap^.va_mtime.tv_sec:=VNOVAL;
|
||||
vap^.va_mtime.tv_nsec:=VNOVAL;
|
||||
vap^.va_ctime.tv_sec:=VNOVAL;
|
||||
vap^.va_ctime.tv_nsec:=VNOVAL;
|
||||
vap^.va_birthtime.tv_sec:=VNOVAL;
|
||||
vap^.va_type :=VNON;
|
||||
vap^.va_size :=QWORD(VNOVAL);
|
||||
vap^.va_bytes :=QWORD(VNOVAL);
|
||||
vap^.va_mode :=WORD(VNOVAL);
|
||||
vap^.va_nlink :=WORD(VNOVAL);
|
||||
vap^.va_uid :=VNOVAL;
|
||||
vap^.va_gid :=VNOVAL;
|
||||
vap^.va_fsid :=VNOVAL;
|
||||
vap^.va_fileid :=QWORD(VNOVAL);
|
||||
vap^.va_blocksize :=QWORD(VNOVAL);
|
||||
vap^.va_rdev :=VNOVAL;
|
||||
vap^.va_atime.tv_sec :=VNOVAL;
|
||||
vap^.va_atime.tv_nsec :=VNOVAL;
|
||||
vap^.va_mtime.tv_sec :=VNOVAL;
|
||||
vap^.va_mtime.tv_nsec :=VNOVAL;
|
||||
vap^.va_ctime.tv_sec :=VNOVAL;
|
||||
vap^.va_ctime.tv_nsec :=VNOVAL;
|
||||
vap^.va_birthtime.tv_sec :=VNOVAL;
|
||||
vap^.va_birthtime.tv_nsec:=VNOVAL;
|
||||
vap^.va_flags:=VNOVAL;
|
||||
vap^.va_gen:=VNOVAL;
|
||||
vap^.va_vaflags:=0;
|
||||
vap^.va_flags :=QWORD(VNOVAL);
|
||||
vap^.va_gen :=QWORD(VNOVAL);
|
||||
vap^.va_vaflags :=0;
|
||||
end;
|
||||
|
||||
{
|
||||
|
@ -2594,21 +2611,16 @@ begin
|
|||
}
|
||||
end;
|
||||
|
||||
{
|
||||
static void
|
||||
destroy_vpollinfo_free(struct vpollinfo *vi)
|
||||
procedure destroy_vpollinfo_free(vi:p_vpollinfo);
|
||||
begin
|
||||
|
||||
knlist_destroy(@vi^.vpi_selinfo.si_note);
|
||||
mtx_destroy(@vi^.vpi_lock);
|
||||
uma_zfree(vnodepoll_zone, vi);
|
||||
//knlist_destroy(@vi^.vpi_selinfo.si_note);
|
||||
mtx_destroy(vi^.vpi_lock);
|
||||
FreeMem(vi);
|
||||
end;
|
||||
|
||||
static void
|
||||
destroy_vpollinfo(struct vpollinfo *vi)
|
||||
procedure destroy_vpollinfo(vi:p_vpollinfo);
|
||||
begin
|
||||
|
||||
knlist_clear(@vi^.vpi_selinfo.si_note, 1);
|
||||
//knlist_clear(@vi^.vpi_selinfo.si_note, 1);
|
||||
seldrain(@vi^.vpi_selinfo);
|
||||
destroy_vpollinfo_free(vi);
|
||||
end;
|
||||
|
@ -2616,19 +2628,18 @@ end;
|
|||
{
|
||||
* Initalize per-vnode helper structure to hold poll-related state.
|
||||
}
|
||||
void
|
||||
v_addpollinfo(vp:p_vnode)
|
||||
procedure v_addpollinfo(vp:p_vnode);
|
||||
var
|
||||
vi:p_vpollinfo;
|
||||
begin
|
||||
struct vpollinfo *vi;
|
||||
|
||||
if (vp^.v_pollinfo<>nil)
|
||||
if (vp^.v_pollinfo<>nil) then
|
||||
Exit;
|
||||
vi:=uma_zalloc(vnodepoll_zone, M_WAITOK);
|
||||
mtx_init(@vi^.vpi_lock, "vnode pollinfo", nil, MTX_DEF);
|
||||
knlist_init(@vi^.vpi_selinfo.si_note, vp, vfs_knllock,
|
||||
vfs_knlunlock, vfs_knl_assert_locked, vfs_knl_assert_unlocked);
|
||||
vi:=AllocMem(SizeOf(vpollinfo));
|
||||
mtx_init(vi^.vpi_lock,'vnode pollinfo');
|
||||
//knlist_init(@vi^.vpi_selinfo.si_note, vp, vfs_knllock, vfs_knlunlock, vfs_knl_assert_locked, vfs_knl_assert_unlocked);
|
||||
VI_LOCK(vp);
|
||||
if (vp^.v_pollinfo<>nil) begin
|
||||
if (vp^.v_pollinfo<>nil) then
|
||||
begin
|
||||
VI_UNLOCK(vp);
|
||||
destroy_vpollinfo_free(vi);
|
||||
Exit;
|
||||
|
@ -2645,13 +2656,12 @@ end;
|
|||
* functions. (These are done together, while the lock is held,
|
||||
* to avoid race conditions.)
|
||||
}
|
||||
int
|
||||
vn_pollrecord(vp:p_vnode, struct thread *td, int events)
|
||||
function vn_pollrecord(vp:p_vnode;events:Integer):Integer;
|
||||
begin
|
||||
|
||||
v_addpollinfo(vp);
|
||||
mtx_lock(@vp^.v_pollinfo^.vpi_lock);
|
||||
if (vp^.v_pollinfo^.vpi_revents and events) begin
|
||||
mtx_lock(vp^.v_pollinfo^.vpi_lock);
|
||||
if ((vp^.v_pollinfo^.vpi_revents and events)<>0) then
|
||||
begin
|
||||
{
|
||||
* This leaves events we are not interested
|
||||
* in available for the other process which
|
||||
|
@ -2659,18 +2669,17 @@ begin
|
|||
* (otherwise they would never have been
|
||||
* recorded).
|
||||
}
|
||||
events:= and vp^.v_pollinfo^.vpi_revents;
|
||||
vp^.v_pollinfo^.vpi_revents:= and ~events;
|
||||
events:=events and vp^.v_pollinfo^.vpi_revents;
|
||||
vp^.v_pollinfo^.vpi_revents:=vp^.v_pollinfo^.vpi_revents and (not events);
|
||||
|
||||
mtx_unlock(@vp^.v_pollinfo^.vpi_lock);
|
||||
mtx_unlock(vp^.v_pollinfo^.vpi_lock);
|
||||
Exit(events);
|
||||
end;
|
||||
vp^.v_pollinfo^.vpi_events:= or events;
|
||||
selrecord(td, &vp^.v_pollinfo^.vpi_selinfo);
|
||||
mtx_unlock(@vp^.v_pollinfo^.vpi_lock);
|
||||
vp^.v_pollinfo^.vpi_events:=vp^.v_pollinfo^.vpi_events or events;
|
||||
selrecord(curkthread, @vp^.v_pollinfo^.vpi_selinfo);
|
||||
mtx_unlock(vp^.v_pollinfo^.vpi_lock);
|
||||
Exit(0);
|
||||
end;
|
||||
}
|
||||
|
||||
{
|
||||
* Routine to create and manage a filesystem syncer vnode.
|
||||
|
@ -2870,6 +2879,7 @@ begin
|
|||
//if ((vp^.v_rdev^.si_devsw^.d_flags and D_DISK)=0) then
|
||||
// error:=ENOTBLK;
|
||||
//dev_unlock();
|
||||
error:=ENOTBLK;
|
||||
if (errp<>nil) then
|
||||
errp^:=error;
|
||||
Exit(error=0);
|
||||
|
@ -3063,154 +3073,111 @@ begin
|
|||
vhold(ap^.a_tvp);
|
||||
end;
|
||||
|
||||
procedure vop_create_post(ap:p_vop_create_args;rc:Integer);
|
||||
begin
|
||||
if (rc=0) then
|
||||
begin
|
||||
//VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure vop_deleteextattr_post(ap:p_vop_deleteextattr_args;rc:Integer);
|
||||
begin
|
||||
if (rc=0) then
|
||||
begin
|
||||
//VFS_KNOTE_LOCKED(a^.a_vp, NOTE_ATTRIB);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure vop_link_post(ap:p_vop_link_args;rc:Integer);
|
||||
begin
|
||||
if (rc=0) then
|
||||
begin
|
||||
//VFS_KNOTE_LOCKED(a^.a_vp, NOTE_LINK);
|
||||
//VFS_KNOTE_LOCKED(a^.a_tdvp, NOTE_WRITE);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure vop_mkdir_post(ap:p_vop_mkdir_args;rc:Integer);
|
||||
begin
|
||||
if (rc=0) then
|
||||
begin
|
||||
//VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE or NOTE_LINK);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure vop_mknod_post(ap:p_vop_mknod_args;rc:Integer);
|
||||
begin
|
||||
if (rc=0) then
|
||||
begin
|
||||
//VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure vop_remove_post(ap:p_vop_remove_args;rc:Integer);
|
||||
begin
|
||||
if (rc=0) then
|
||||
begin
|
||||
//VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE);
|
||||
//VFS_KNOTE_LOCKED(a^.a_vp, NOTE_DELETE);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure vop_rename_post(ap:p_vop_rename_args;rc:Integer);
|
||||
begin
|
||||
if (rc=0) then
|
||||
begin
|
||||
//VFS_KNOTE_UNLOCKED(a^.a_fdvp, NOTE_WRITE);
|
||||
//VFS_KNOTE_UNLOCKED(a^.a_tdvp, NOTE_WRITE);
|
||||
//VFS_KNOTE_UNLOCKED(a^.a_fvp, NOTE_RENAME);
|
||||
if (ap^.a_tvp<>nil) then
|
||||
begin
|
||||
//VFS_KNOTE_UNLOCKED(a^.a_tvp, NOTE_DELETE);
|
||||
end;
|
||||
end;
|
||||
if (ap^.a_tdvp<>ap^.a_fdvp) then
|
||||
vdrop(ap^.a_fdvp);
|
||||
if (ap^.a_tvp<>ap^.a_fvp) then
|
||||
vdrop(ap^.a_fvp);
|
||||
vdrop(ap^.a_tdvp);
|
||||
if (ap^.a_tvp<>nil) then
|
||||
vdrop(ap^.a_tvp);
|
||||
end;
|
||||
|
||||
procedure vop_rmdir_post(ap:p_vop_rmdir_args;rc:Integer);
|
||||
begin
|
||||
if (rc=0) then
|
||||
begin
|
||||
//VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE or NOTE_LINK);
|
||||
//VFS_KNOTE_LOCKED(a^.a_vp, NOTE_DELETE);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure vop_setattr_post(ap:p_vop_setattr_args;rc:Integer);
|
||||
begin
|
||||
if (rc=0) then
|
||||
begin
|
||||
//VFS_KNOTE_LOCKED(a^.a_vp, NOTE_ATTRIB);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure vop_setextattr_post(ap:p_vop_setextattr_args;rc:Integer);
|
||||
begin
|
||||
if (rc=0) then
|
||||
begin
|
||||
//VFS_KNOTE_LOCKED(a^.a_vp, NOTE_ATTRIB);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure vop_symlink_post(ap:p_vop_symlink_args;rc:Integer);
|
||||
begin
|
||||
if (rc=0) then
|
||||
begin
|
||||
//VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE);
|
||||
end;
|
||||
end;
|
||||
|
||||
{
|
||||
void
|
||||
vop_strategy_pre(void *ap)
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
void
|
||||
vop_lock_pre(void *ap)
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
void
|
||||
vop_lock_post(void *ap, int rc)
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
void
|
||||
vop_unlock_pre(void *ap)
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
void
|
||||
vop_unlock_post(void *ap, int rc)
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
void
|
||||
vop_create_post(void *ap, int rc)
|
||||
begin
|
||||
struct vop_create_args *a:=ap;
|
||||
|
||||
if (!rc)
|
||||
VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE);
|
||||
end;
|
||||
|
||||
void
|
||||
vop_deleteextattr_post(void *ap, int rc)
|
||||
begin
|
||||
struct vop_deleteextattr_args *a:=ap;
|
||||
|
||||
if (!rc)
|
||||
VFS_KNOTE_LOCKED(a^.a_vp, NOTE_ATTRIB);
|
||||
end;
|
||||
|
||||
void
|
||||
vop_link_post(void *ap, int rc)
|
||||
begin
|
||||
struct vop_link_args *a:=ap;
|
||||
|
||||
if (!rc) begin
|
||||
VFS_KNOTE_LOCKED(a^.a_vp, NOTE_LINK);
|
||||
VFS_KNOTE_LOCKED(a^.a_tdvp, NOTE_WRITE);
|
||||
end;
|
||||
end;
|
||||
|
||||
void
|
||||
vop_mkdir_post(void *ap, int rc)
|
||||
begin
|
||||
struct vop_mkdir_args *a:=ap;
|
||||
|
||||
if (!rc)
|
||||
VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE or NOTE_LINK);
|
||||
end;
|
||||
|
||||
void
|
||||
vop_mknod_post(void *ap, int rc)
|
||||
begin
|
||||
struct vop_mknod_args *a:=ap;
|
||||
|
||||
if (!rc)
|
||||
VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE);
|
||||
end;
|
||||
|
||||
void
|
||||
vop_remove_post(void *ap, int rc)
|
||||
begin
|
||||
struct vop_remove_args *a:=ap;
|
||||
|
||||
if (!rc) begin
|
||||
VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE);
|
||||
VFS_KNOTE_LOCKED(a^.a_vp, NOTE_DELETE);
|
||||
end;
|
||||
end;
|
||||
|
||||
void
|
||||
vop_rename_post(void *ap, int rc)
|
||||
begin
|
||||
struct vop_rename_args *a:=ap;
|
||||
|
||||
if (!rc) begin
|
||||
VFS_KNOTE_UNLOCKED(a^.a_fdvp, NOTE_WRITE);
|
||||
VFS_KNOTE_UNLOCKED(a^.a_tdvp, NOTE_WRITE);
|
||||
VFS_KNOTE_UNLOCKED(a^.a_fvp, NOTE_RENAME);
|
||||
if (a^.a_tvp)
|
||||
VFS_KNOTE_UNLOCKED(a^.a_tvp, NOTE_DELETE);
|
||||
end;
|
||||
if (a^.a_tdvp<>a^.a_fdvp)
|
||||
vdrop(a^.a_fdvp);
|
||||
if (a^.a_tvp<>a^.a_fvp)
|
||||
vdrop(a^.a_fvp);
|
||||
vdrop(a^.a_tdvp);
|
||||
if (a^.a_tvp)
|
||||
vdrop(a^.a_tvp);
|
||||
end;
|
||||
|
||||
void
|
||||
vop_rmdir_post(void *ap, int rc)
|
||||
begin
|
||||
struct vop_rmdir_args *a:=ap;
|
||||
|
||||
if (!rc) begin
|
||||
VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE or NOTE_LINK);
|
||||
VFS_KNOTE_LOCKED(a^.a_vp, NOTE_DELETE);
|
||||
end;
|
||||
end;
|
||||
|
||||
void
|
||||
vop_setattr_post(void *ap, int rc)
|
||||
begin
|
||||
struct vop_setattr_args *a:=ap;
|
||||
|
||||
if (!rc)
|
||||
VFS_KNOTE_LOCKED(a^.a_vp, NOTE_ATTRIB);
|
||||
end;
|
||||
|
||||
void
|
||||
vop_setextattr_post(void *ap, int rc)
|
||||
begin
|
||||
struct vop_setextattr_args *a:=ap;
|
||||
|
||||
if (!rc)
|
||||
VFS_KNOTE_LOCKED(a^.a_vp, NOTE_ATTRIB);
|
||||
end;
|
||||
|
||||
void
|
||||
vop_symlink_post(void *ap, int rc)
|
||||
begin
|
||||
struct vop_symlink_args *a:=ap;
|
||||
|
||||
if (!rc)
|
||||
VFS_KNOTE_LOCKED(a^.a_dvp, NOTE_WRITE);
|
||||
end;
|
||||
|
||||
static struct knlist fs_knlist;
|
||||
|
||||
static void
|
||||
|
|
|
@ -85,6 +85,7 @@ function sys_revoke(path:PChar):Integer;
|
|||
implementation
|
||||
|
||||
uses
|
||||
atomic,
|
||||
mqueue,
|
||||
systm,
|
||||
errno,
|
||||
|
|
|
@ -9,6 +9,7 @@ uses
|
|||
mqueue,
|
||||
kern_thr,
|
||||
kern_mtx,
|
||||
vselinfo,
|
||||
time,
|
||||
vmparam;
|
||||
|
||||
|
@ -173,6 +174,14 @@ type
|
|||
|
||||
vtype=(VNON,VREG,VDIR,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD,VMARKER);
|
||||
|
||||
p_vpollinfo=^vpollinfo;
|
||||
vpollinfo=packed record
|
||||
vpi_lock :mtx; // lock to protect below
|
||||
vpi_selinfo:t_selinfo; // identity of poller(s)
|
||||
vpi_events :Word; // what they are looking for
|
||||
vpi_revents:Word; // what has happened
|
||||
end;
|
||||
|
||||
t_vnode=packed object
|
||||
v_type:vtype;
|
||||
v_tag :PChar;
|
||||
|
@ -196,10 +205,12 @@ type
|
|||
v_iflag:QWORD;
|
||||
v_vflag:QWORD;
|
||||
|
||||
property v_mountedhere:Pointer read v_un{.vu_mount };
|
||||
property v_socket :Pointer read v_un{.vu_socket };
|
||||
property v_rdev :Pointer read v_un{.vu_cdev };
|
||||
property v_fifoinfo :Pointer read v_un{.vu_fifoinfo};
|
||||
v_pollinfo:p_vpollinfo; // i Poll events, p for *v_pi
|
||||
|
||||
property v_mountedhere:Pointer read v_un{.vu_mount } write v_un;
|
||||
property v_socket :Pointer read v_un{.vu_socket } write v_un;
|
||||
property v_rdev :Pointer read v_un{.vu_cdev } write v_un;
|
||||
property v_fifoinfo :Pointer read v_un{.vu_fifoinfo} write v_un;
|
||||
end;
|
||||
|
||||
p_vattr=^t_vattr;
|
||||
|
|
|
@ -475,7 +475,7 @@ begin
|
|||
mode:=mode or S_IFIFO;
|
||||
else
|
||||
Exit(EBADF);
|
||||
end;;
|
||||
end;
|
||||
sb^.st_mode:=mode;
|
||||
sb^.st_nlink:=vap^.va_nlink;
|
||||
sb^.st_uid:=vap^.va_uid;
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
unit vioccom;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
{$CALLING SysV_ABI_CDecl}
|
||||
|
||||
interface
|
||||
|
||||
{
|
||||
* Ioctl's have the command encoded in the lower word, and the size of
|
||||
* any in or out parameters in the upper word. The high 3 bits of the
|
||||
* upper word are used to encode the in/out status of the parameter.
|
||||
}
|
||||
const
|
||||
IOCPARM_SHIFT=13; { number of bits for ioctl size }
|
||||
IOCPARM_MASK =((1 shl IOCPARM_SHIFT) - 1); { parameter length mask }
|
||||
|
||||
IOCPARM_MAX =(1 shl IOCPARM_SHIFT); { max size of ioctl }
|
||||
IOC_VOID =$20000000; { no parameters }
|
||||
IOC_OUT =$40000000; { copy out parameters }
|
||||
IOC_IN =$80000000; { copy in parameters }
|
||||
IOC_INOUT =(IOC_IN or IOC_OUT);
|
||||
IOC_DIRMASK =(IOC_VOID or IOC_OUT or IOC_IN);
|
||||
|
||||
function IOCPARM_LEN(x:QWORD):QWORD; inline;
|
||||
function IOCBASECMD (x:QWORD):QWORD; inline;
|
||||
function IOCGROUP (x:QWORD):QWORD; inline;
|
||||
|
||||
implementation
|
||||
|
||||
function IOCPARM_LEN(x:QWORD):QWORD; inline;
|
||||
begin
|
||||
Result:=(x shr 16) and IOCPARM_MASK;
|
||||
end;
|
||||
|
||||
function IOCBASECMD(x:QWORD):QWORD; inline;
|
||||
begin
|
||||
Result:=x and (not (IOCPARM_MASK shl 16));
|
||||
end;
|
||||
|
||||
function IOCGROUP(x:QWORD):QWORD; inline;
|
||||
begin
|
||||
Result:=(x shr 8) and $ff;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
|
@ -582,8 +582,8 @@ begin
|
|||
end;
|
||||
|
||||
initialization
|
||||
mtx_init(mountlist_mtx);
|
||||
mtx_init(VFS_Giant);
|
||||
mtx_init(mountlist_mtx,'mountlist');
|
||||
mtx_init(VFS_Giant ,'VFS_Giant');
|
||||
|
||||
end.
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ uses
|
|||
vfile,
|
||||
vuio,
|
||||
vmount,
|
||||
vfcntl;
|
||||
vfcntl,
|
||||
vsocketvar;
|
||||
|
||||
type
|
||||
PPPtrUint =^PPtrUint;
|
||||
|
@ -25,8 +26,6 @@ type
|
|||
acl_type_t =Integer;
|
||||
p_acl =Pointer;
|
||||
p_label =Pointer;
|
||||
p_socket =Pointer;
|
||||
pp_socket =Pointer;
|
||||
|
||||
p_vop_islocked_args=^vop_islocked_args;
|
||||
vop_islocked_args=packed record
|
||||
|
@ -643,6 +642,7 @@ begin
|
|||
a.a_cnp:=cnp;
|
||||
a.a_vap:=vap;
|
||||
Result:=vop_create_t(dvp^.v_op^.vop_create)(@a);
|
||||
vop_create_post(@a,Result);
|
||||
end;
|
||||
|
||||
function VOP_WHITEOUT(dvp:p_vnode;cnp:p_componentname;flags:Integer):Integer;
|
||||
|
@ -664,6 +664,7 @@ begin
|
|||
a.a_cnp:=cnp;
|
||||
a.a_vap:=vap;
|
||||
Result:=vop_mknod_t(dvp^.v_op^.vop_mknod)(@a);
|
||||
vop_mknod_post(@a,Result);
|
||||
end;
|
||||
|
||||
function VOP_OPEN(vp:p_vnode;mode:Integer;fp:p_file):Integer;
|
||||
|
@ -719,6 +720,7 @@ begin
|
|||
a.a_vp :=vp;
|
||||
a.a_vap:=vap;
|
||||
Result:=vop_setattr_t(vp^.v_op^.vop_setattr)(@a);
|
||||
vop_setattr_post(@a,Result);
|
||||
end;
|
||||
|
||||
function VOP_MARKATIME(vp:p_vnode):Integer;
|
||||
|
@ -801,6 +803,7 @@ begin
|
|||
a.a_vp :=vp;
|
||||
a.a_cnp:=cnp;
|
||||
Result:=vop_remove_t(dvp^.v_op^.vop_remove)(@a);
|
||||
vop_remove_post(@a,Result);
|
||||
end;
|
||||
|
||||
function VOP_LINK(tdvp:p_vnode;vp:p_vnode;cnp:p_componentname):Integer;
|
||||
|
@ -811,6 +814,7 @@ begin
|
|||
a.a_vp :=vp;
|
||||
a.a_cnp :=cnp;
|
||||
Result:=vop_link_t(tdvp^.v_op^.vop_link)(@a);
|
||||
vop_link_post(@a,Result);
|
||||
end;
|
||||
|
||||
function VOP_RENAME(fdvp:p_vnode;fvp:p_vnode;fcnp:p_componentname;tdvp:p_vnode;tvp:p_vnode;tcnp:p_componentname):Integer;
|
||||
|
@ -825,6 +829,7 @@ begin
|
|||
a.a_tcnp:=tcnp;
|
||||
vop_rename_pre(@a);
|
||||
Result:=vop_rename_t(fdvp^.v_op^.vop_rename)(@a);
|
||||
vop_rename_post(@a,Result);
|
||||
end;
|
||||
|
||||
function VOP_MKDIR(dvp:p_vnode;vpp:pp_vnode;cnp:p_componentname;vap:p_vattr):Integer;
|
||||
|
@ -836,6 +841,7 @@ begin
|
|||
a.a_cnp:=cnp;
|
||||
a.a_vap:=vap;
|
||||
Result:=vop_mkdir_t(dvp^.v_op^.vop_mkdir)(@a);
|
||||
vop_mkdir_post(@a,Result);
|
||||
end;
|
||||
|
||||
function VOP_RMDIR(dvp:p_vnode;vp:p_vnode;cnp:p_componentname):Integer;
|
||||
|
@ -846,6 +852,7 @@ begin
|
|||
a.a_vp :=vp;
|
||||
a.a_cnp:=cnp;
|
||||
Result:=vop_rmdir_t(dvp^.v_op^.vop_rmdir)(@a);
|
||||
vop_rmdir_post(@a,Result);
|
||||
end;
|
||||
|
||||
function VOP_SYMLINK(dvp:p_vnode;vpp:pp_vnode;cnp:p_componentname;vap:p_vattr;target:PChar):Integer;
|
||||
|
@ -858,6 +865,7 @@ begin
|
|||
a.a_vap :=vap;
|
||||
a.a_target:=target;
|
||||
Result:=vop_symlink_t(dvp^.v_op^.vop_symlink)(@a);
|
||||
vop_symlink_post(@a,Result);
|
||||
end;
|
||||
|
||||
function VOP_READDIR(vp:p_vnode;uio:p_uio;eofflag:PInteger;ncookies:PInteger;cookies:PPPtrUint):Integer;
|
||||
|
@ -1097,6 +1105,7 @@ begin
|
|||
a.a_attrnamespace:=attrnamespace;
|
||||
a.a_name :=name;
|
||||
Result:=vop_deleteextattr_t(vp^.v_op^.vop_deleteextattr)(@a);
|
||||
vop_deleteextattr_post(@a,Result);
|
||||
end;
|
||||
|
||||
function VOP_SETEXTATTR(vp:p_vnode;attrnamespace:Integer;name:PChar;uio:p_uio):Integer;
|
||||
|
@ -1108,6 +1117,7 @@ begin
|
|||
a.a_name :=name;
|
||||
a.a_uio :=uio;
|
||||
Result:=vop_setextattr_t(vp^.v_op^.vop_setextattr)(@a);
|
||||
vop_setextattr_post(@a,Result);
|
||||
end;
|
||||
|
||||
function VOP_SETLABEL(vp:p_vnode;_label:p_label):Integer;
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
unit vpoll;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
{$CALLING SysV_ABI_CDecl}
|
||||
|
||||
interface
|
||||
|
||||
type
|
||||
nfds_t=DWORD;
|
||||
|
||||
{
|
||||
* This structure is passed as an array to poll(2).
|
||||
}
|
||||
p_pollfd=^t_pollfd;
|
||||
t_pollfd=packed record
|
||||
fd :Integer; { which file descriptor to poll }
|
||||
events :Word; { events we are interested in }
|
||||
revents:Word; { events found on return }
|
||||
end;
|
||||
|
||||
const
|
||||
{
|
||||
* Requestable events. If poll(2) finds any of these set, they are
|
||||
* copied to revents on return.
|
||||
* XXX Note that FreeBSD doesn't make much distinction between POLLPRI
|
||||
* and POLLRDBAND since none of the file types have distinct priority
|
||||
* bands - and only some have an urgent "mode".
|
||||
* XXX Note POLLIN isn't really supported in true SVSV terms. Under SYSV
|
||||
* POLLIN includes all of normal, band and urgent data. Most poll handlers
|
||||
* on FreeBSD only treat it as "normal" data.
|
||||
}
|
||||
POLLIN =$0001; { any readable data available }
|
||||
POLLPRI =$0002; { OOB/Urgent readable data }
|
||||
POLLOUT =$0004; { file descriptor is writeable }
|
||||
POLLRDNORM=$0040; { non-OOB/URG data available }
|
||||
POLLWRNORM=POLLOUT; { no write type differentiation }
|
||||
POLLRDBAND=$0080; { OOB/Urgent readable data }
|
||||
POLLWRBAND=$0100; { OOB/Urgent data can be written }
|
||||
|
||||
{ General FreeBSD extension (currently only supported for sockets): }
|
||||
POLLINIGNEOF=$2000; { like POLLIN, except ignore EOF }
|
||||
|
||||
{
|
||||
* These events are set if they occur regardless of whether they were
|
||||
* requested.
|
||||
}
|
||||
POLLERR =$0008; { some poll error occurred }
|
||||
POLLHUP =$0010; { file descriptor was "hung up" }
|
||||
POLLNVAL=$0020; { requested events "invalid" }
|
||||
|
||||
POLLSTANDARD=(POLLIN or POLLPRI or POLLOUT or POLLRDNORM or POLLRDBAND or
|
||||
POLLWRBAND or POLLERR or POLLHUP or POLLNVAL);
|
||||
|
||||
{
|
||||
* Request that poll() wait forever.
|
||||
* XXX in SYSV, this is defined in stropts.h, which is not included
|
||||
* by poll.h.
|
||||
}
|
||||
INFTIM=-1;
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
unit vselect;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
{$CALLING SysV_ABI_CDecl}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
signal,
|
||||
time;
|
||||
|
||||
type
|
||||
pp_fd_mask=^p_fd_mask;
|
||||
p_fd_mask=^fd_mask;
|
||||
fd_mask=QWORD;
|
||||
|
||||
{
|
||||
* Select uses bit masks of file descriptors in longs. These macros
|
||||
* manipulate such bit fields (the filesystem macros use chars).
|
||||
* FD_SETSIZE may be defined by the user, but the default here should
|
||||
* be enough for most uses.
|
||||
}
|
||||
const
|
||||
FD_SETSIZE=1024;
|
||||
NFDBITS =(sizeof(fd_mask) * 8); { bits per mask }
|
||||
|
||||
type
|
||||
p_fd_set=^t_fd_set;
|
||||
t_fd_set=packed record
|
||||
fds_bits:array[0..((FD_SETSIZE + (NFDBITS - 1)) div NFDBITS)-1] of fd_mask;
|
||||
end;
|
||||
|
||||
procedure FD_CLR(n:Integer;p:p_fd_set);
|
||||
procedure FD_COPY(f,t:p_fd_set);
|
||||
function FD_ISSET(n:Integer;p:p_fd_set):Boolean;
|
||||
procedure FD_SET(n:Integer;p:p_fd_set);
|
||||
procedure FD_ZERO(p:p_fd_set);
|
||||
|
||||
implementation
|
||||
|
||||
function __fdset_mask(n:Integer):fd_mask; inline;
|
||||
begin
|
||||
Result:=fd_mask(1) shl (n mod NFDBITS);
|
||||
end;
|
||||
|
||||
procedure FD_CLR(n:Integer;p:p_fd_set);
|
||||
begin
|
||||
p^.fds_bits[n div NFDBITS]:=p^.fds_bits[n div NFDBITS] and (not __fdset_mask(n));
|
||||
end;
|
||||
|
||||
procedure FD_COPY(f,t:p_fd_set);
|
||||
begin
|
||||
f^:=t^;
|
||||
end;
|
||||
|
||||
function FD_ISSET(n:Integer;p:p_fd_set):Boolean;
|
||||
begin
|
||||
Result:=(p^.fds_bits[n div NFDBITS] and __fdset_mask(n))<>0;
|
||||
end;
|
||||
|
||||
procedure FD_SET(n:Integer;p:p_fd_set);
|
||||
begin
|
||||
p^.fds_bits[n div NFDBITS]:=p^.fds_bits[n div NFDBITS] or __fdset_mask(n);
|
||||
end;
|
||||
|
||||
procedure FD_ZERO(p:p_fd_set);
|
||||
begin
|
||||
p^:=Default(t_fd_set);
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
unit vselinfo;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
{$CALLING SysV_ABI_CDecl}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
mqueue,
|
||||
kern_mtx;
|
||||
|
||||
type
|
||||
{
|
||||
* Used to maintain information about processes that wish to be
|
||||
* notified when I/O becomes possible.
|
||||
}
|
||||
p_selinfo=^t_selinfo;
|
||||
t_selinfo=packed record
|
||||
si_tdlist:TAILQ_HEAD; { List of sleeping threads. }
|
||||
//si_note:knlist; { kernel note list }
|
||||
si_mtx:p_mtx; { Lock for tdlist. }
|
||||
end;
|
||||
|
||||
function SEL_WAITING(si:p_selinfo):Boolean; inline;
|
||||
|
||||
implementation
|
||||
|
||||
function SEL_WAITING(si:p_selinfo):Boolean; inline;
|
||||
begin
|
||||
Result:=(not TAILQ_EMPTY(@si^.si_tdlist));
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
unit vsockbuf;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
{$CALLING SysV_ABI_CDecl}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
vselinfo,
|
||||
kern_mtx;
|
||||
|
||||
const
|
||||
SB_MAX=(2*1024*1024); { default for max chars in sockbuf }
|
||||
|
||||
{
|
||||
* Constants for sb_flags field of struct sockbuf.
|
||||
}
|
||||
SB_WAIT =$04 ; { someone is waiting for data/space }
|
||||
SB_SEL =$08 ; { someone is selecting }
|
||||
SB_ASYNC =$10 ; { ASYNC I/O, need signals }
|
||||
SB_UPCALL =$20 ; { someone wants an upcall }
|
||||
SB_NOINTR =$40 ; { operations not interruptible }
|
||||
SB_AIO =$80 ; { AIO operations queued }
|
||||
SB_KNOTE =$100; { kernel note attached }
|
||||
SB_NOCOALESCE=$200; { don't coalesce new data into existing mbufs }
|
||||
SB_IN_TOE =$400; { socket buffer is in the middle of an operation }
|
||||
SB_AUTOSIZE =$800; { automatically size socket buffer }
|
||||
|
||||
SBS_CANTSENDMORE=$0010; { can't send more data to peer }
|
||||
SBS_CANTRCVMORE =$0020; { can't receive more data from peer }
|
||||
SBS_RCVATMARK =$0040; { at mark on input }
|
||||
|
||||
//struct mbuf;
|
||||
//struct sockaddr;
|
||||
//struct socket;
|
||||
//struct thread;
|
||||
|
||||
type
|
||||
t_xsockbuf=packed record
|
||||
sb_cc :DWORD;
|
||||
sb_hiwat:DWORD;
|
||||
sb_mbcnt:DWORD;
|
||||
sb_mcnt :DWORD;
|
||||
sb_ccnt :DWORD;
|
||||
sb_mbmax:DWORD;
|
||||
sb_lowat:Integer;
|
||||
sb_timeo:Integer;
|
||||
sb_flags:Word;
|
||||
end;
|
||||
|
||||
{
|
||||
* Variables for socket buffering.
|
||||
}
|
||||
t_sb_upcall=function(s,p:Pointer;i:Integer):Integer;
|
||||
|
||||
p_sockbuf=^t_sockbuf;
|
||||
t_sockbuf=record
|
||||
sb_sel :p_selinfo ; { process selecting read/write }
|
||||
sb_mtx :mtx ; { sockbuf lock }
|
||||
sb_sx :Pointer ; { prevent I/O interlacing }
|
||||
sb_state :Word ; { (c/d) socket state on sockbuf }
|
||||
//sb_startzero=sb_mb
|
||||
sb_mb :Pointer ; { (c/d) the mbuf chain }
|
||||
sb_mbtail :Pointer ; { (c/d) the last mbuf in the chain }
|
||||
sb_lastrecord:Pointer ; { (c/d) first mbuf of last record in socket buffer }
|
||||
sb_sndptr :Pointer ; { (c/d) pointer into mbuf chain }
|
||||
sb_sndptroff :DWORD ; { (c/d) byte offset of ptr into chain }
|
||||
sb_cc :DWORD ; { (c/d) actual chars in buffer }
|
||||
sb_hiwat :DWORD ; { (c/d) max actual char count }
|
||||
sb_mbcnt :DWORD ; { (c/d) chars of mbufs used }
|
||||
sb_mcnt :DWORD ; { (c/d) number of mbufs in buffer }
|
||||
sb_ccnt :DWORD ; { (c/d) number of clusters in buffer }
|
||||
sb_mbmax :DWORD ; { (c/d) max chars of mbufs to use }
|
||||
sb_ctl :DWORD ; { (c/d) non-data chars in buffer }
|
||||
sb_lowat :Integer ; { (c/d) low water mark }
|
||||
sb_timeo :Integer ; { (c/d) timeout for read/write }
|
||||
sb_flags :Word ; { (c/d) flags, see below }
|
||||
sb_upcall :t_sb_upcall; { (c/d) }
|
||||
sb_upcallarg :Pointer ; { (c/d) }
|
||||
end;
|
||||
|
||||
function SOCKBUF_MTX(_sb:p_sockbuf):p_mtx; inline;
|
||||
procedure SOCKBUF_LOCK_INIT(_sb:p_sockbuf;_name:PChar); inline;
|
||||
procedure SOCKBUF_LOCK_DESTROY(_sb:p_sockbuf); inline;
|
||||
procedure SOCKBUF_LOCK(_sb:p_sockbuf); inline;
|
||||
function SOCKBUF_OWNED(_sb:p_sockbuf):Boolean; inline;
|
||||
procedure SOCKBUF_UNLOCK(_sb:p_sockbuf); inline;
|
||||
procedure SOCKBUF_LOCK_ASSERT(_sb:p_sockbuf); inline;
|
||||
|
||||
function sbspace(sb:p_sockbuf):DWORD; inline;
|
||||
|
||||
implementation
|
||||
|
||||
{
|
||||
* Per-socket buffer mutex used to protect most fields in the socket
|
||||
* buffer.
|
||||
}
|
||||
function SOCKBUF_MTX(_sb:p_sockbuf):p_mtx; inline;
|
||||
begin
|
||||
Result:=@_sb^.sb_mtx
|
||||
end;
|
||||
|
||||
procedure SOCKBUF_LOCK_INIT(_sb:p_sockbuf;_name:PChar); inline;
|
||||
begin
|
||||
mtx_init(SOCKBUF_MTX(_sb)^,_name);
|
||||
end;
|
||||
|
||||
procedure SOCKBUF_LOCK_DESTROY(_sb:p_sockbuf); inline;
|
||||
begin
|
||||
mtx_destroy(SOCKBUF_MTX(_sb)^);
|
||||
end;
|
||||
|
||||
procedure SOCKBUF_LOCK(_sb:p_sockbuf); inline;
|
||||
begin
|
||||
mtx_lock(SOCKBUF_MTX(_sb)^);
|
||||
end;
|
||||
|
||||
function SOCKBUF_OWNED(_sb:p_sockbuf):Boolean; inline;
|
||||
begin
|
||||
Result:=mtx_owned(SOCKBUF_MTX(_sb)^);
|
||||
end;
|
||||
|
||||
procedure SOCKBUF_UNLOCK(_sb:p_sockbuf); inline;
|
||||
begin
|
||||
mtx_unlock(SOCKBUF_MTX(_sb)^);
|
||||
end;
|
||||
|
||||
procedure SOCKBUF_LOCK_ASSERT(_sb:p_sockbuf); inline;
|
||||
begin
|
||||
mtx_assert(SOCKBUF_MTX(_sb)^);
|
||||
end;
|
||||
|
||||
//
|
||||
|
||||
function sbspace(sb:p_sockbuf):DWORD; inline;
|
||||
var
|
||||
s1,s2:DWORD;
|
||||
begin
|
||||
s1:=sb^.sb_hiwat-sb^.sb_cc;
|
||||
s2:=sb^.sb_mbmax-sb^.sb_mbcnt;
|
||||
if (s1<s2) then
|
||||
Result:=s1
|
||||
else
|
||||
Result:=s2;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
unit vsocket;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
{$CALLING SysV_ABI_CDecl}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
vuio;
|
||||
|
||||
{
|
||||
* Definitions related to sockets: types, address families, options.
|
||||
}
|
||||
|
||||
{
|
||||
* Data types.
|
||||
}
|
||||
type
|
||||
sa_family_t=Byte;
|
||||
socklen_t =DWORD;
|
||||
|
||||
const
|
||||
{
|
||||
* Types
|
||||
}
|
||||
SOCK_STREAM =1; { stream socket }
|
||||
SOCK_DGRAM =2; { datagram socket }
|
||||
SOCK_RAW =3; { raw-protocol interface }
|
||||
SOCK_RDM =4; { reliably-delivered message }
|
||||
SOCK_SEQPACKET=5; { sequenced packet stream }
|
||||
|
||||
{
|
||||
* Option flags per-socket.
|
||||
}
|
||||
SO_DEBUG =$0001; { turn on debugging info recording }
|
||||
SO_ACCEPTCONN =$0002; { socket has had listen() }
|
||||
SO_REUSEADDR =$0004; { allow local address reuse }
|
||||
SO_KEEPALIVE =$0008; { keep connections alive }
|
||||
SO_DONTROUTE =$0010; { just use interface addresses }
|
||||
SO_BROADCAST =$0020; { permit sending of broadcast msgs }
|
||||
SO_USELOOPBACK =$0040; { bypass hardware when possible }
|
||||
SO_LINGER =$0080; { linger on close if data present }
|
||||
SO_OOBINLINE =$0100; { leave received OOB data in line }
|
||||
SO_REUSEPORT =$0200; { allow local address & port reuse }
|
||||
SO_TIMESTAMP =$0400; { timestamp received dgram traffic }
|
||||
SO_NOSIGPIPE =$0800; { no SIGPIPE from EPIPE }
|
||||
SO_ACCEPTFILTER=$1000; { there is an accept filter }
|
||||
SO_BINTIME =$2000; { timestamp received dgram traffic }
|
||||
SO_NO_OFFLOAD =$4000; { socket cannot be offloaded }
|
||||
SO_NO_DDP =$8000; { disable direct data placement }
|
||||
|
||||
{
|
||||
* Additional options, not kept in so_options.
|
||||
}
|
||||
SO_SNDBUF =$1001; { send buffer size }
|
||||
SO_RCVBUF =$1002; { receive buffer size }
|
||||
SO_SNDLOWAT =$1003; { send low-water mark }
|
||||
SO_RCVLOWAT =$1004; { receive low-water mark }
|
||||
SO_SNDTIMEO =$1005; { send timeout }
|
||||
SO_RCVTIMEO =$1006; { receive timeout }
|
||||
SO_ERROR =$1007; { get error status and clear }
|
||||
SO_TYPE =$1008; { get socket type }
|
||||
SO_LABEL =$1009; { socket's MAC label }
|
||||
SO_PEERLABEL =$1010; { socket's peer's MAC label }
|
||||
SO_LISTENQLIMIT =$1011; { socket's backlog limit }
|
||||
SO_LISTENQLEN =$1012; { socket's complete queue length }
|
||||
SO_LISTENINCQLEN=$1013; { socket's incomplete queue length }
|
||||
SO_SETFIB =$1014; { use this FIB to route }
|
||||
SO_USER_COOKIE =$1015; { user cookie (dummynet etc.) }
|
||||
SO_PROTOCOL =$1016; { get socket protocol (Linux name) }
|
||||
SO_PROTOTYPE =SO_PROTOCOL; { alias for SO_PROTOCOL (SunOS name) }
|
||||
|
||||
{
|
||||
* Space reserved for new socket options added by third-party vendors.
|
||||
* This range applies to all socket option levels. New socket options
|
||||
* in FreeBSD should always use an option value less than SO_VENDOR.
|
||||
}
|
||||
SO_VENDOR=$80000000;
|
||||
|
||||
type
|
||||
{
|
||||
* Structure used for manipulating linger option.
|
||||
}
|
||||
p_linger=^t_linger;
|
||||
t_linger=packed record
|
||||
l_onoff :Integer; { option on/off }
|
||||
l_linger:Integer; { linger time }
|
||||
end;
|
||||
|
||||
t_accept_filter_arg=packed record
|
||||
af_name:array[0..15] of AnsiChar;
|
||||
af_arg :array[0..256-15] of Byte;
|
||||
end;
|
||||
|
||||
const
|
||||
{
|
||||
* Level number for (get/set)sockopt() to apply to socket itself.
|
||||
}
|
||||
SOL_SOCKET=$ffff; { options for socket level }
|
||||
|
||||
{ address families }
|
||||
AF_UNSPEC=0;
|
||||
AF_UNIX =1;
|
||||
AF_LOCAL =AF_UNIX;
|
||||
AF_INET =2;
|
||||
AF_INET6 =28;
|
||||
AF_MAX =38;
|
||||
|
||||
type
|
||||
{
|
||||
* Structure used by kernel to store most
|
||||
* addresses.
|
||||
}
|
||||
p_sockaddr=^t_sockaddr;
|
||||
t_sockaddr=packed record
|
||||
sa_len :Byte; { total length }
|
||||
sa_family:sa_family_t; { address family }
|
||||
sa_data :array[0..13] of Byte; { actually longer; address value }
|
||||
end;
|
||||
|
||||
const
|
||||
SOCK_MAXADDRLEN=255; { longest possible addresses }
|
||||
|
||||
{
|
||||
* Structure used by kernel to pass protocol
|
||||
* information in raw sockets.
|
||||
}
|
||||
type
|
||||
p_sockproto=^t_sockproto;
|
||||
t_sockproto=packed record
|
||||
sp_family :Word; { address family }
|
||||
sp_protocol:Word; { protocol }
|
||||
end;
|
||||
|
||||
const
|
||||
{
|
||||
* PF_ROUTE - Routing table
|
||||
*
|
||||
* Three additional levels are defined:
|
||||
* Fourth: address family, 0 is wildcard
|
||||
* Fifth: type of info, defined below
|
||||
* Sixth: flag(s) to mask with for NET_RT_FLAGS
|
||||
}
|
||||
NET_RT_DUMP =1; { dump; may limit to a.f. }
|
||||
NET_RT_FLAGS =2; { by flags, e.g. RESOLVING }
|
||||
NET_RT_IFLIST =3; { survey interface list }
|
||||
NET_RT_IFMALIST=4; { return multicast address list }
|
||||
NET_RT_IFLISTL =5; { Survey interface list, using len versions of msghdr structs. }
|
||||
NET_RT_MAXID =6;
|
||||
|
||||
{
|
||||
* Maximum queue length specifiable by listen.
|
||||
}
|
||||
SOMAXCONN=128;
|
||||
|
||||
type
|
||||
{
|
||||
* Message header for recvmsg and sendmsg calls.
|
||||
* Used value-result for recvmsg, value only for sendmsg.
|
||||
}
|
||||
p_msghdr=^t_msghdr;
|
||||
t_msghdr=packed record
|
||||
msg_name :Pointer; { optional address }
|
||||
msg_namelen :socklen_t; { size of address }
|
||||
_align1 :Integer;
|
||||
msg_iov :p_iovec; { scatter/gather array }
|
||||
msg_iovlen :Integer; { # elements in msg_iov }
|
||||
_align2 :Integer;
|
||||
msg_control :Pointer; { ancillary data, see below }
|
||||
msg_controllen:socklen_t; { ancillary data buffer len }
|
||||
msg_flags :Integer; { flags on received message }
|
||||
end;
|
||||
|
||||
const
|
||||
MSG_OOB =$1 ; { process out-of-band data }
|
||||
MSG_PEEK =$2 ; { peek at incoming message }
|
||||
MSG_DONTROUTE =$4 ; { send without using routing tables }
|
||||
MSG_EOR =$8 ; { data completes record }
|
||||
MSG_TRUNC =$10 ; { data discarded before delivery }
|
||||
MSG_CTRUNC =$20 ; { control data lost before delivery }
|
||||
MSG_WAITALL =$40 ; { wait for full request or error }
|
||||
MSG_NOTIFICATION=$2000 ; { SCTP notification }
|
||||
MSG_DONTWAIT =$80 ; { this message should be nonblocking }
|
||||
MSG_EOF =$100 ; { data completes connection }
|
||||
MSG_NBIO =$4000 ; { FIONBIO mode, used by fifofs }
|
||||
MSG_COMPAT =$8000 ; { used in sendit() }
|
||||
MSG_SOCALLBCK =$10000; { for use by socket callbacks - soreceive (TCP) }
|
||||
MSG_NOSIGNAL =$20000; { do not generate SIGPIPE on EOF }
|
||||
|
||||
type
|
||||
{
|
||||
* Header for ancillary data objects in msg_control buffer.
|
||||
* Used for additional information with/about a datagram
|
||||
* not expressible by flags. The format is a sequence
|
||||
* of message elements headed by cmsghdr structures.
|
||||
}
|
||||
p_cmsghdr=^t_cmsghdr;
|
||||
t_cmsghdr=packed record
|
||||
cmsg_len:socklen_t; { data byte count, including hdr }
|
||||
cmsg_level:Integer; { originating protocol }
|
||||
cmsg_type:Integer; { protocol-specific type }
|
||||
{ followed by u_char cmsg_data[]; }
|
||||
end;
|
||||
|
||||
const
|
||||
{
|
||||
* While we may have more groups than this, the cmsgcred struct must
|
||||
* be able to fit in an mbuf and we have historically supported a
|
||||
* maximum of 16 groups.
|
||||
}
|
||||
CMGROUP_MAX=16;
|
||||
|
||||
{ "Socket"-level control message types: }
|
||||
SCM_RIGHTS =$01; { access rights (array of int) }
|
||||
SCM_TIMESTAMP=$02; { timestamp (struct timeval) }
|
||||
SCM_CREDS =$03; { process creds (struct cmsgcred) }
|
||||
SCM_BINTIME =$04; { timestamp (struct bintime) }
|
||||
|
||||
{
|
||||
* howto arguments for shutdown(2), specified by Posix.1g.
|
||||
}
|
||||
SHUT_RD =0; { shut down the reading side }
|
||||
SHUT_WR =1; { shut down the writing side }
|
||||
SHUT_RDWR=2; { shut down both sides }
|
||||
|
||||
{ we cheat and use the SHUT_XX defines for these }
|
||||
PRU_FLUSH_RD =SHUT_RD ;
|
||||
PRU_FLUSH_WR =SHUT_WR ;
|
||||
PRU_FLUSH_RDWR=SHUT_RDWR;
|
||||
|
||||
type
|
||||
{
|
||||
* sendfile(2) header/trailer struct
|
||||
}
|
||||
p_sf_hdtr=^t_sf_hdtr;
|
||||
t_sf_hdtr=packed record
|
||||
headers :p_iovec; { pointer to an array of header struct iovec's }
|
||||
hdr_cnt :Integer; { number of header iovec's }
|
||||
_align :Integer;
|
||||
trailers:p_iovec; { pointer to an array of trailer struct iovec's }
|
||||
trl_cnt :Integer; { number of trailer iovec's }
|
||||
end;
|
||||
|
||||
const
|
||||
{
|
||||
* Sendfile-specific flag(s)
|
||||
}
|
||||
SF_NODISKIO=$00000001;
|
||||
SF_MNOWAIT =$00000002;
|
||||
SF_SYNC =$00000004;
|
||||
|
||||
function CMSG_ALIGN(p:ptrint):ptrint; inline;
|
||||
function CMSG_DATA(cmsg:Pointer):Pointer; inline;
|
||||
function CMSG_FIRSTHDR(mhdr:p_msghdr):p_msghdr; inline;
|
||||
function CMSG_NXTHDR(mhdr:p_msghdr;cmsg:p_cmsghdr):p_msghdr; inline;
|
||||
function CMSG_SPACE(l:Ptruint):Ptruint;
|
||||
function CMSG_LEN(l:Ptruint):Ptruint;
|
||||
|
||||
implementation
|
||||
|
||||
const
|
||||
_ALIGNBYTES=SizeOf(ptrint)-1;
|
||||
|
||||
function CMSG_ALIGN(p:ptrint):ptrint; inline;
|
||||
begin
|
||||
Result:=(p+_ALIGNBYTES) and (not _ALIGNBYTES);
|
||||
end;
|
||||
|
||||
{ given pointer to struct cmsghdr, return pointer to data }
|
||||
function CMSG_DATA(cmsg:Pointer):Pointer; inline;
|
||||
begin
|
||||
Result:=cmsg+CMSG_ALIGN(SizeOf(t_cmsghdr));
|
||||
end;
|
||||
|
||||
{
|
||||
* RFC 2292 requires to check msg_controllen, in case that the kernel returns
|
||||
* an empty list for some reasons.
|
||||
}
|
||||
function CMSG_FIRSTHDR(mhdr:p_msghdr):p_msghdr; inline;
|
||||
begin
|
||||
if (mhdr^.msg_controllen>=SizeOf(t_cmsghdr)) then
|
||||
Result:=mhdr^.msg_control
|
||||
else
|
||||
Result:=nil;
|
||||
end;
|
||||
|
||||
{ given pointer to struct cmsghdr, return pointer to next cmsghdr }
|
||||
function CMSG_NXTHDR(mhdr:p_msghdr;cmsg:p_cmsghdr):p_msghdr; inline;
|
||||
begin
|
||||
if (cmsg=nil) then
|
||||
Result:=CMSG_FIRSTHDR(mhdr)
|
||||
else
|
||||
if (Ptruint(cmsg)+CMSG_ALIGN(cmsg^.cmsg_len)+CMSG_ALIGN(SizeOf(t_cmsghdr)))>
|
||||
(Ptruint(mhdr^.msg_control)+mhdr^.msg_controllen) then
|
||||
begin
|
||||
Result:=nil;
|
||||
end else
|
||||
begin
|
||||
Result:=Pointer(cmsg)+CMSG_ALIGN(cmsg^.cmsg_len);
|
||||
end;
|
||||
end;
|
||||
|
||||
{ RFC 2292 additions }
|
||||
function CMSG_SPACE(l:Ptruint):Ptruint;
|
||||
begin
|
||||
Result:=CMSG_ALIGN(SizeOf(t_cmsghdr))+CMSG_ALIGN(l);
|
||||
end;
|
||||
|
||||
function CMSG_LEN(l:Ptruint):Ptruint;
|
||||
begin
|
||||
Result:=CMSG_ALIGN(SizeOf(t_cmsghdr))+l;
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
|
@ -0,0 +1,305 @@
|
|||
unit vsocketvar;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
{$CALLING SysV_ABI_CDecl}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
mqueue,
|
||||
vfile,
|
||||
vselinfo,
|
||||
vsocket,
|
||||
vsockstate,
|
||||
vsockbuf,
|
||||
kern_mtx;
|
||||
|
||||
//#include <sys/sockopt.h>
|
||||
|
||||
{
|
||||
* Kernel structure per socket.
|
||||
* Contains send and receive buffer queues,
|
||||
* handle on protocol and pointer to protocol
|
||||
* private data and error information.
|
||||
}
|
||||
type
|
||||
so_gen_t=QWORD;
|
||||
|
||||
t_accf_callback=function(so,arg:Pointer;waitflag:Integer):Integer;
|
||||
t_accf_create =function(so,arg:Pointer):Pointer;
|
||||
t_accf_destroy =procedure(so:Pointer);
|
||||
|
||||
p_accept_filter=^t_accept_filter;
|
||||
t_accept_filter=packed record
|
||||
accf_name :array[0..15] of AnsiChar;
|
||||
accf_callback:t_accf_callback;
|
||||
accf_create :t_accf_create ;
|
||||
accf_destroy :t_accf_destroy ;
|
||||
accf_next :SLIST_ENTRY ;
|
||||
end;
|
||||
|
||||
{-
|
||||
* Locking key to struct socket:
|
||||
* (a) constant after allocation, no locking required.
|
||||
* (b) locked by SOCK_LOCK(so).
|
||||
* (c) locked by SOCKBUF_LOCK(@so^.so_rcv).
|
||||
* (d) locked by SOCKBUF_LOCK(@so^.so_snd).
|
||||
* (e) locked by ACCEPT_LOCK().
|
||||
* (f) not locked since integer reads/writes are atomic.
|
||||
* (g) used only as a sleep/wakeup address, no value.
|
||||
* (h) locked by global mutex so_global_mtx.
|
||||
}
|
||||
pp_socket=^p_socket;
|
||||
p_socket=^t_socket;
|
||||
t_socket=packed record
|
||||
so_count :Integer; { (b) reference count }
|
||||
so_type :Word; { (a) generic type, see socket.h }
|
||||
so_options:Word; { from socket call, see socket.h }
|
||||
so_linger :Word; { time to linger while closing }
|
||||
so_state :Word; { (b) internal state flags SS_* }
|
||||
so_qstate :Integer; { (e) internal state flags SQ_* }
|
||||
so_pcb :Pointer; { protocol control block }
|
||||
so_vnet :Pointer; { network stack instance }
|
||||
so_proto :Pointer; { (a) protocol handle }
|
||||
{
|
||||
* Variables for connection queuing.
|
||||
* Socket where accepts occur is so_head in all subsidiary sockets.
|
||||
* If so_head is 0, socket is not related to an accept.
|
||||
* For head socket so_incomp queues partially completed connections,
|
||||
* while so_comp is a queue of connections ready to be accepted.
|
||||
* If a connection is aborted and it has so_head set, then
|
||||
* it has to be pulled out of either so_incomp or so_comp.
|
||||
* We allow connections to queue up based on current queue lengths
|
||||
* and limit on number of queued connections for this socket.
|
||||
}
|
||||
so_head :p_socket ; { (e) back pointer to listen socket }
|
||||
so_incomp :TAILQ_HEAD ; { (e) queue of partial unaccepted connections }
|
||||
so_comp :TAILQ_HEAD ; { (e) queue of complete unaccepted connections }
|
||||
so_list :TAILQ_ENTRY; { (e) list of unaccepted connections }
|
||||
so_qlen :Word ; { (e) number of unaccepted connections }
|
||||
so_incqlen:Word ; { (e) number of unaccepted incomplete connections }
|
||||
so_qlimit :Word ; { (e) max number queued connections }
|
||||
so_timeo :Word ; { (g) connection timeout }
|
||||
so_error :Word ; { (f) error affecting connection }
|
||||
so_sigio :Pointer ; { [sg] information for async I/O or out of band data (SIGURG) }
|
||||
so_oobmark:QWORD ; { (c) chars to oob mark }
|
||||
so_aiojobq:TAILQ_HEAD ; { AIO ops waiting on socket }
|
||||
|
||||
so_rcv :t_sockbuf;
|
||||
so_snd :t_sockbuf;
|
||||
|
||||
//label *so_label ; { (b) MAC label for socket }
|
||||
//label *so_peerlabel ; { (b) cached MAC label for peer }
|
||||
{ NB: generation count must not be first. }
|
||||
so_gencnt :so_gen_t; { (h) generation count }
|
||||
so_emuldata:Pointer ; { (b) private data for emulators }
|
||||
|
||||
so_accf:packed record
|
||||
so_accept_filter :p_accept_filter;
|
||||
so_accept_filter_arg:Pointer; { saved filter args }
|
||||
so_accept_filter_str:Pointer; { saved user args }
|
||||
end;
|
||||
{
|
||||
* so_fibnum, so_user_cookie and friends can be used to attach
|
||||
* some user-specified metadata to a socket, which then can be
|
||||
* used by the kernel for various actions.
|
||||
* so_user_cookie is used by ipfw/dummynet.
|
||||
}
|
||||
so_fibnum :Integer; { routing domain for this socket }
|
||||
so_user_cookie:DWORD;
|
||||
end;
|
||||
|
||||
{
|
||||
* Global accept mutex to serialize access to accept queues and
|
||||
* fields associated with multiple sockets. This allows us to
|
||||
* avoid defining a lock order between listen and accept sockets
|
||||
* until such time as it proves to be a good idea.
|
||||
}
|
||||
var
|
||||
accept_mtx:mtx;
|
||||
|
||||
const
|
||||
{
|
||||
* Socket state bits stored in so_qstate.
|
||||
}
|
||||
SQ_INCOMP=$0800; { unaccepted, incomplete connection }
|
||||
SQ_COMP =$1000; { unaccepted, complete connection }
|
||||
|
||||
type
|
||||
{
|
||||
* Externalized form of struct socket used by the sysctl(3) interface.
|
||||
}
|
||||
xsocket=packed record
|
||||
xso_len :QWORD ; { length of this structure }
|
||||
xso_so :p_socket; { makes a convenient handle sometimes }
|
||||
so_type :Word;
|
||||
so_options :Word;
|
||||
so_linger :Word;
|
||||
so_state :Word;
|
||||
so_pcb :Pointer; { another convenient handle }
|
||||
xso_protocol:Integer;
|
||||
xso_family :Integer;
|
||||
so_qlen :Word;
|
||||
so_incqlen :Word;
|
||||
so_qlimit :Word;
|
||||
so_timeo :Word;
|
||||
so_error :Word;
|
||||
so_pgid :Integer;
|
||||
so_oobmark :QWORD;
|
||||
so_rcv :t_xsockbuf;
|
||||
so_snd :t_xsockbuf;
|
||||
so_uid :uid_t; { XXX }
|
||||
end;
|
||||
|
||||
{
|
||||
* Macros for sockets and socket buffering.
|
||||
}
|
||||
|
||||
const
|
||||
{
|
||||
* Flags to sblock().
|
||||
}
|
||||
SBL_WAIT =$00000001; { Wait if not immediately available. }
|
||||
SBL_NOINTR=$00000002; { Force non-interruptible sleep. }
|
||||
SBL_VALID =(SBL_WAIT or SBL_NOINTR);
|
||||
|
||||
{ 'which' values for socket upcalls. }
|
||||
SO_RCV=1;
|
||||
SO_SND=2;
|
||||
|
||||
{ Return values for socket upcalls. }
|
||||
SU_OK =0;
|
||||
SU_ISCONNECTED=1;
|
||||
|
||||
procedure ACCEPT_LOCK_ASSERT(); inline;
|
||||
procedure ACCEPT_LOCK(); inline;
|
||||
procedure ACCEPT_UNLOCK(); inline;
|
||||
|
||||
function SOCK_MTX(_so:p_socket):p_mtx; inline;
|
||||
procedure SOCK_LOCK(_so:p_socket); inline;
|
||||
function SOCK_OWNED(_so:p_socket):Boolean; inline;
|
||||
procedure SOCK_UNLOCK(_so:p_socket); inline;
|
||||
procedure SOCK_LOCK_ASSERT(_so:p_socket); inline;
|
||||
|
||||
function sb_notify(sb:p_sockbuf):Boolean; inline;
|
||||
function sosendallatonce(so:p_socket):Boolean; inline;
|
||||
function soreadabledata(so:p_socket):Boolean; inline;
|
||||
function soreadable(so:p_socket):Boolean; inline;
|
||||
function sowriteable(so:p_socket):Boolean; inline;
|
||||
procedure soref(so:p_socket);
|
||||
procedure sorele(so:p_socket);
|
||||
|
||||
implementation
|
||||
|
||||
procedure ACCEPT_LOCK_ASSERT(); inline;
|
||||
begin
|
||||
mtx_assert(accept_mtx);
|
||||
end;
|
||||
|
||||
procedure ACCEPT_LOCK(); inline;
|
||||
begin
|
||||
mtx_lock(accept_mtx);
|
||||
end;
|
||||
|
||||
procedure ACCEPT_UNLOCK(); inline;
|
||||
begin
|
||||
mtx_unlock(accept_mtx);
|
||||
end;
|
||||
|
||||
//
|
||||
|
||||
function SOCK_MTX(_so:p_socket):p_mtx; inline;
|
||||
begin
|
||||
Result:=SOCKBUF_MTX(@_so^.so_rcv)
|
||||
end;
|
||||
|
||||
procedure SOCK_LOCK(_so:p_socket); inline;
|
||||
begin
|
||||
SOCKBUF_LOCK(@_so^.so_rcv)
|
||||
end;
|
||||
|
||||
function SOCK_OWNED(_so:p_socket):Boolean; inline;
|
||||
begin
|
||||
Result:=SOCKBUF_OWNED(@_so^.so_rcv);
|
||||
end;
|
||||
|
||||
procedure SOCK_UNLOCK(_so:p_socket); inline;
|
||||
begin
|
||||
SOCKBUF_UNLOCK(@_so^.so_rcv)
|
||||
end;
|
||||
|
||||
procedure SOCK_LOCK_ASSERT(_so:p_socket); inline;
|
||||
begin
|
||||
SOCKBUF_LOCK_ASSERT(@_so^.so_rcv);
|
||||
end;
|
||||
|
||||
//
|
||||
|
||||
{
|
||||
* Do we need to notify the other side when I/O is possible?
|
||||
}
|
||||
function sb_notify(sb:p_sockbuf):Boolean; inline;
|
||||
begin
|
||||
Result:=(sb^.sb_flags and (SB_WAIT or SB_SEL or SB_ASYNC or SB_UPCALL or SB_AIO or SB_KNOTE))<>0;
|
||||
end;
|
||||
|
||||
{ do we have to send all at once on a socket? }
|
||||
function sosendallatonce(so:p_socket):Boolean; inline;
|
||||
begin
|
||||
//Result:=((so^.so_proto^.pr_flags and PR_ATOMIC)<>0);
|
||||
Result:=False;
|
||||
end;
|
||||
|
||||
{ can we read something from so? }
|
||||
function soreadabledata(so:p_socket):Boolean; inline;
|
||||
begin
|
||||
Result:=(so^.so_rcv.sb_cc >= so^.so_rcv.sb_lowat) or
|
||||
(not TAILQ_EMPTY(@so^.so_comp)) or (so^.so_error<>0);
|
||||
end;
|
||||
|
||||
function soreadable(so:p_socket):Boolean; inline;
|
||||
begin
|
||||
Result:=soreadabledata(so) or ((so^.so_rcv.sb_state and SBS_CANTRCVMORE)<>0);
|
||||
end;
|
||||
|
||||
{ can we write something to so? }
|
||||
function sowriteable(so:p_socket):Boolean; inline;
|
||||
begin
|
||||
Result:=((sbspace(@so^.so_snd)>=so^.so_snd.sb_lowat) and
|
||||
(((so^.so_state and SS_ISCONNECTED)<>0) or
|
||||
({(so^.so_proto^.pr_flags and PR_CONNREQUIRED)=0}False))) or
|
||||
((so^.so_snd.sb_state and SBS_CANTSENDMORE)<>0) or
|
||||
(so^.so_error<>0);
|
||||
end;
|
||||
|
||||
{
|
||||
* soref()/sorele() ref-count the socket structure. Note that you must
|
||||
* still explicitly close the socket, but the last ref count will free
|
||||
* the structure.
|
||||
}
|
||||
procedure soref(so:p_socket);
|
||||
begin
|
||||
SOCK_LOCK_ASSERT(so);
|
||||
Inc(so^.so_count);
|
||||
end;
|
||||
|
||||
procedure sorele(so:p_socket);
|
||||
begin
|
||||
ACCEPT_LOCK_ASSERT();
|
||||
SOCK_LOCK_ASSERT(so);
|
||||
if (so^.so_count <= 0) then
|
||||
Assert(false,'sorele');
|
||||
Dec(so^.so_count);
|
||||
if (so^.so_count=0) then
|
||||
begin
|
||||
//sofree(so);
|
||||
end else
|
||||
begin
|
||||
SOCK_UNLOCK(so);
|
||||
ACCEPT_UNLOCK();
|
||||
end
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
unit vsockstate;
|
||||
|
||||
{$mode ObjFPC}{$H+}
|
||||
{$CALLING SysV_ABI_CDecl}
|
||||
|
||||
interface
|
||||
|
||||
const
|
||||
{
|
||||
* Socket state bits.
|
||||
*
|
||||
* Historically, this bits were all kept in the so_state field. For
|
||||
* locking reasons, they are now in multiple fields, as they are
|
||||
* locked differently. so_state maintains basic socket state protected
|
||||
* by the socket lock. so_qstate holds information about the socket
|
||||
* accept queues. Each socket buffer also has a state field holding
|
||||
* information relevant to that socket buffer (can't send, rcv). Many
|
||||
* fields will be read without locks to improve performance and avoid
|
||||
* lock order issues. However, this approach must be used with caution.
|
||||
}
|
||||
SS_NOFDREF =$0001; { no file table ref any more }
|
||||
SS_ISCONNECTED =$0002; { socket connected to a peer }
|
||||
SS_ISCONNECTING =$0004; { in process of connecting to peer }
|
||||
SS_ISDISCONNECTING=$0008; { in process of disconnecting }
|
||||
SS_NBIO =$0100; { non-blocking ops }
|
||||
SS_ASYNC =$0200; { async i/o notify }
|
||||
SS_ISCONFIRMING =$0400; { deciding to accept connection req }
|
||||
SS_ISDISCONNECTED =$2000; { socket disconnected from peer }
|
||||
|
||||
{
|
||||
* Protocols can mark a socket as SS_PROTOREF to indicate that, following
|
||||
* pru_detach, they still want the socket to persist, and will free it
|
||||
* themselves when they are done. Protocols should only ever call sofree()
|
||||
* following setting this flag in pru_detach(), and never otherwise, as
|
||||
* sofree() bypasses socket reference counting.
|
||||
}
|
||||
SS_PROTOREF =$4000; { strong protocol reference }
|
||||
|
||||
{
|
||||
* Socket state bits now stored in the socket buffer state field.
|
||||
}
|
||||
SBS_CANTSENDMORE=$0010; { can't send more data to peer }
|
||||
SBS_CANTRCVMORE =$0020; { can't receive more data from peer }
|
||||
SBS_RCVATMARK =$0040; { at mark on input }
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -21,6 +21,7 @@ type
|
|||
UIO_NOCOPY // don't copy, already in object
|
||||
);
|
||||
|
||||
pp_uio=^p_uio;
|
||||
p_uio=^t_uio;
|
||||
t_uio=packed record
|
||||
uio_iov :p_iovec; // scatter/gather list
|
||||
|
|
|
@ -307,7 +307,7 @@ procedure vm_map_zinit(map:vm_map_t);
|
|||
begin
|
||||
map^.nentries:=0;
|
||||
map^.size:=0;
|
||||
mtx_init(map^.lock);
|
||||
mtx_init(map^.lock,'vm map (system)');
|
||||
end;
|
||||
|
||||
function vmspace_pmap(vm:p_vmspace):pmap_t; inline;
|
||||
|
@ -433,7 +433,7 @@ end;
|
|||
procedure vm_map_init(map:vm_map_t;pmap:pmap_t;min,max:vm_offset_t);
|
||||
begin
|
||||
_vm_map_init(map, pmap, min, max);
|
||||
mtx_init(map^.lock);
|
||||
mtx_init(map^.lock,'user map');
|
||||
end;
|
||||
|
||||
{
|
||||
|
|
|
@ -134,7 +134,7 @@ function vm_object_allocate(t:objtype_t;size:vm_pindex_t):vm_object_t;
|
|||
begin
|
||||
Result:=AllocMem(SizeOf(_vm_object));
|
||||
|
||||
mtx_init(Result^.mtx);
|
||||
mtx_init(Result^.mtx,'vm_object');
|
||||
|
||||
TAILQ_INIT(@Result^.memq);
|
||||
|
||||
|
|
Loading…
Reference in New Issue