mirror of https://github.com/red-prig/fpPS4.git
276 lines
4.9 KiB
Plaintext
276 lines
4.9 KiB
Plaintext
unit kern_synch;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
sys_sleepqueue,
|
|
kern_param,
|
|
kern_mtx,
|
|
kern_thr;
|
|
|
|
function msleep(ident :Pointer;
|
|
lock :p_mtx;
|
|
priority:Integer;
|
|
wmesg :PChar;
|
|
timo :Int64):Integer;
|
|
|
|
function tsleep(ident :Pointer;
|
|
priority:Integer;
|
|
wmesg :PChar;
|
|
timo :Int64):Integer;
|
|
|
|
function pause(wmesg:PChar;timo:Int64):Integer;
|
|
|
|
procedure wakeup(ident:Pointer);
|
|
procedure wakeup_one(ident:Pointer);
|
|
function mi_switch(flags:Integer):Integer;
|
|
|
|
procedure maybe_yield();
|
|
procedure kern_yield(prio:Integer);
|
|
function sys_yield():Integer;
|
|
function sys_sched_yield():Integer;
|
|
function sys_cpumode_yield():Integer;
|
|
|
|
implementation
|
|
|
|
uses
|
|
kern_proc,
|
|
sched_ule,
|
|
md_sleep,
|
|
rtprio;
|
|
|
|
var
|
|
pause_wchan:Integer=0;
|
|
|
|
function msleep(ident :Pointer;
|
|
lock :p_mtx;
|
|
priority:Integer;
|
|
wmesg :PChar;
|
|
timo :Int64):Integer; public;
|
|
var
|
|
td:p_kthread;
|
|
catch,flags,pri:Integer;
|
|
begin
|
|
td:=curkthread;
|
|
|
|
catch:=priority and PCATCH;
|
|
pri :=priority and PRIMASK;
|
|
|
|
if (TD_ON_SLEEPQ(td)) then
|
|
begin
|
|
sleepq_remove(td,td^.td_wchan);
|
|
end;
|
|
|
|
if (ident=@pause_wchan) then
|
|
flags:=SLEEPQ_PAUSE
|
|
else
|
|
flags:=SLEEPQ_SLEEP;
|
|
|
|
if (catch<>0) then
|
|
begin
|
|
flags:=flags or SLEEPQ_INTERRUPTIBLE;
|
|
end;
|
|
|
|
if ((priority and PBDRY)<>0) then
|
|
begin
|
|
flags:=flags or SLEEPQ_STOP_ON_BDRY;
|
|
end;
|
|
|
|
sleepq_lock(ident);
|
|
|
|
if (lock<>nil) then //not LC_SLEEPABLE
|
|
begin
|
|
mtx_unlock(lock^);
|
|
end;
|
|
|
|
{
|
|
* We put ourselves on the sleep queue and start our timeout
|
|
* before calling thread_suspend_check, as we could stop there,
|
|
* and a wakeup or a SIGCONT (or both) could occur while we were
|
|
* stopped without resuming us. Thus, we must be ready for sleep
|
|
* when cursig() is called. If the wakeup happens while we're
|
|
* stopped, then td will no longer be on a sleep queue upon
|
|
* return from cursig().
|
|
}
|
|
|
|
sleepq_add(ident,lock,wmesg,flags,0);
|
|
|
|
sleepq_set_timeout(ident,timo);
|
|
|
|
if (timo<>0) and (catch<>0) then
|
|
Result:=sleepq_timedwait_sig(ident,pri)
|
|
else if (timo<>0) then
|
|
Result:=sleepq_timedwait(ident,pri)
|
|
else if (catch<>0) then
|
|
Result:=sleepq_wait_sig(ident,pri)
|
|
else
|
|
begin
|
|
sleepq_wait(ident,pri);
|
|
Result:=0;
|
|
end;
|
|
|
|
//sleepq_release in sleepq_switch
|
|
|
|
if (lock<>nil) and ((priority and PDROP)=0) then
|
|
begin
|
|
mtx_lock(lock^);
|
|
end;
|
|
end;
|
|
|
|
function tsleep(ident :Pointer;
|
|
priority:Integer;
|
|
wmesg :PChar;
|
|
timo :Int64):Integer; public;
|
|
begin
|
|
Result:=msleep(ident,nil,priority,wmesg,timo);
|
|
end;
|
|
|
|
function pause(wmesg:PChar;timo:Int64):Integer; public;
|
|
begin
|
|
// silently convert invalid timeouts
|
|
if (timo < 1) then timo:=1;
|
|
|
|
Result:=(tsleep(@pause_wchan, 0, wmesg, timo));
|
|
end;
|
|
|
|
procedure wakeup(ident:Pointer); public;
|
|
begin
|
|
sleepq_lock(ident);
|
|
sleepq_broadcast(ident,SLEEPQ_SLEEP,0,0);
|
|
sleepq_release(ident);
|
|
end;
|
|
|
|
procedure wakeup_one(ident:Pointer); public;
|
|
begin
|
|
sleepq_lock(ident);
|
|
sleepq_signal(ident,SLEEPQ_SLEEP,0,0);
|
|
sleepq_release(ident);
|
|
end;
|
|
|
|
function mi_switch(flags:Integer):Integer; public;
|
|
var
|
|
td:p_kthread;
|
|
begin
|
|
Result:=0;
|
|
|
|
td:=curkthread;
|
|
thread_lock_assert(td);
|
|
|
|
if (td<>nil) then
|
|
begin
|
|
if (flags and SW_VOL)<>0 then
|
|
begin
|
|
System.InterlockedIncrement64(td^.td_ru.ru_nvcsw);
|
|
System.InterlockedIncrement64(p_proc.p_nvcsw);
|
|
end else
|
|
begin
|
|
System.InterlockedIncrement64(td^.td_ru.ru_nivcsw);
|
|
System.InterlockedIncrement64(p_proc.p_nivcsw);
|
|
end;
|
|
end;
|
|
|
|
case (flags and SW_TYPE_MASK) of
|
|
SWT_RELINQUISH,
|
|
SWT_NEEDRESCHED:
|
|
begin
|
|
if (td<>nil) then
|
|
begin
|
|
thread_unlock(td);
|
|
end;
|
|
|
|
md_yield;
|
|
|
|
if (td<>nil) then
|
|
begin
|
|
thread_lock(td);
|
|
end;
|
|
end;
|
|
SWT_SLEEPQ,
|
|
SWT_SLEEPQTIMO:
|
|
begin
|
|
if (td=nil) then Exit(-1);
|
|
Result:=sched_switch(td);
|
|
end;
|
|
SWT_SUSPEND:
|
|
begin
|
|
if (td=nil) then Exit(-1);
|
|
td^.td_slptick:=0; //infinite
|
|
Result:=sched_switch(td);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure maybe_yield();
|
|
begin
|
|
kern_yield(PRI_USER);
|
|
end;
|
|
|
|
procedure kern_yield(prio:Integer);
|
|
var
|
|
td:p_kthread;
|
|
begin
|
|
td:=curkthread;
|
|
if (td<>nil) then
|
|
begin
|
|
thread_lock(td);
|
|
if (prio=PRI_USER) then
|
|
begin
|
|
prio:=td^.td_user_pri;
|
|
end;
|
|
if (prio>=0) then
|
|
begin
|
|
sched_prio(td, prio);
|
|
end;
|
|
end;
|
|
|
|
mi_switch(SW_VOL or SWT_RELINQUISH);
|
|
|
|
if (td<>nil) then
|
|
begin
|
|
thread_unlock(td);
|
|
end;
|
|
end;
|
|
|
|
function sys_yield():Integer;
|
|
var
|
|
td:p_kthread;
|
|
begin
|
|
td:=curkthread;
|
|
|
|
if (td<>nil) then
|
|
begin
|
|
thread_lock(td);
|
|
if (PRI_BASE(td^.td_pri_class)=PRI_TIMESHARE) then
|
|
begin
|
|
sched_prio(td, PRI_MAX_TIMESHARE);
|
|
end;
|
|
td^.td_retval[0]:=0;
|
|
end;
|
|
|
|
mi_switch(SW_VOL or SWT_RELINQUISH);
|
|
|
|
if (td<>nil) then
|
|
begin
|
|
thread_unlock(td);
|
|
end;
|
|
|
|
Exit(0);
|
|
end;
|
|
|
|
function sys_sched_yield():Integer;
|
|
begin
|
|
Result:=sys_yield;
|
|
end;
|
|
|
|
function sys_cpumode_yield():Integer;
|
|
begin
|
|
Result:=sys_yield;
|
|
end;
|
|
|
|
end.
|
|
|