unit md_timeout; {$mode ObjFPC}{$H+} {$CALLING SysV_ABI_CDecl} interface uses ntapi, // LFQueue, md_sleep, sched_ule, kern_synch, kern_thr, kern_callout; procedure md_start_softclock(); procedure md_callout_new_inserted(c:p_callout;cc:p_callout_cpu); procedure md_callout_reset(c:p_callout); procedure md_callout_stop(c:p_callout); procedure md_callout_done(c:p_callout); implementation uses kern_timeout; var timeout_thr:p_kthread=nil; timeout_new:TIntrusiveMPSCQueue=(tail_:@timeout_new.stub_;stub_:(next_:nil);head_:@timeout_new.stub_); procedure softclock(arg:Pointer); forward; procedure md_start_softclock(); var r:Integer; begin r:=kthread_add(@softclock,nil,@timeout_thr,0,'softclock'); Assert(r=0,'softclock'); end; procedure wt_event(arg:Pointer;dwTimerLowValue,dwTimerHighValue:DWORD); stdcall; var c:p_callout; cc:p_callout_cpu; begin if (arg=nil) then Exit; c:=arg; cc:=callout_lock(); softclock_call_cc(c,cc); CC_UNLOCK(cc); end; Procedure wt_timer_add(c:p_callout;cc:p_callout_cpu); var f:Int64; n:Integer; begin f:=-c^.c_time; n:=-1; if ((c^.c_flags and CALLOUT_PENDING)<>0) then begin n:=NtSetTimer(c^.c_timer, @f, @wt_event, c, false, 0, nil); end; if (n<>0) then begin if (cc^.cc_waiting<>0) then begin cc^.cc_waiting:=0; CC_UNLOCK(cc); wakeup(@cc^.cc_waiting); CC_LOCK(cc); end; Assert(((c^.c_flags and CALLOUT_LOCAL_ALLOC)=0) or (c^.c_flags=CALLOUT_LOCAL_ALLOC),'corrupted callout'); if ((c^.c_flags and CALLOUT_LOCAL_ALLOC)<>0) then begin callout_cc_del(c, cc); end; end; end; procedure md_callout_new_inserted(c:p_callout;cc:p_callout_cpu); var n:Integer; begin if (timeout_thr=curkthread) then begin wt_timer_add(c,cc); end else begin timeout_new.Push(c); n:=wakeup_td(timeout_thr); Assert(n=0,'md_callout_new_inserted'); end; end; procedure softclock(arg:Pointer); var c:p_callout; cc:p_callout_cpu; begin sched_prio(curkthread,64); repeat cc:=nil; c:=nil; while timeout_new.Pop(c) do begin cc:=callout_lock(); wt_timer_add(c,cc); CC_UNLOCK(cc); end; msleep_td(0); until false; end; procedure md_callout_reset(c:p_callout); var n:Integer; begin if (c^.c_timer=0) then begin n:=NtCreateTimer( @c^.c_timer, EVENT_ALL_ACCESS, nil, 0); Assert(n=0,'NtCreateTimer'); end else begin NtCancelTimer(c^.c_timer,nil); end; end; procedure md_callout_stop(c:p_callout); begin if (c^.c_timer<>0) then begin NtCancelTimer(c^.c_timer,nil); end; end; procedure md_callout_done(c:p_callout); begin if (c^.c_timer<>0) then begin NtClose(c^.c_timer); c^.c_timer:=0; end; end; end.