unit sys_vm_object;

{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}

interface

uses
 mqueue,
 vm,
 vmparam,
 kern_mtx;

type
 obj_type=(
   OBJT_DEFAULT  ,//0
   OBJT_SWAP     ,//1
   OBJT_VNODE    ,//2
   OBJT_DEVICE   ,//3
   OBJT_PHYS     ,//4
   OBJT_DEAD     ,//5
   OBJT_SG       ,//6
   OBJT_JITSHM   ,//7
   OBJT_SELF     ,//8
   OBJT_TRCMEM   ,//9
   OBJT_PHYSHM   ,//10
   OBJT_BLOCKPOOL //11
  );

 objtype_t=obj_type;

 p_vm_object_t=^vm_object_t;
 vm_object_t=^t_vm_object;
 t_vm_object=record
  mtx       :mtx;
  patchq    :TAILQ_HEAD;              // list of patches
  size      :vm_pindex_t;             // Object size
  generation:Integer;                 // generation ID
  ref_count :Integer;                 // How many refs??
  otype     :objtype_t;               // type of pager
  pg_color  :Word;
  flags     :Word;                    // see below
  pip       :Integer;
  budget_id :Integer;
  handle    :Pointer;
  un_pager  :record
   map_base:Pointer;
   vnp:record
    vnp_size:QWORD;
    writemappings:vm_ooffset_t;
   end;
   physhm:record
    mtype   :Byte;
   end;
  end;
 end;

const
 //Flags
 OBJ_ACTIVE       =$0004; // active objects
 OBJ_DEAD         =$0008; // dead objects (during rundown)
 OBJ_NOSPLIT      =$0010; // dont split this object
 OBJ_PIPWNT       =$0040; // paging in progress wanted
 OBJ_MIGHTBEDIRTY =$0100; // object might be dirty, only for vnode
 OBJ_COLORED      =$1000; // pg_color is defined
 OBJ_ONEMAPPING   =$2000; // One USE (a single, non-forked) mapping flag
 OBJ_DISCONNECTWNT=$4000; // disconnect from vnode wanted
 OBJ_DMEM_EXT     =$8000; // direct  memory
 OBJ_JITSHM_EXT   =$0020; // jitshim memory
 OBJ_WIRE_BUDGET  =$0080; // wire state in budget

 OBJPC_SYNC  =$1;  // sync I/O
 OBJPC_INVAL =$2;  // invalidate
 OBJPC_NOSYNC=$4;  // skip if PG_NOSYNC

 //The following options are supported by vm_object_page_remove().
 OBJPR_CLEANONLY=$1; // Don't remove dirty pages.
 OBJPR_NOTMAPPED=$2; // Don't unmap pages.
 OBJPR_NOTWIRED =$4; // Don't remove wired pages.

function  VM_OBJECT_MTX(obj:vm_object_t):p_mtx;
procedure VM_OBJECT_LOCK(obj:vm_object_t);
function  VM_OBJECT_TRYLOCK(obj:vm_object_t):Boolean;
procedure VM_OBJECT_UNLOCK(obj:vm_object_t);
function  VM_OBJECT_LOCKED(obj:vm_object_t):Boolean;
procedure VM_OBJECT_LOCK_ASSERT(obj:vm_object_t);

procedure vm_object_set_flag(obj:vm_object_t;bits:Word);
procedure vm_object_clear_flag(obj:vm_object_t;bits:Word);

procedure vm_object_set_budget(obj:vm_object_t;budget_id:Integer);

function  vm_object_allocate(t:objtype_t;size:vm_pindex_t):vm_object_t;
procedure vm_object_destroy(obj:vm_object_t);
procedure vm_object_reference(obj:vm_object_t);

procedure vm_object_pip_add(obj:vm_object_t;i:word);
procedure vm_object_pip_subtract(obj:vm_object_t;i:word);
function  vm_object_type(obj:vm_object_t):obj_type;

procedure vm_object_patch_remove(_obj:Pointer;start,__end:DWORD); external;

