FPPS4/sys/kern/kern_condvar.pas

332 lines
5.5 KiB
Plaintext

unit kern_condvar;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
time,
kern_thr,
sys_sleepqueue;
type
p_cv=^t_cv;
t_cv=packed record
cv_description:Pchar;
cv_waiters :Integer;
end;
const
max_cv_waiters=$7fffffff;
procedure cv_init(cvp:p_cv;desc:Pchar);
procedure cv_destroy(cvp:p_cv);
procedure _cv_wait(cvp:p_cv;lock:Pointer);
procedure _cv_wait_unlock(cvp:p_cv;lock:Pointer);
function _cv_wait_sig(cvp:p_cv;lock:Pointer):Integer;
function _cv_timedwait(cvp:p_cv;lock:Pointer;timo:Int64):Integer;
function _cv_timedwait_sig(cvp:p_cv;lock:Pointer;timo:Int64):Integer;
function _cv_timedwait_sig_proctime(cvp:p_cv;lock:Pointer;timeout:p_timespec):Integer;
procedure cv_signal(cvp:p_cv);
procedure cv_signalto(cvp:p_cv;td:p_kthread);
procedure cv_broadcastpri(cvp:p_cv;pri:Integer);
implementation
uses
errno,
kern_mtx,
md_time;
function IS_SLEEPABLE(lock:Pointer):Boolean; inline;
begin
Result:=False;
end;
procedure lc_lock(lock:Pointer); inline;
begin
mtx_lock(p_mtx(lock)^);
end;
procedure lc_unlock(lock:Pointer); inline;
begin
mtx_unlock(p_mtx(lock)^);
end;
procedure cv_init(cvp:p_cv;desc:Pchar);
begin
cvp^.cv_description:=desc;
cvp^.cv_waiters :=0;
end;
procedure cv_destroy(cvp:p_cv);
begin
//
end;
procedure CV_ASSERT(cvp:p_cv;lock,td:Pointer);
begin
Assert(td<>nil,'td nil');
Assert(TD_IS_RUNNING(td),'not TDS_RUNNING');
Assert(cvp<>nil,'cvp nil');
Assert(lock<>nil,'lock nil');
end;
procedure _cv_wait(cvp:p_cv;lock:Pointer);
var
td:p_kthread;
begin
td:=curkthread;
CV_ASSERT(cvp,lock,td);
sleepq_lock(cvp);
if (cvp^.cv_waiters<>max_cv_waiters) then
begin
Inc(cvp^.cv_waiters);
end;
sleepq_add(cvp,lock,cvp^.cv_description,SLEEPQ_CONDVAR,0);
if IS_SLEEPABLE(lock) then
begin
sleepq_release(cvp);
end;
lc_unlock(lock);
if IS_SLEEPABLE(lock) then
begin
sleepq_lock(cvp);
end;
sleepq_wait(cvp,0);
lc_lock(lock);
end;
procedure _cv_wait_unlock(cvp:p_cv;lock:Pointer);
var
td:p_kthread;
begin
td:=curkthread;
CV_ASSERT(cvp,lock,td);
sleepq_lock(cvp);
if (cvp^.cv_waiters<>max_cv_waiters) then
begin
Inc(cvp^.cv_waiters);
end;
sleepq_add(cvp,lock,cvp^.cv_description,SLEEPQ_CONDVAR,0);
if IS_SLEEPABLE(lock) then
begin
sleepq_release(cvp);
end;
lc_unlock(lock);
if IS_SLEEPABLE(lock) then
begin
sleepq_lock(cvp);
end;
sleepq_wait(cvp,0);
end;
function _cv_wait_sig(cvp:p_cv;lock:Pointer):Integer;
var
td:p_kthread;
begin
td:=curkthread;
CV_ASSERT(cvp,lock,td);
sleepq_lock(cvp);
if (cvp^.cv_waiters<>max_cv_waiters) then
begin
Inc(cvp^.cv_waiters);
end;
sleepq_add(cvp,lock,cvp^.cv_description,SLEEPQ_CONDVAR or SLEEPQ_INTERRUPTIBLE,0);
if IS_SLEEPABLE(lock) then
begin
sleepq_release(cvp);
end;
lc_unlock(lock);
if IS_SLEEPABLE(lock) then
begin
sleepq_lock(cvp);
end;
Result:=sleepq_wait_sig(cvp,0);
lc_lock(lock);
end;
function _cv_timedwait(cvp:p_cv;lock:Pointer;timo:Int64):Integer;
var
td:p_kthread;
begin
td:=curkthread;
CV_ASSERT(cvp,lock,td);
sleepq_lock(cvp);
if (cvp^.cv_waiters<>max_cv_waiters) then
begin
Inc(cvp^.cv_waiters);
end;
sleepq_add(cvp,lock,cvp^.cv_description,SLEEPQ_CONDVAR,0);
sleepq_set_timeout(cvp,timo);
if IS_SLEEPABLE(lock) then
begin
sleepq_release(cvp);
end;
lc_unlock(lock);
if IS_SLEEPABLE(lock) then
begin
sleepq_lock(cvp);
end;
Result:=sleepq_timedwait(cvp,0);
lc_lock(lock);
end;
function _cv_timedwait_sig(cvp:p_cv;lock:Pointer;timo:Int64):Integer;
var
td:p_kthread;
begin
td:=curkthread;
CV_ASSERT(cvp,lock,td);
sleepq_lock(cvp);
if (cvp^.cv_waiters<>max_cv_waiters) then
begin
Inc(cvp^.cv_waiters);
end;
sleepq_add(cvp,lock,cvp^.cv_description,SLEEPQ_CONDVAR or SLEEPQ_INTERRUPTIBLE,0);
sleepq_set_timeout(cvp,timo);
if IS_SLEEPABLE(lock) then
begin
sleepq_release(cvp);
end;
lc_unlock(lock);
if IS_SLEEPABLE(lock) then
begin
sleepq_lock(cvp);
end;
Result:=sleepq_timedwait_sig(cvp,0);
lc_lock(lock);
end;
function _cv_timedwait_sig_proctime(cvp:p_cv;lock:Pointer;timeout:p_timespec):Integer;
var
tv,ts,ts2:Int64;
begin
tv:=TIMESPEC_TO_UNIT(timeout);
ts:=get_unit_uptime;
ts:=ts+tv;
repeat
Result:=_cv_timedwait_sig(cvp,lock,tvtohz(tv));
if (Result<>EWOULDBLOCK) then Break;
ts2:=get_unit_uptime;
if (ts2>=ts) then
begin
Result:=EWOULDBLOCK;
Break;
end;
tv:=ts-ts2;
until false;
end;
procedure cv_signal(cvp:p_cv);
begin
sleepq_lock(cvp);
if (cvp^.cv_waiters>0) then
begin
if (cvp^.cv_waiters=max_cv_waiters) then
begin
if (sleepq_lookup(cvp)=nil) then
begin
cvp^.cv_waiters:=0;
end else
begin
if (cvp^.cv_waiters<>max_cv_waiters) then
begin
Dec(cvp^.cv_waiters);
end;
sleepq_signal(cvp,SLEEPQ_CONDVAR,0,0);
end;
end else
begin
Dec(cvp^.cv_waiters);
sleepq_signal(cvp,SLEEPQ_CONDVAR,0,0);
end;
end;
sleepq_release(cvp);
end;
procedure cv_signalto(cvp:p_cv;td:p_kthread);
begin
sleepq_lock(cvp);
if (cvp^.cv_waiters>0) then
begin
if (cvp^.cv_waiters=max_cv_waiters) then
begin
if (sleepq_lookup(cvp)=nil) then
begin
cvp^.cv_waiters:=0;
end else
begin
if (cvp^.cv_waiters<>max_cv_waiters) then
begin
Dec(cvp^.cv_waiters);
end;
sleepq_signalto(cvp,SLEEPQ_CONDVAR,0,0,td);
end;
end else
begin
Dec(cvp^.cv_waiters);
sleepq_signalto(cvp,SLEEPQ_CONDVAR,0,0,td);
end;
end;
sleepq_release(cvp);
end;
procedure cv_broadcastpri(cvp:p_cv;pri:Integer);
begin
if (pri=-1) then pri:=0;
sleepq_lock(cvp);
if (cvp^.cv_waiters>0) then
begin
cvp^.cv_waiters:=0;
sleepq_broadcast(cvp,SLEEPQ_CONDVAR,pri,0);
end;
sleepq_release(cvp);
end;
end.