procedure vm_object_deallocate(obj:vm_object_t); external;

procedure vm_object_collapse(obj:vm_object_t); external;

function  vm_object_coalesce(prev_object:vm_object_t;
                             prev_offset:vm_ooffset_t;
                             prev_size  :vm_ooffset_t;
                             next_size  :vm_ooffset_t;
                             reserved   :Boolean):Boolean; external;

procedure vm_object_page_remove(obj:vm_object_t;
                                start:vm_pindex_t;
                                __end:vm_pindex_t;
                                options:Integer); external;

function  vm_object_page_clean(obj:vm_object_t;
                               start,__end:vm_ooffset_t;
                               flags:Integer):Boolean; external;

implementation

uses
 vnode;

//

procedure vref(vp:p_vnode); external;

//

function VM_OBJECT_MTX(obj:vm_object_t):p_mtx;
begin
 Result:=@obj^.mtx;
end;

procedure VM_OBJECT_LOCK(obj:vm_object_t);
begin
 mtx_lock(obj^.mtx);
end;

function VM_OBJECT_TRYLOCK(obj:vm_object_t):Boolean;
begin
 Result:=mtx_trylock(obj^.mtx);
end;

procedure VM_OBJECT_UNLOCK(obj:vm_object_t);
begin
 mtx_unlock(obj^.mtx);
end;

function VM_OBJECT_LOCKED(obj:vm_object_t):Boolean;
begin
 Result:=(mtx_owned(obj^.mtx));
end;

procedure VM_OBJECT_LOCK_ASSERT(obj:vm_object_t);
begin
 Assert(mtx_owned(obj^.mtx));
end;

procedure vm_object_set_flag(obj:vm_object_t;bits:Word);
begin
 VM_OBJECT_LOCK_ASSERT(obj);
 obj^.flags:=obj^.flags or bits;
end;

procedure vm_object_clear_flag(obj:vm_object_t;bits:Word);
begin
 VM_OBJECT_LOCK_ASSERT(obj);
 obj^.flags:=obj^.flags and (not bits);
end;

procedure vm_object_set_budget(obj:vm_object_t;budget_id:Integer);
begin
 obj^.budget_id:=budget_id;
end;

function vm_object_allocate(t:objtype_t;size:vm_pindex_t):vm_object_t;
begin
 Result:=AllocMem(SizeOf(t_vm_object));

 mtx_init(Result^.mtx,'vm_object');

 TAILQ_INIT(@Result^.patchq);

 Result^.otype     :=t;
 Result^.size      :=size;
 Result^.generation:=1;
 Result^.ref_count :=1;

 Result^.budget_id :=-1;
 //Result^.vm_container:=0;

 case t of
  OBJT_DEFAULT:
    begin
     Result^.flags:=OBJ_ONEMAPPING;
    end;
  else;
 end;

end;

procedure vm_object_destroy(obj:vm_object_t);
begin
 mtx_destroy(obj^.mtx);

 FreeMem(obj);
end;

procedure vm_object_reference(obj:vm_object_t);
begin
 if (obj=nil) then Exit;

 VM_OBJECT_LOCK(obj);

  Inc(obj^.ref_count);

  if (obj^.otype=OBJT_VNODE) then
  begin
   if (obj^.otype=OBJT_VNODE) then
   begin
    vref(obj^.handle);
   end;
  end;

 VM_OBJECT_UNLOCK(obj);
end;

procedure vm_object_pip_add(obj:vm_object_t;i:word);
begin
 if (obj=nil) then Exit;

 VM_OBJECT_LOCK_ASSERT(obj);
 obj^.pip:=obj^.pip+i;
end;

procedure vm_object_pip_subtract(obj:vm_object_t;i:word);
begin
 if (obj=nil) then Exit;

 VM_OBJECT_LOCK_ASSERT(obj);
 obj^.pip:=obj^.pip-i;
end;

function vm_object_type(obj:vm_object_t):obj_type;
begin
 if (obj=nil) then Exit(OBJT_DEFAULT);

 Result:=obj^.otype;
end;


end.




